DF-0473 / nullcall.c
/* * DF-0473 call-site NULL-check test: install an IN-RANGE but UNREGISTERED * opcode (module=0 BASIC, opcode=50 -- passes the install-time range check, * but filter_funcs[0][50] is NULL since only opcode 0/1 are registered), * then enable the firewall and send a packet. * * UNPATCHED module: ip_fw3_chk calls (NULL)(...) -> NULL-deref panic. * PATCHED module: call-site NULL check -> goto next_cmd -> NO panic. * * Exercises the defense-in-depth call-site hunk (fix.diff hunk #1). * * Build: cc -Wall -o nullcall nullcall.c * Run : ./nullcall (as root, with ipfw3.ko loaded) */ #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 MY_IP_FW_X 49 #define MY_IP_FW_ADD 50 typedef struct { uint8_t opcode; uint8_t len; uint16_t arg1; uint8_t module; uint8_t arg3; uint16_t arg2; } my_insn; typedef struct { uint16_t opcode; uint16_t _pad; } my_x_header; struct my_ioc_rule { uint16_t act_ofs, cmd_len, rulenum; uint8_t set, insert; uint32_t sets; uint64_t pcnt, bcnt; uint32_t timestamp; my_insn cmd; }; int main(void) { int s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); if (s < 0) { perror("socket raw [needs root]"); return 2; } unsigned char buf[sizeof(my_x_header) + sizeof(struct my_ioc_rule)]; memset(buf, 0, sizeof(buf)); my_x_header *xh = (my_x_header *)buf; xh->opcode = MY_IP_FW_ADD; struct my_ioc_rule *r = (struct my_ioc_rule *)(buf + sizeof(my_x_header)); /* module=0 (in range <10), opcode=50 (in range <100, but UNREGISTERED) */ r->cmd_len = 2; r->cmd.opcode = 50; r->cmd.len = 2; r->cmd.module = 0; int rc = setsockopt(s, IPPROTO_IP, MY_IP_FW_X, buf, sizeof(buf)); printf("[+] install in-range/unregistered rule (module=0 opcode=50): rc=%d %s\n", rc, rc ? strerror(errno) : "(accepted -- passes range check)"); if (rc) { printf("[!] add failed\n"); close(s); return 1; } close(s); printf("[+] enabling firewall + sending packet (PATCHED: NULL-skip, no panic)...\n"); fflush(stdout); system("sysctl net.inet.ip.fw3.enable=1"); int u = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); struct sockaddr_in dst; memset(&dst, 0, sizeof(dst)); dst.sin_family = AF_INET; dst.sin_port = htons(9); dst.sin_addr.s_addr = htonl(0x7f000001); sendto(u, "x", 1, 0, (struct sockaddr *)&dst, sizeof(dst)); usleep(300000); printf("[+] packet sent; if we reach here the call-site NULL check skipped the cmd\n"); close(u); return 0; } |