# DF-0776 — Missing production bounds validation on HAMMER B-tree node `count`/`type`

## Verdict
**REPRODUCED + FIX VALIDATED.**

On the GENERIC (INVARIANTS-ON) kernel the bug manifests as a kernel **panic**
(local DoS) at `hammer_btree.c:1278` on the first `btree_search` of a forged
node. On a production (INVARIANTS-OFF) kernel the same forged node drives
deterministic **OOB kernel-heap read** (info leak, up to ~8 KB per access via
`hammer_btree_search_node` + leaf loop) and **OOB kernel-heap write** (up to
~8.8 KB via `hammer_btree_insert`'s `bcopy` element shift). The `fix.diff`
adds runtime validation of `type`/`count` in `hammer_load_node` plus error
propagation through `hammer_init_cursor`/`hammer_get_inode`; the panic is gone
on a single-fix `#1` kernel (mount returns EIO, guest stays up, normal mounts
unaffected).

## Reproduce
```sh
./build.sh                      # builds craft_img (forger) + harness (OOB proof)
./run.sh                        # harness + image creation + forge + mount + ls
```
The `mount` step is the acceptable root precondition (admin mounts a crafted
image). The `ls`/`stat` trigger is unprivileged (in the production/INVARIANTS-OFF
case where mount succeeds and readdir hits the loops). On GENERIC, the panic
fires at mount-time (the mount's own root-inode btree lookup is the first hit).

### Expected output
- **GENERIC #0** (unpatched, INVARIANTS ON):
  `panic: assertion "node->count <= HAMMER_BTREE_LEAF_ELMS" failed in btree_search
  at hammer_btree.c:1278` — guest wedges in DDB. See `panic.txt`.
- **Production** (INVARIANTS OFF): harness shows the OOB extents (read + write).
- **Fix #1**: `mount: Input/output error` (EIO), dmesg shows
  `hammer_load_node: B-TREE NODE @ ... BAD type=76 count=200`, no panic, guest healthy.
