DF-3042 / corrupt3042.c
/* DF-3042: flip one byte of the hammer volume header covered by vol_crc * (vol_reserved[7], harmless to mount logic) WITHOUT fixing vol_crc. * hammer's volume CRC is CRC32C (iscsi_crc32) of CRCSIZE1 ^ CRC32C of the * tail region; we compute it locally to prove the stored crc no longer * matches after the flip. */ #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <stddef.h> #include <sys/types.h> #include <hammer_disk.h> static uint32_t crc32c_tab[8][256]; static void crc32c_init(void) { uint32_t i, j, c; for (i = 0; i < 256; i++) { c = i; for (j = 0; j < 8; j++) c = (c >> 1) ^ (0x82F63B78u & (0 - (c & 1))); crc32c_tab[0][i] = c; } for (i = 0; i < 256; i++) { c = crc32c_tab[0][i]; for (j = 1; j < 8; j++) { c = crc32c_tab[0][c & 0xff] ^ (c >> 8); crc32c_tab[j][i] = c; } } } static uint32_t crc32c(const void *buf, size_t len) { const uint8_t *p = buf; uint32_t crc = 0xFFFFFFFFu; while (len >= 8) { crc ^= (uint32_t)p[0] | ((uint32_t)p[1]<<8) | ((uint32_t)p[2]<<16) | ((uint32_t)p[3]<<24); crc = crc32c_tab[7][crc & 0xff] ^ crc32c_tab[6][(crc>>8)&0xff] ^ crc32c_tab[5][(crc>>16)&0xff] ^ crc32c_tab[4][crc>>24] ^ crc32c_tab[3][p[4]] ^ crc32c_tab[2][p[5]] ^ crc32c_tab[1][p[6]] ^ crc32c_tab[0][p[7]]; p += 8; len -= 8; } while (len--) crc = crc32c_tab[0][(crc ^ *p++) & 0xff] ^ (crc >> 8); return ~crc; } int main(int argc, char **argv) { struct hammer_volume_ondisk hdr, hdr2; off_t roff = offsetof(struct hammer_volume_ondisk, vol_reserved); unsigned char *p; uint64_t before, after; int fd; crc32c_init(); fd = open(argv[1], O_RDWR); if (fd < 0) { perror("open"); return 1; } if (pread(fd, &hdr, sizeof(hdr), 0) != sizeof(hdr)) { perror("pread"); return 1; } if (hdr.vol_signature != HAMMER_FSBUF_VOLUME) { fprintf(stderr, "not a hammer volume (sig %016jx)\n", (uintmax_t)hdr.vol_signature); return 1; } memcpy(&hdr2, &hdr, sizeof(hdr)); p = (unsigned char *)&hdr2; if (argc > 2 && !strcmp(argv[2], "crc")) { /* forge a NONZERO but wrong stored vol_crc */ unsigned char *crcp = (unsigned char *)&hdr2.vol_crc; crcp[0] ^= 0x5a; if (crcp[0] == 0) crcp[0] = 0x5a; } else { p[roff + 31] ^= 0x5a; } #define VOLCRC(h) ((uint64_t)crc32c(&h, HAMMER_VOL_CRCSIZE1) << 32 | \ crc32c((char *)&h + HAMMER_VOL_CRCSIZE1 + sizeof(hdr.vol_crc), HAMMER_VOL_CRCSIZE2)) before = VOLCRC(hdr); after = VOLCRC(hdr2); printf("sizeof(hdr)=%zu vol_crc@%zu CRCSIZE1=%d(+4) CRCSIZE2=%d\n", sizeof(hdr), (size_t)offsetof(struct hammer_volume_ondisk, vol_crc), (int)HAMMER_VOL_CRCSIZE1, (int)HAMMER_VOL_CRCSIZE2); printf("stored vol_crc = %016jx\n", (uintmax_t)hdr.vol_crc); printf("computed CRC (before) = %016jx %s\n", (uintmax_t)before, before == hdr.vol_crc ? "(MATCH - image was clean)" : "(MISMATCH)"); printf("computed CRC (after) = %016jx (differs from stored -> header invalid)\n", (uintmax_t)after); if (pwrite(fd, &hdr2, sizeof(hdr2), 0) != sizeof(hdr2)) { perror("pwrite"); return 1; } printf("flipped vol_reserved[7] byte; vol_crc left stale\n"); close(fd); return 0; } |