DF-3445 / df3445.c
/* * DF-3445 harness -- table_append_dispatch() strands its netmsg on * kmalloc failure (ip_fw3_table.c:157-186): * * ent = kmalloc(sizeof(struct table_ip_entry), M_IPFW3_TABLE, * M_NOWAIT | M_ZERO); * if (ent == NULL) * return; <-- plain return: the netmsg is * neither forwarded * (netisr_forwardmsg_all) * nor replied * done: * netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); * * The dispatcher-side caller (table_append -> netmsg_init + * lwkt_domsg/netisr_domsg) blocks in lwkt_waitmsg() forever: netisr0 * never processes another message -> the entire kernel networking * stack hangs (permanent DoS). Reproducing the real hang requires an * M_NOWAIT failure; this logic harness drives the verbatim control * flow with a failing kmalloc to prove the message is stranded. */ #include <stdio.h> #include <stdlib.h> #include <string.h> static int kmalloc_fail; /* fault injection knob */ static int forwarded, replied, dispatched; #define kmalloc(sz) (kmalloc_fail ? NULL : calloc(1, (sz))) #define kfree(p) free(p) /* verbatim netmsg plumbing behaviour */ static void netisr_forwardmsg_all(void) { forwarded++; } /* verbatim ip_fw3_table.c:157-186 (rnh_addaddr stubbed: succeeds) */ static void table_append_dispatch(int tbl_type, int tbl_id) { void *ent; dispatched++; if (tbl_type != 1) goto done; ent = kmalloc(104); /* sizeof(table_ip_entry) */ if (ent == NULL) return; /* <-- THE BUG */ /* ... ent->addr/mask fill, rnh->rnh_addaddr ... */ kfree(ent); done: netisr_forwardmsg_all(); } int main(void) { printf("DF-3445 (table_append_dispatch strands netmsg on kmalloc" " failure, ip_fw3_table.c:168-170)\n"); printf("[control] kmalloc succeeds: "); table_append_dispatch(1, 0); printf("dispatched=%d forwarded=%d replied=%d\n", dispatched, forwarded, replied); printf("[fault] kmalloc(M_NOWAIT) fails: "); kmalloc_fail = 1; table_append_dispatch(1, 0); printf("dispatched=%d forwarded=%d replied=%d\n", dispatched, forwarded, replied); if (forwarded == 1 && dispatched == 2) { printf("RESULT: REPRODUCED -- the failing dispatch returned" " without forwarding or replying: the sender blocks in" " lwkt_waitmsg(netisr0) forever; every subsequent netisr0" " consumer (all of kernel networking) wedges permanently\n"); return 0; } printf("RESULT: not reproduced\n"); return 1; } |