plimit COW swap stores p->p_limit without p->p_spin, leaving a theoretical ref-acquisition race window against cross-process readers (schedcpu)
| Field | Value |
|---|---|
| ID | DF-2913 |
| Status | new |
| Severity | Info |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:L |
| CWE | CWE-667 Improper Locking |
| File | sys/kern/kern_plimit.c |
| Lines | 189, 226 (readers :100-103, kern_descrip.c:624-632) |
| Area | kern |
| Confidence | speculative |
| Discovered | 2026-09-02 |
| Pass | 2 (GLM 5.3 second pass) |
| Bucket | memcorrupt |
| Reported | pending |
| Known CVE | none |
| CVE match | novel |
Summary
readplimits reads p->p_limit and takes a reference while holding p->p_spin shared, but the writers of p->p_limit β the COW swap in plimit_modify (:226) and plimit_lwp_fork (:189) β store the new pointer with no lock at all. The shared spinlock therefore does not serialize readers against the writer; it only serializes readers against each other. For user threads this is saved by the EXCLUSIVE invariant (a multithreaded process never swaps; a single-threaded process has no concurrent reader), but schedcpu's cross-process check (kern_synch.c:308 β plimit_testcpulimit β readplimits) can race a single-threaded target's setrlimit/lwp_create COW swap: the kernel thread loads the old p->p_limit under the spinlock and then increments p_refcnt in a separate locked instruction (confirmed in the shipped kernel at 0xffffffff80655b5cβ0xffffffff80655b60). If every remaining reference drained inside that 2-instruction window, the increment would land on freed memory β later UAF decrement. Not reachable with any reliability (preemption must land exactly between two instructions AND a multi-millisecond teardown must complete inside it) β Info/speculative hardening so the lock protocol matches its documented intent. The related CPU-limit kill-test overflow candidate was FALSIFIED live on the guest (unsigned predicate confirmed in disassembly; SIGXCPU + survival delivered correctly; evidence findings/poc/DF-2913/). plimit_testcpulimit's comment also claims a spinlock retest that does not exist β benign on x86_64.
Recommended fix
spin_lock(&p->p_spin) around both COW pointer stores (leaf lock, no inversion risk); optionally implement or delete the stale :456-459 comment.
Timeline
- 2026-09-02 Discovered during pass-2 audit of kern_plimit.c (GLM 5.3); overflow candidate falsified live, invariant protocol proven sound.
No comments yet.