DF-3374 / df3374.c
/* * DF-3374 harness -- ieee80211_parse_csaparams() consumes the CSA IE * with no validation of its declared length. * * VERBATIM ieee80211_sta.c:1146-1200 (extract of the field reads): * const struct ieee80211_csa_ie *csa = (const void *)frm; * if (csa->csa_mode > 1) ... (byte 2) * csa->csa_newchan (byte 3) * csa->csa_count (byte 4) * struct ieee80211_csa_ie { ie; len; mode; newchan; count } (802.11.h:1063) * caller sta.c:1472 passes scan.csa straight from the beacon walk * (ieee80211_input.c:565 case IEEE80211_ELEMID_CSA: scan->csa = frm). * A CSA IE with declared len < 3 drives reads up to 3 bytes past the IE. */ #include "guard.h" struct ieee80211_csa_ie { uint8_t csa_ie; uint8_t csa_len; uint8_t csa_mode; uint8_t csa_newchan; uint8_t csa_count; } __packed; /* verbatim shape of the field consumption (channel lookups stubbed) */ static int ieee80211_parse_csaparams(uint8_t *frm) { const struct ieee80211_csa_ie *csa = (const struct ieee80211_csa_ie *) frm; if (csa->csa_mode > 1) return -1; /* invalid mode */ /* channel switch decision driven by: */ if (csa->csa_newchan == 0) return -1; return csa->csa_count; /* switch count */ } static uint8_t *ie; static int r, which; static uint8_t *ie; static int r; int main(int argc, char **argv) { int which = (argc > 1) ? atoi(argv[1]) : 0; printf("DF-3374 (parse_csaparams: no frm[1] check)\n"); if (which == 2) { ie = guard_buf(4); ie[0] = 37; ie[1] = 2; ie[2] = 0; ie[3] = 36; printf(" CSA len=2: csa_count (byte 4) past the IE\n"); } else if (which == 1) { ie = guard_buf(3); ie[0] = 37; ie[1] = 1; ie[2] = 0; printf(" CSA len=1: csa_newchan (byte 3) past the IE\n"); } else { ie = guard_buf(8); ie[0] = 37; ie[1] = 3; ie[2] = 0; ie[3] = 36; ie[4] = 5; printf(" control: well-formed CSA IE\n"); } fflush(stdout); #ifdef FIXED /* DF-3374 fix: CSA IE must carry mode+newchan+count */ if (ie[1] < 3) { printf("FIXED: CSA IE len %d < 3, discarded\n", ie[1]); return 0; } #endif r = ieee80211_parse_csaparams(ie); printf(" ran (in bounds), r=%d\n", r); return 0; } |