kobj_class_free() reclaims the compiled ops table with no grace period while the lock-free dispatch hot path reads it (force multiplier turning any consumer refcount slip into a freed function-pointer table call)
| Field | Value |
|---|---|
| ID | DF-2961 |
| Status | new |
| Severity | Low |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H |
| CWE | CWE-362 / CWE-416 |
| File | sys/kern/subr_kobj.c |
| Lines | 179-208 (dispatch :184-188; kfree :206; publish :260) |
| Area | kern/kobj |
| Confidence | certain |
| Discovered | 2026-09-02 |
| Pass | 2 (GLM 5.3 second pass) |
| Bucket | memcorrupt |
| Reported | pending |
| Known CVE | none |
| CVE match | novel |
Summary
Every KOBJOPLOOKUP dispatch executes kobj_lookup_method_cache() completely unsynchronized: it reads OPS->cls, cep[desc->id & 255], ce->desc and finally indirect-calls ce->func, and the slow path even WRITES the cache slot. Meanwhile kobj_class_uninstantiate() drops the last reference and kobj_class_free() immediately kfree()s the 2056-byte ops table holding only kobj_token β a lock the dispatch path never takes. kobj_init() likewise publishes obj->ops = cls->ops with no release/acquire discipline relative to a concurrent free. kobj therefore provides zero read-side lifetime protection: any consumer that drops the class reference even transiently while another CPU is mid-dispatch (exactly the unprivileged sysctl-reader-vs-device-teardown race already proven as DF-2679 against subr_bus) turns a would-be benign stale read into a UAF walk of freed slab memory culminating in an indirect call through reclaimed data β RIP control if the attacker grooms the freed 2056-byte block (/dev/dsp open/close cycles legitimately compile/free channel-class ops at attacker-influenced timing). No in-tree caller misbalances refs by itself β newbus, libiconv, and PCM sound are balanced β which is why this is filed Low/defense-in-depth: the kobj layer is the multiplier, the trigger is a consumer lifetime bug. No standalone PoC exists or should exist at the kobj layer (manufacturing the primitive requires a buggy demonstration driver; verification deferred to the consumer-side DF-2679 which owns the reachable trigger). Fix: grace period or never-free static classes (row sketch).
Timeline
- 2026-09-02 Discovered during pass-2 audit of subr_kobj.c (GLM 5.3).
No comments yet.