refcount_release/_n have no underflow floor or INVARIANTS assert β double-release silently wraps the count to 0xFFFFFFFF and hides DF-2941-class double-put/double-free bugs at runtime
| Field | Value |
|---|---|
| ID | DF-2987 |
| 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-754 |
| File | sys/kern/kern_refcount.c |
| Lines | header sys/sys/refcount.h:54-70 |
| Area | kern |
| Confidence | certain |
| Discovered | 2026-09-02 |
| Pass | 2 (GLM 5.3 second pass) |
| Bucket | memcorrupt |
| Reported | pending |
| Known CVE | none |
| CVE match | novel |
Summary
The put-side primitives in sys/sys/refcount.h (consumed by every kern_refcount.c caller) perform a blind atomic_fetchadd_int(countp, β1/βi) with no floor and no INVARIANTS assert: releasing an already-zero (or over-released) counter wraps it to 0xFFFFFFFF and returns FALSE, leaving the corruption completely silent β even on an INVARIANTS kernel. This is the exact analog of the sysref put-side floor gap (DF-2941): the ~100+ in-tree consumers get no run-time tripwire against double-put bugs, so the UAF/double-free family remains undetectable until unrelated memory corruption manifests elsewhere. The count can never recover β a wrapped counter also permanently wedges refcount_wait callers into the 10s-polled slowpath. Defense-in-depth gap only (kernel-internal primitive, no userland entry). Fix: INVARIANTS-only floor asserts, non-INVARIANTS fast path identical (row diff). Protocol otherwise proven sound this pass (wait/wakeup interlock, torn windows, double-release, bit aliasing all killed with citations).
Timeline
- 2026-09-02 Discovered during pass-2 audit of kern_refcount.c (GLM 5.3).
No comments yet.