{
  "finding_id": "DF-2626",
  "title": "hammer2_read_file() discards uiomovebp() error: unprivileged unkillable in-kernel livelock on read()/readlink() with EFAULT destination",
  "verdict": "reproduced",
  "impact": "dos",
  "confidence": "certain",
  "reproduce": {
    "build": "cc -O2 -Wall -o poc poc.c && cc -O2 -Wall -o readlink_poc readlink_poc.c   (on guest, any dir)",
    "run": "as unprivileged user on the hammer2 root fs: ./poc /etc/rc   (and ./readlink_poc)",
    "expected_vulnerable": "read() never returns; ps shows STAT R, 100% CPU, wchan '-'; kill -9 ineffective; 6 instances on 6 distinct hammer2 files starve all CPUs (ssh dead, serial console silent, no panic)",
    "expected_fixed": "read returned -1 errno=14 (Bad address), exit 0, in 0.00 s; box idle"
  },
  "kernel_refs": [
    "sys/vfs/hammer2/hammer2_vnops.c:983",
    "sys/vfs/hammer2/hammer2_vnops.c:926",
    "sys/vfs/hammer2/hammer2_vnops.c:922",
    "sys/vfs/hammer2/hammer2_vnops.c:986",
    "sys/vfs/hammer2/hammer2_vnops.c:790",
    "sys/kern/kern_subr.c:148",
    "sys/kern/vfs_vnops.c:751"
  ],
  "artifacts": [
    {"path": "poc.c", "desc": "trigger: read() into mmap(PROT_NONE, MAP_FIXED) page — guaranteed fault at byte 0"},
    {"path": "readlink_poc.c", "desc": "trigger: readlink() of a hammer2 symlink into PROT_NONE page"},
    {"path": "build.sh", "desc": "exact build commands (guest cc)"},
    {"path": "run.sh", "desc": "exact run commands incl. timeout-based vulnerable/fixed discrimination"},
    {"path": "build.log", "desc": "build transcript with honesty note (in-guest log lost to final reset)"},
    {"path": "run.log", "desc": "DECISIVE: single unprivileged reader — STAT R2, 100.0% CPU, wchan '-', survives two kill -9"},
    {"path": "wedge1.log", "desc": "same-file multi-reader (100% sys, getblk interleave) + tmpfs control (EFAULT returned, 'tmpfs_read uiomove error 14' on console)"},
    {"path": "wedge2.log", "desc": "6 readers on 6 distinct hammer2 files — monitoring session truncated to header; vm.sh status down"},
    {"path": "serial_wedge1.log", "desc": "serial console mirror of run.log evidence (survives ssh death)"},
    {"path": "serial_wedge2.log", "desc": "serial console: last line is the wedge-test header, then silence (full starvation, no panic)"},
    {"path": "serial_initial_wedge.log", "desc": "first-ever incident: single reader with unmapped dest wedged box (pre-instrumentation)"},
    {"path": "readlink_stock.log", "desc": "readlink vector on stock kernel: session died mid-script"},
    {"path": "serial_readlink_stock.log", "desc": "serial console of the readlink stock run"},
    {"path": "fix.diff", "desc": "validated fix: propagate uiomovebp() error, bqrelse preserved, break on error (git apply -p1)"},
    {"path": "fix_build.log", "desc": "kernel rebuild transcript (verbatim poll excerpts; full log lost to final reset — flagged)"},
    {"path": "fix_run.log", "desc": "patched kernel: exact same PoC binary returns -1/EFAULT in 0.00 s, exit 0"},
    {"path": "fix_readlink.log", "desc": "patched kernel: readlink variant returns -1/EFAULT in 0.00 s"},
    {"path": "fix_regress.log", "desc": "patched kernel regression: 50/50 good reads, 50/50 EFAULTs, 6-file pattern leaves 0 spinners, 98.9% idle"},
    {"path": "env.txt", "desc": "guest environment (uname, mounts, users, targets)"},
    {"path": "VERDICT.md", "desc": "full narrative: source trace, empirical runs, fix validation, honest notes"},
    {"path": "manifest.json", "desc": "this catalog"},
    {"path": "verdict.json", "desc": "machine verdict consumed by audit/persist_poc.py and audit/persist_fix.py"}
  ]
}
