# DF-0787 — Reproduce

## Bug
Unbounded attribute walk in `ntfs_loadntnode` (`sys/vfs/ntfs/ntfs_subr.c:305-320`).
The loop reads `fr_attroff` (uint16) and each attribute's `reclen` (uint32) from the
on-disk MFT record with **no bound check** against the in-memory record size, so a
crafted NTFS image causes (a) an infinite loop / slab-allocation panic if `reclen==0`
or `fr_attroff` points into a zero-tail, or (b) an OOB heap read if `reclen` overshoots
the record. Triggered at mount time (before the DF-0786 lockmgr bug).

## Files
| file | purpose |
|---|---|
| `gen_ntfs_0787.py` | builds three crafted NTFS images (loop / oob_a / oob_r) by corrupting only the ino-5 (root dir) MFT record of an otherwise-valid image |
| `ntfs_loop.img`    | reclen=0 → infinite loop → slab panic |
| `ntfs_oob_a.img`   | fr_attroff=0x0FF0 → walk reads zero-tail → same loop |
| `ntfs_oob_r.img`   | reclen=0x1000 → next iter OOB read past mfrp |
| `harness.c`        | userspace replication of `ntfs_loadntnode:305-320` with a guard page; accepts `clean|loop|oob_attroff|oob_reclen` and `apply_fix` |
| `build.sh`         | compiles the harness + (if python3 available) regenerates the images |
| `run.sh`           | runs the harness; `run.sh live` (root) also runs the live mount |
| `fix.diff`         | git-apply-able fix at the root cause |
| `VERDICT.md`       | full narrative + evidence |
| `manifest.json`    | artifact catalog |

## Build
```sh
./build.sh            # builds ./harness (+ images if python3 present)
```

## Run
```sh
./run.sh              # userspace harness, deterministic (no root needed)
./run.sh live         # + live mount test (REQUIRES ROOT, panics the guest)
```

## Expected
- **Harness, buggy mode:** `loop`/`oob_attroff` → "ITERATION CAP HIT" (infinite loop);
  `oob_reclen` → SIGSEGV (OOB read).
- **Harness, fix mode:** all three corrupt modes → "FIX REJECTED input" (EINVAL); clean unchanged.
- **Live (unpatched kernel):** `mount_ntfs` panics with `NTFS vattr: malloc limit exceeded`,
  stack through `ntfs_loadntnode+0x178`. Guest dies at DDB.
- **Live (patched ntfs.ko):** `mount_ntfs` returns `Invalid argument` (RC=71), dmesg shows
  `ntfs_loadntnode: failed to load attr ino: 5`, guest stays UP. Clean images still mount.

## Preconditions
- `mount_ntfs` is root-only (`vfs.usermount=0` on stock DragonFly). Threat model:
  admin mounts attacker-supplied NTFS image / USB stick.
- Reachable at mount time; does NOT require the post-mount lookup path (so the DF-0786
  lockmgr panic does not block this finding).
