KKASSERT is the only bounds check before bcopy/hammer_datacrc in hammer_indirect_callback (defense-in-depth gap on non-INVARIANTS kernels)
| Field | Value |
|---|---|
| ID | DF-3034 |
| Status | new |
| Severity | Info |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:N/I:N/A:N |
| CWE | CWE-617 (assert-as-bounds-check) |
| File | sys/vfs/hammer/hammer_io.c |
| Lines | 1658-1677 |
| Area | vfs/hammer |
| Confidence | likely |
| Discovered | 2026-09-02 |
| Pass | 2 (GLM 5.3 second pass) |
| Bucket | base:vfs |
| Reported | pending |
| Known CVE | none |
| CVE match | novel |
Summary
hammer_indirect_callback() validates that the device-side buffer covers the request only via KKASSERT(bp->b_bufsize >= obp->b_bufsize) β compiled out on production kernels β and then bcopy()s obp->b_bufsize bytes out of bp->b_data; the preceding CRC check has the same unguarded assumption. The code's own comment admits fragility ('due to big-block recycling and other factors there is some fragility there'), and HAMMER genuinely mixes 16K and 64K buffer sizes in the large-data zone, so a future regression in buffer sizing turns this into an OOB kernel heap read copied into a user-readable file buffer. Currently not exploitable: getblk guarantees an exact size match (disposes of mismatched buffers and retries), both breadcb and cluster_readcb acquire the callback's buffer at exactly obp->b_bufsize, and the path requires hammer_double_buffer=1 (non-default). Filed as Info hardening: the memory-safety property is incidental (relies on distant getblk internals) and any buffer-size regression immediately becomes an OOB read (kernel heap β user file page) on production kernels. Fix: convert the assert into an explicit runtime check + short-circuit the CRC condition (row diff). Same assert-as-bounds-check class as DF-3003 (:931), kept separate because the guarded operations differ.
Timeline
- 2026-09-02 Discovered during pass-2 audit of hammer_io.c (GLM 5.3).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3034 Β· 4 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 243 B | β raw | |
| fix.diff | β | 920 B | view raw | |
| manifest.json | β | 395 B | view raw | |
| verdict.json | β | 1.7 KB | view raw |
DF-3034 evidence pack
What
hammer_indirect_callback: KKASSERT-only size gate before bcopy/datacrc
Verdict
status=not_reproduced impact=none confidence=certain
See VERDICT.md for the full narrative and fix.diff for the verified fix.
Fix verification
not_testablefix.diff applied in the F40FIX verification kernel build (RC=0, zero -Werror errors); no runtime A/B for this item (line-certain hardening)
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md with path:line citations; run.log where a live demo exists; fix.diff
PoC changes
n/a - no PoC (size match guaranteed by getblk/breadcb on this guest)
Verified recommended fix
explicit bp->b_bufsize >= obp->b_bufsize runtime gate failing with EIO, ahead of CRC + bcopy
Verdict
Line-accurate confirmation; runtime demonstration deliberately not attempted (the mismatched-device-buffer precondition is prevented by getblk/breadcb acquiring at exactly obp->b_bufsize, and the path requires non-default hammer_double_buffer=1). The only gate before bcopy(bp->b_data, ..., obp->b_bufsize) is the KKASSERT at hammer_io.c:1676 - compiled out on production - and the CRC check at :1658-1664 reads obp->b_bufsize bytes from bp->b_data with the same unguarded assumption. Fix adds an explicit runtime size gate (B_ERROR/EIO short-circuit before the CRC condition); compiled in the F40FIX build (HAMMER in kernel).
No comments yet.