DF-2963 / gen_gpt.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 | /* * DF-2963 PoC image generator. * * Builds a GPT-labeled disk image that exposes the slice-index-128 minor * truncation bug: * * - protective MBR (entry 0 type 0xEE) * - GPT header @ LBA1: 128 entries, entsz 128, table @ LBA2 (32 sectors) * - entry 0 -> LBA 34..63 (data pattern ENTRY0ZONE) -> slice s0 (compat) * - entry 126 -> LBA 160 (1 sector, pattern E126) -> slice s126 (index 127, OK) * - entry 127 -> LBA 1000..1099 (pattern ENTRY127ZONE) -> slice s127 (index 128, BUG) * * The kernel creates /dev/vn0s127 for entry 127, but dkmakeminor() masks the * slice field to 7 bits, so its minor equals slice 0's minor. Expected: * st_rdev(vn0s127) == st_rdev(vn0s0), and reads via vn0s127 return entry 0's * data, not entry 127's. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #define SECSZ 512 #define NBLK 131072 /* 64MB */ #define NENT 128 #define TBL_LBA 2 #define TBL_BLOCKS (NENT * 128 / SECSZ) /* 32 */ static uint32_t crc_tab[256]; static void crc_init(void) { for (uint32_t n = 0; n < 256; n++) { uint32_t c = n; for (int k = 0; k < 8; k++) c = (c & 1) ? 0xEDB88320U ^ (c >> 1) : c >> 1; crc_tab[n] = c; } } static uint32_t crc32buf(const void *buf, size_t len) { const uint8_t *p = buf; uint32_t c = 0xFFFFFFFFU; for (size_t i = 0; i < len; i++) c = crc_tab[(c ^ p[i]) & 0xFF] ^ (c >> 8); return c ^ 0xFFFFFFFFU; } static void putle16(uint8_t *p, uint16_t v) { p[0]=v; p[1]=v>>8; } static void putle32(uint8_t *p, uint32_t v) { p[0]=v;p[1]=v>>8;p[2]=v>>16;p[3]=v>>24; } static void putle64(uint8_t *p, uint64_t v) { putle32(p,(uint32_t)v); putle32(p+4,(uint32_t)(v>>32)); } /* little-endian on-disk GUID: first 3 fields LE, rest raw */ static void putguid(uint8_t *p, uint32_t d1, uint16_t d2, uint16_t d3, const uint8_t d4[8]) { putle32(p, d1); putle16(p+4, d2); putle16(p+6, d3); memcpy(p+8, d4, 8); } static uint8_t img[(uint64_t)NBLK * SECSZ]; static void fill_pattern(uint64_t lba, const char *tag) { for (int s = 0; s < 64; s++) { uint8_t *p = img + lba*SECSZ; (void)s; break; } /* tag the first sector of the region, each 64th byte shows the tag */ uint8_t *p = img + lba*SECSZ; memset(p, 0, SECSZ); for (int i = 0; i < SECSZ; i += 64) { memcpy(p + i, tag, strlen(tag) < 63 ? strlen(tag) : 63); } } static void set_ent(int idx, uint32_t d1, uint64_t start, uint64_t end, const char *name16) { uint8_t *e = img + (TBL_LBA*SECSZ) + (uint64_t)idx*128; uint8_t d4[8] = {1,2,3,4,5,6,7,8}; memset(e, 0, 128); putguid(e, d1, 0x1ca5, 0x11dc, d4); /* type */ putguid(e+16, 0xAA000000u+(uint32_t)idx, 1, 2, d4); /* unique */ putle64(e+32, start); putle64(e+40, end); putle64(e+48, 0); /* attrs */ if (name16) for (int i = 0; name16[i]; i++) putle16(e+72+2*i, (uint16_t)name16[i]); } int main(int argc, char **argv) { const char *out = argc > 1 ? argv[1] : "/tmp/df2963.img"; crc_init(); /* ---- protective MBR @ LBA0 ---- */ uint8_t *mbr = img; memset(mbr, 0, SECSZ); mbr[0x1be + 4] = 0xEE; /* part 0 type = GPT PMBR */ putle32(mbr + 0x1be + 8, 1); /* start LBA 1 */ putle32(mbr + 0x1be + 12, 0xFFFFFFFF); /* size */ mbr[0x1FE] = 0x55; mbr[0x1FF] = 0xAA; /* ---- partition entries @ LBA2..33 ---- */ /* entries 1..125: nil type (unused) */ /* entry 0: EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 MS basic data */ set_ent(0, 0xEBD0A0A2u, 34, 63, "slice0-entry0"); /* entries 1..125 nil */ for (int i = 1; i <= 125; i++) set_ent(i, 0, 0, 0, NULL); /* entry 126: MS basic data, LBA 160..161 */ set_ent(126, 0xEBD0A0A2u, 160, 161, "slice126"); /* entry 127: MS basic data, LBA 1000..1099 */ set_ent(127, 0xEBD0A0A2u, 1000, 1099, "slice127-ALIAS"); /* ---- GPT header @ LBA1 ---- */ uint8_t *h = img + SECSZ; memset(h, 0, SECSZ); memcpy(h, "EFI PART", 8); putle32(h+8, 0x00010000); /* revision */ putle32(h+12, 92); /* hdr_size */ putle32(h+16, 0); /* crc_self (fill below) */ putle32(h+20, 0); /* reserved */ putle64(h+24, 1); /* lba_self */ putle64(h+32, NBLK-1); /* lba_alt */ putle64(h+40, 34); /* usable start */ putle64(h+48, NBLK-34); /* usable end */ putguid(h+56, 0x29632963u, 0x2963, 0x2963, (const uint8_t[]){"DF2963!"}); putle64(h+72, TBL_LBA); /* lba_table */ putle32(h+80, NENT); /* entries */ putle32(h+84, 128); /* entsz */ putle32(h+88, crc32buf(img + TBL_LBA*SECSZ, NENT*128)); /* crc_table */ putle32(h+16, crc32buf(h, 92)); /* crc_self over first 92 bytes */ /* ---- data patterns ---- */ fill_pattern(34, "ENTRY0ZONE_compat_slice0"); fill_pattern(160, "ENTRY126ZONE"); fill_pattern(1000, "ENTRY127ZONE_real_s127_data"); FILE *f = fopen(out, "w"); if (!f) { perror("fopen"); return 1; } if (fwrite(img, 1, sizeof(img), f) != sizeof(img)) { perror("write"); return 1; } fclose(f); printf("wrote %s (%d sectors)\n", out, NBLK); return 0; } |