cluster_write() reads bp->b_bio2.bio_offset after bdwrite()/bawrite() released the buffer β type-stable use-after-free reads corrupting write-clustering heuristics
| Field | Value |
|---|---|
| ID | DF-2726 |
| 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:N |
| CWE | CWE-416 (non-exploitable pool-object read) |
| File | sys/kern/vfs_cluster.c |
| Lines | 1344-1346, 1365, 1408-1409 (releases at 1340-1342, 1363, 1388/1401/1406) |
| Area | kern |
| Confidence | certain |
| Discovered | 2026-08-30 |
| Pass | 2 (GLM 5.3 second pass) |
| Bucket | base:kern |
| Reported | pending |
| Known CVE | none |
| CVE match | novel |
Summary
In three paths cluster_write() disposes of bp via bdwrite()/bawrite()
β which release the buffer lock β and then reads
bp->b_bio2.bio_offset to update the cluster-tracking cache. Between
release and read, any CPU (or the biodone interrupt path for bawrite)
can re-lock, re-purpose, or recycle the buf header, so v_lasta/v_lastw
can be computed from another vnode's data. Buffer headers live in the
type-stable buf pool (never unmapped), so this cannot fault and the
stolen value feeds only heuristic decisions (all re-validated against
live buffers; negative/truncated values degrade to no-op scans). No
memory unsafety, no info leak β hardening/correctness only, and a trap
if b_bio2 ever becomes a pointer-bearing field.
Recommended fix
Capture bio_offset into a local before the first bdwrite/bawrite in each path (mirror of FreeBSD's ordering which computes v_lasta before disposing).
Timeline
- 2026-08-30 Discovered during pass-2 audit of vfs_cluster.c (GLM 5.3).
No comments yet.