DF-2283 / sg2283.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | /* * DF-2283 PoC v2 -- sgread() tsleep(&hstat) has no wakeup source. * * Redesigned after the first run WEDGED the guest when the test fd was * closed while a reader slept (the DF-2282 open/close refcount-underflow * collision -- documented separately; not this finding). v2: * - a HOLDER process opens /dev/sg0 once and keeps the fd open for the * whole session (no sgclose ever runs while tests are in flight); * - children fork from the holder share the same open file description * (no additional sgopen/sgclose churn); * - state is observed by a separate `ps` probe, not by killing things; * - the reader child parks in the blocked read indefinitely (proof is * its wchan + sleep time, not its death). * * Output: machine-readable lines "DF2283:" on stdout. * * Usage: ./sg2283 block # child blocks in read(pack_id=4242) * ./sg2283 probe # parent-side: ps snapshot of child * (run block in background, probe from another session) */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> struct sg_hdr_local { int32_t pack_len; int32_t reply_len; int32_t pack_id; int32_t result; uint32_t bits; unsigned char sense[16]; }; #define SG_HDR_SIZE 36 int main(int argc, char **argv) { unsigned char buf[SG_HDR_SIZE + 512]; struct sg_hdr_local *h = (struct sg_hdr_local *)buf; int fd; setvbuf(stdout, NULL, _IONBF, 0); if (argc < 2) { printf("usage: %s block|probe\n", argv[0]); return (2); } fd = open("/dev/sg0", O_RDWR); if (fd < 0) { printf("DF2283: open /dev/sg0 FAILED %s\n", strerror(errno)); return (1); } if (strcmp(argv[1], "block") == 0) { /* queue one request with pack_id=2002 (INQUIRY) */ unsigned char req[SG_HDR_SIZE + 6 + 512]; struct sg_hdr_local *rh = (struct sg_hdr_local *)req; unsigned char *cdb = req + SG_HDR_SIZE; memset(req, 0, sizeof(req)); rh->pack_len = (int32_t)sizeof(req); rh->reply_len = 512; rh->pack_id = 2002; cdb[0] = 0x12; cdb[4] = 0x24; if (write(fd, req, sizeof(req)) != (ssize_t)sizeof(req)) { printf("DF2283: write failed %s\n", strerror(errno)); return (1); } printf("DF2283: request pack_id=2002 queued; " "waiting 2s for sgdone()\n"); sleep(2); /* CONTROL: read with the matching id returns at once */ memset(buf, 0xAA, sizeof(buf)); h->pack_id = 2002; h->reply_len = 512; alarm(10); if (read(fd, buf, SG_HDR_SIZE + 512) < 0) { printf("DF2283: control read FAILED %s\n", strerror(errno)); return (1); } alarm(0); printf("DF2283: CONTROL read(pack_id=2002) returned " "immediately, result=%d\n", h->result); /* TEST: queue another, then read with a bogus pack_id */ rh->pack_id = 3003; if (write(fd, req, sizeof(req)) != (ssize_t)sizeof(req)) { printf("DF2283: write2 failed %s\n", strerror(errno)); return (1); } sleep(2); memset(buf, 0xAA, sizeof(buf)); h->pack_id = 4242; /* never matches */ h->reply_len = 512; printf("DF2283: TEST read(pack_id=4242) entering " "tsleep(&hstat, PCATCH, \"sgnull\", 0) NOW " "(pid %d)\n", getpid()); read(fd, buf, SG_HDR_SIZE + 512); printf("DF2283: TEST read RETURNED errno=%d " "(unexpected: no wakeup source exists)\n", errno); return (0); } /* probe mode: nothing to do here; the ps probe runs externally */ printf("DF2283: probe placeholder\n"); return (0); } |