DF-0594 / fix_check.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | /* * DF-0594 โ fix-validation harness. * * This replicates the GUARD added by fix.diff at the top of tkip_decap() and * inside tkip_demic(), and demonstrates that the too-short trigger frame (the * same 32-byte frame the reproduction harness uses) is now REJECTED before the * vulnerable line-994 / line-357 arithmetic can run. It also confirms a * well-formed (long-enough) frame still passes the guard, proving the fix is * not over-restrictive. * * Build: * cc -O2 -Wall -o fix_check fix_check.c * * Run: * ./fix_check * * Expected (fix present): the 32-byte trigger frame is rejected at the * tkip_decap guard (returns 0, "too short for decrypt"); a 36-byte frame and a * 33-byte demic frame both pass their respective guards. Compare with the * unpatched reproduction harness, where the 32-byte frame reaches the * line-994 underflow. */ #include <stdio.h> #include <stdint.h> typedef unsigned int u_int; typedef uint8_t u8; #define IEEE80211_WEP_IVLEN 3 #define IEEE80211_WEP_KIDLEN 1 #define IEEE80211_WEP_EXTIVLEN 4 #define IEEE80211_WEP_CRCLEN 4 #define IEEE80211_WEP_MICLEN 8 static const struct { u_int ic_header, ic_trailer, ic_miclen; } tkip = { IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_EXTIVLEN, IEEE80211_WEP_CRCLEN, IEEE80211_WEP_MICLEN, }; /* * Returns 1 if the frame passes the patched tkip_decap guard (long enough to * proceed to decrypt), 0 if rejected by the new length check. This is the * verbatim condition from fix.diff: * if (m->m_pkthdr.len < hdrlen + (int)(tkip.ic_header + tkip.ic_trailer)) * return 0; */ static int tkip_decap_guard_passes(int m_len, int hdrlen) { if (m_len < hdrlen + (int)(tkip.ic_header + tkip.ic_trailer)) return 0; /* rejected by fix.diff guard */ return 1; /* proceeds to tkip_decrypt (line 994 arithmetic) */ } /* * Returns 1 if the frame passes the patched tkip_demic guard (long enough for * MIC verification), 0 if rejected. */ static int tkip_demic_guard_passes(int m_len, int hdrlen) { if (m_len < hdrlen + (int)tkip.ic_miclen) return 0; /* rejected by fix.diff guard */ return 1; /* proceeds to michael_mic (line 357 arithmetic) */ } int main(void) { const int hdrlen = 24; const int decrypt_need = hdrlen + (int)(tkip.ic_header + tkip.ic_trailer); /* 36 */ const int demic_need = hdrlen + (int)tkip.ic_miclen; /* 32 */ int fails = 0; fprintf(stderr, "=== DF-0594 fix-validation (patched tkip_decap/tkip_demic guards) ===\n"); fprintf(stderr, "decrypt floor = hdrlen + ic_header + ic_trailer = %d\n", decrypt_need); fprintf(stderr, "demic floor = hdrlen + ic_miclen = %d\n\n", demic_need); /* Case 1: the 32-byte trigger frame from the reproduction harness. * Unpatched: reaches line 994 underflow -> panic/OOB read. * Patched: rejected by the new tkip_decap guard. */ { int m_len = 32; int ok = tkip_decap_guard_passes(m_len, hdrlen); fprintf(stderr, "[1] 32-byte trigger frame tkip_decap: %s\n", ok ? "PASSES (BUG STILL REACHABLE)" : "REJECTED by guard (fix works)"); if (ok) fails++; } /* Case 2: 35-byte frame (still < 36 decrypt floor). Patched: rejected. */ { int m_len = 35; int ok = tkip_decap_guard_passes(m_len, hdrlen); fprintf(stderr, "[2] 35-byte frame tkip_decap: %s\n", ok ? "PASSES (BUG STILL REACHABLE)" : "REJECTED by guard (fix works)"); if (ok) fails++; } /* Case 3: 36-byte frame (exactly meets decrypt floor). Patched: passes, * and the line-994 arithmetic yields data_len = 0 (no underflow). */ { int m_len = 36; int ok = tkip_decap_guard_passes(m_len, hdrlen); size_t dl = (size_t)((u_int)m_len - (u_int)(hdrlen + tkip.ic_header + tkip.ic_trailer)); fprintf(stderr, "[3] 36-byte frame tkip_decap: %s; line994 data_len=%zu %s\n", ok ? "passes (legitimate)" : "REJECTED (over-restrictive!)", dl, dl == 0 ? "(no underflow)" : "(UNDERFLOW!)"); if (!ok) fails++; if (dl != 0) fails++; } /* Case 4: 31-byte frame at the demic path (HW-decrypt + SW-MIC). Patched: * rejected by the new tkip_demic guard. */ { int m_len = 31; int ok = tkip_demic_guard_passes(m_len, hdrlen); fprintf(stderr, "[4] 31-byte frame tkip_demic: %s\n", ok ? "PASSES (BUG STILL REACHABLE)" : "REJECTED by guard (fix works)"); if (ok) fails++; } /* Case 5: 32-byte demic frame (meets demic floor exactly). Patched: * passes; the line-357 arithmetic yields data_len = 0 (no underflow). */ { int m_len = 32; int ok = tkip_demic_guard_passes(m_len, hdrlen); size_t dl = (size_t)((u_int)m_len - (u_int)(hdrlen + tkip.ic_miclen)); fprintf(stderr, "[5] 32-byte frame tkip_demic: %s; line357 data_len=%zu %s\n", ok ? "passes (legitimate)" : "REJECTED (over-restrictive!)", dl, dl == 0 ? "(no underflow)" : "(UNDERFLOW!)"); if (!ok) fails++; if (dl != 0) fails++; } fprintf(stderr, "\n"); if (fails == 0) { fprintf(stderr, "RESULT: fix.diff GUARDS the vulnerable path โ too-short frames " "rejected, legitimate frames pass with no underflow. FIX VALIDATED.\n"); return 0; } fprintf(stderr, "RESULT: %d check(s) failed โ fix does not fully close the path.\n", fails); return 2; } |