sys_getsid reads the p_pgrp->pg_session chain without pt->p_token; sys_setpgid reads curp->p_session unlocked β lifetime race vs. enterpgrp's pgrp free (stale/UAF read)
| Field | Value |
|---|---|
| ID | DF-2760 |
| Status | new |
| Severity | Low |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:L |
| CWE | CWE-667 / CWE-367 |
| File | sys/kern/kern_prot.c |
| Lines | 153-154 (sibling correct at :124-126), 383, 404 |
| Area | kern |
| Confidence | certain |
| Discovered | 2026-08-30 |
| Pass | 2 (GLM 5.3 second pass) |
| Bucket | memcorrupt |
| Reported | pending |
| Known CVE | none |
| CVE match | novel |
Summary
p_session is a macro over p_pgrp. sys_getpgid correctly wraps its chain
deref in lwkt_gettoken_shared(&pt->p_token), but sys_getsid reads
pt->p_pgrp->pg_session->s_sid with no token at all, and sys_setpgid
reads curp->p_pgrp->pg_session unlocked while holding only targp's
token. p->p_pgrp is only stable under p->p_token: enterpgrp swaps it
and drops the old pgrp's refs, freeing the old pgrp (and possibly its
session) when the mover was the last member. An unlocked reader that
loads p_pgrp just before the swap then dereferences freed memory β
getsid returns a sid through two chained loads of a freed object;
setpgid compares a session pointer loaded from a freed pgrp. Realistic
ceiling: stale/incorrect sid (correctness/info) with a practically
unreachable groomed-garbage panic path; no write primitive.
Recommended fix
Mirror sys_getpgid's token discipline: take pt->p_token shared around the getsid read; snapshot curp->p_pgrp->pg_session under curp's token (brief, non-nested) before the setpgid comparisons.
Timeline
- 2026-08-30 Discovered during pass-2 audit of kern_prot.c (GLM 5.3).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2760 Β· 3 files| File | Type | Description | Size | |
|---|---|---|---|---|
| getsid_race.c | β | 2.6 KB | view raw | |
| run.log | β | 244 B | view raw | |
| fix.diff | β | 1.2 KB | view raw |
Fix verification
not_testableToken-discipline fix (getsid shared token; setpgid curp token) compile-validated; no observable anomaly to A/B (365K baseline samples clean).
compile-validated in the fix-all kernel build (make nativekernel, 0 errors)
Confirmed kernel references
Detail
Evidence (decisive lines)
getsid_race.c; df2760_getsid.log: 365,448 samples, 0 anomalies, no panic
PoC changes
registry-based validation (shared mmap of churner pids)
Verified recommended fix
--- sys/kern/kern_prot.c 2026-06-29 12:51:19.000000000 +0000
Verdict
Code-verified lock-discipline gap; race window not observable externally. sys_getsid (sys/kern/kern_prot.c:153-154) dereferences pt->p_pgrp->pg_session with no p_token while the adjacent sys_getpgid wraps the same chain in a shared token (:124-126); sys_setpgid reads curp->p_session unlocked at :383/:404 while holding only targps token. A hammer run with 24 processes churning setpgid/setsid (pgrp/session alloc/free) and a checker performing 365,448 getsid() samples on a shared pid registry produced zero impossible values, zero stale-transition observations, and no panics - the p_ucred/p_pgrp swap window is too narrow to catch from another process without heavy grooming, matching the findings own assessment (realistic ceiling: stale/incorrect sid; groomed-garbage panic practically unreachable). The token-discipline fix (mirror getpgid) is compile-validated and A/B-safe.
No comments yet.