DF-0663 / df0663_slist_sim.c
/* * DF-0663 - SLIST_REMOVE on never-inserted element (ng_device newhook). * * Standalone userspace demonstration that the SLIST_REMOVE macro from * sys/sys/queue.h:208-220 panics (NULL deref) when invoked on an element * that was never inserted into the list. This reproduces the exact logic * of `ng_device_newhook` error paths at sys/netgraph/ng_device.c:290 and * :300 without needing to build/load the dead ng_device.c file. * * Build: cc -O2 -o df0663_slist_sim df0663_slist_sim.c * Run: ./df0663_slist_sim * Expected: "Segmentation fault" (SIGSEGV) when SLIST_REMOVE walks off * the end of the list and dereferences NULL->field. */ #include <sys/queue.h> #include <stdio.h> #include <stdlib.h> #include <string.h> struct ngd_connection { int unit; SLIST_ENTRY(ngd_connection) links; }; struct head { struct ngd_connection *slh_first; }; #define TEST_NAME "ng_device newhook SLIST_REMOVE on non-member" int main(void) { /* Case 1: empty list. ng_device_newhook's first call where make_dev or * readq kmalloc fails. */ struct head sc_head_empty = { NULL }; struct ngd_connection *new_conn = malloc(sizeof(*new_conn)); memset(new_conn, 0, sizeof(*new_conn)); printf("[%s] Case 1: empty list, SLIST_REMOVE on never-inserted conn\n", TEST_NAME); printf(" SLIST_FIRST(&sc_head_empty) = %p\n", (void *)sc_head_empty.slh_first); printf(" new_conn = %p\n", (void *)new_conn); printf(" invoking SLIST_REMOVE(&sc_head_empty, new_conn, ...)\n"); fflush(stdout); /* This macro: curelm = SLIST_FIRST(head) = NULL; while-loop body * derefs curelm->links.sle_next => NULL deref => SIGSEGV. */ SLIST_REMOVE(&sc_head_empty, new_conn, ngd_connection, links); printf(" unreachable -- should have crashed\n"); return 0; } |