DF-4509 / twa_probe.c
/* * DF-4509 trigger prober — twa(4) tw_cli_drain_aen_queue FREE_Q double-insert * * The bug is an internal driver state-machine defect (firmware-hang path): * * fw wedged -> reset path -> tw_cli_drain_aen_queue() (tw_cl_misc.c:309) * -> REQUEST_SENSE poll times out (tw_cl_misc.c:353 ETIMEDOUT) * -> out: label (tw_cl_misc.c:379-384) inserts `req` into TW_CLI_FREE_Q * although it is STILL linked in TW_CLI_BUSY_Q (tw_cl_io.c:219) or * TW_CLI_PENDING_Q (tw_cl_io.c:204) ==> one request in two queues. * * No unprivileged trigger exists even with hardware: the path runs during * controller reset, entered from the MPSAFE watchdog / passthru-timeout / * init paths when the firmware stops completing commands. This program * documents the *userspace-visible* preconditions: a twa(4) control device * must exist (root-only node /dev/twaN) and the controller must hang. * * On a machine WITH a twa controller, the reproducer for the underlying * state is: cause a firmware hang (e.g. 3ware CLI bug, slot failure) or * block MMIO (devctl detach device memory) while I/O is in flight, then * watch the reset path hit the 60-second REQUEST_SENSE timeout inside * tw_cli_drain_aen_queue and the subsequent queue-structure corruption * (duplicate request handed out by tw_cli_get_request while the firmware * later completes the original request id). * * Build: cc -O -o twa_probe twa_probe.c * Run: ./twa_probe */ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <dirent.h> #include <errno.h> #include <stdio.h> #include <string.h> #include <unistd.h> int main(void) { DIR *d; struct dirent *de; char path[64]; int fd, found = 0; printf("DF-4509 twa drain_aen_queue probe\n"); d = opendir("/dev"); if (d != NULL) { while ((de = readdir(d)) != NULL) { if (strncmp(de->d_name, "twa", 3) == 0) { found = 1; snprintf(path, sizeof(path), "/dev/%s", de->d_name); printf("found control node: %s\n", path); fd = open(path, O_RDWR); printf(" open(O_RDWR) -> %s\n", fd >= 0 ? "OK (root)" : strerror(errno)); if (fd >= 0) close(fd); } } closedir(d); } if (!found) { printf("no /dev/twa* nodes on this machine: " "twa(4) controller ABSENT -> the vulnerable code path " "(controller reset -> tw_cli_drain_aen_queue ETIMEDOUT) " "cannot be exercised here.\n"); return (2); } return (0); } |