ffs_reallocblks reads start_ap[-1] (stack OOB) when a cluster spans direct→indirect blocks — DIAGNOSTIC-only
| Field | Value |
|---|---|
| ID | DF-3036 |
| Status | new |
| Severity | Info |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L |
| CWE | CWE-125 |
| File | sys/vfs/ufs/ffs_alloc.c |
| Lines | 430-433 (cf. guards :410, :512) |
| Area | vfs/ufs |
| Confidence | certain |
| Discovered | 2026-09-02 |
| Pass | 2 (GLM 5.3 second pass) |
| Bucket | base:vfs |
| Reported | pending |
| Known CVE | none |
| CVE match | novel |
Summary
When start_lvl==0 (cluster begins in the direct block array) and the cluster's last block lands in an indirect block (end_lvl>0 with end_ap[end_lvl−1].in_off+1 < len, e.g. LBNs 10-12 with UFS_NDADDR=12), the DIAGNOSTIC block evaluates start_ap[start_lvl−1].in_lbn == start_ap[−1].in_lbn — an out-of-bounds stack read below the indir array, plus a possible spurious 'ffs_reallocblk: start == end' panic from garbage. Reachable only in kernels built with 'options DIAGNOSTIC' (not the stock/INVARIANTS configuration); no effect on production kernels. Fix: guard the comparison with start_lvl > 0 (one-liner).
Timeline
- 2026-09-02 Discovered during pass-2 audit of ffs_alloc.c (GLM 5.3).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3036 · 4 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | — | 246 B | ↓ raw | |
| fix.diff | — | 413 B | view raw | |
| manifest.json | — | 350 B | view raw | |
| verdict.json | — | 1.7 KB | view raw |
DF-3036 evidence pack
What
ffs_reallocblks reads start_ap[-1] in the DIAGNOSTIC block (start_lvl==0)
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_testableguard is a trivially-correct one-line change inside the #ifdef DIAGNOSTIC block; the enclosing ffs_alloc.c compiled in F40FIX but the DIAGNOSTIC branch itself requires options DIAGNOSTIC (not set on any guest kernel this batch); full compile validation deferred to a DIAGNOSTIC/LINT build upstream
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 - DIAGNOSTIC not compiled in any guest kernel
Verified recommended fix
guard the DIAGNOSTIC start==end check with start_lvl > 0
Verdict
Line-accurate confirmation at ffs_alloc.c:430-433: when the cluster starts in the direct block array (start_lvl==0) and the DIAGNOSTIC block evaluates start_ap[start_lvl-1].in_lbn, that is start_ap[-1] - an OOB stack read plus a possible spurious panic. Unreachable on the stock and F40FIX kernels: DragonFly X86_64_GENERIC does not compile options DIAGNOSTIC (verified on guest: kern.conftxt DIAGNOSTIC count 0), so the block is absent from the binaries; a DIAGNOSTIC kernel was not built for this Info-tier batch. The one-line guard (start_lvl > 0) is trivially correct C; the enclosing file compiled in F40FIX (ffs in kernel).
No comments yet.