DragonFlyBSD Kernel Audit
DF-0822 / dump_volhdr.c
← back to finding ↓ download raw
/* DF-0822 helper: dump HAMMER2 volume header fields relevant to the exploit. */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>

struct volhdr {
    uint8_t raw[65536];
};

/* offsets from hammer2_disk.h hammer2_volume_data */
#define OFF_magic          0x0000
#define OFF_allocator_size 0x0060
#define OFF_allocator_free 0x0068
#define OFF_allocator_beg  0x0070
#define OFF_mirror_tid     0x0078
#define OFF_freemap_tid    0x0090
#define OFF_bulkfree_tid   0x0098
#define OFF_icrc_sects      0x01E0   /* [8] uint32 */
#define OFF_sroot_blockset  0x0200   /* 512 bytes, 4 blockrefs x 128 */
#define OFF_icrc_volheader  0xFFFC

/* blockref field offsets (struct is 128 bytes) */
#define BR_type        0
#define BR_methods     1
#define BR_key         16  /* uint64 */
#define BR_mirror_tid  24  /* uint64 */
#define BR_modify_tid  32
#define BR_data_off    40  /* uint64, low 6 bits = radix */
#define BR_update_tid  48
#define BR_check_value 56  /* iscsi32.value uint32 (first 4 of check union) */

int main(int argc, char **argv) {
    const char *path = argc > 1 ? argv[1] : "/tmp/h2.img";
    int fd = open(path, O_RDONLY);
    if (fd < 0) { perror("open"); return 1; }
    uint8_t buf[65536];
    /* volume headers are at reserved offsets; scan for magic */
    uint64_t magic = 0x48414d3205172011ULL;
    off_t vhoff = -1;
    for (off_t o = 0; o + 8 <= 65536 * 4; o += 65536) {
        if (lseek(fd, o, SEEK_SET) < 0) break;
        uint64_t m;
        if (read(fd, &m, 8) != 8) break;
        if (m == magic) { vhoff = o; break; }
    }
    if (vhoff < 0) {
        /* try sector-aligned scan within first 4MB */
        for (off_t o = 0; o + 65536 <= 4*1024*1024; o += 512) {
            lseek(fd, o, SEEK_SET);
            uint64_t m;
            if (read(fd, &m, 8) == 8 && m == magic) { vhoff = o; break; }
        }
    }
    if (vhoff < 0) { fprintf(stderr, "magic not found\n"); return 2; }
    printf("VOLHDR at file offset 0x%llx\n", (unsigned long long)vhoff);
    lseek(fd, vhoff, SEEK_SET);
    if (read(fd, buf, 65536) != 65536) { perror("read"); return 3; }

    uint64_t mirror_tid = *(uint64_t*)(buf+OFF_mirror_tid);
    uint64_t freemap_tid = *(uint64_t*)(buf+OFF_freemap_tid);
    uint64_t bulkfree_tid = *(uint64_t*)(buf+OFF_bulkfree_tid);
    uint64_t allocator_beg = *(uint64_t*)(buf+OFF_allocator_beg);
    uint64_t allocator_size = *(uint64_t*)(buf+OFF_allocator_size);
    uint64_t allocator_free = *(uint64_t*)(buf+OFF_allocator_free);
    printf("magic            = 0x%016llx\n", (unsigned long long)*(uint64_t*)(buf+OFF_magic));
    printf("allocator_size   = 0x%016llx\n", (unsigned long long)allocator_size);
    printf("allocator_free   = 0x%016llx\n", (unsigned long long)allocator_free);
    printf("allocator_beg    = 0x%016llx\n", (unsigned long long)allocator_beg);
    printf("mirror_tid       = 0x%016llx\n", (unsigned long long)mirror_tid);
    printf("freemap_tid      = 0x%016llx\n", (unsigned long long)freemap_tid);
    printf("bulkfree_tid     = 0x%016llx\n", (unsigned long long)bulkfree_tid);
    printf("icrc_sects[7]=0x%08x icrc_sects[6]=0x%08x\n",
        *(uint32_t*)(buf+OFF_icrc_sects+7*4),
        *(uint32_t*)(buf+OFF_icrc_sects+6*4));
    printf("icrc_volheader   = 0x%08x\n", *(uint32_t*)(buf+OFF_icrc_volheader));

    /* dump sroot_blockset blockrefs */
    for (int i = 0; i < 4; i++) {
        uint8_t *br = buf + OFF_sroot_blockset + i*128;
        uint8_t type = br[BR_type];
        uint64_t key = *(uint64_t*)(br+BR_key);
        uint64_t mtid = *(uint64_t*)(br+BR_mirror_tid);
        uint64_t doff = *(uint64_t*)(br+BR_data_off);
        uint32_t chk = *(uint32_t*)(br+BR_check_value);
        printf("sroot[%d]: type=0x%02x methods=0x%02x copyid=0x%02x keybits=%d key=0x%016llx mirror_tid=0x%016llx data_off=0x%016llx (radix=%d) check=0x%08x\n",
            i, type, br[1], br[2], br[3], (unsigned long long)key, (unsigned long long)mtid,
            (unsigned long long)doff, (int)(doff & 0x3f), chk);
    }
    close(fd);
    return 0;
}