poll() silently truncates nfds to kern.maxfilesperproc*2 β ready descriptors beyond the clamp are dropped without error
| Field | Value |
|---|---|
| ID | DF-2733 |
| Status | new |
| Severity | Low |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L |
| CWE | CWE-20 |
| File | sys/kern/sys_generic.c |
| Lines | 1639-1640 |
| 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
dopoll() clamps nfds to maxfilesperproc2 (65056 on this guest) instead of returning EINVAL; pollfd entries beyond the clamp are silently ignored. Demonstrated: the only ready descriptor (pipe with data) placed at index clamp+16 β poll returns 0 with no error, while the same descriptor at index 5 returns 1. POSIX requires EINVAL when nfds exceeds the implementation limit. Silent truncation can hang daemons built for large poll sets; also latent signed-int overflow in maxfilesperproc2 if root sets it β₯ 2^30.
Recommended fix
Replace the clamp with if (nfds > maxfilesperproc * 2) return
(EINVAL); in dopoll().
Timeline
- 2026-08-30 Discovered during pass-2 audit of sys_generic.c (GLM 5.3); silent-drop behavior verified on stock same run.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2733 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| pollclamp.c | β | 1.9 KB | view raw | |
| run.log | β | 242 B | view raw | |
| run.2.log | β | 242 B | view raw | |
| build.sh | β | 41 B | view raw | |
| run.sh | β | 22 B | view raw | |
| env.txt | β | 150 B | view raw |
Fix verification
not_testableConfirmed kernel references
Detail
Evidence (decisive lines)
['run.log (ready fd idx 5 -> 1; idx clamp+16 -> 0)', 'run.2.log (independent boot, identical)']
PoC changes
written fresh for this pass (no seed)
Verified recommended fix
Return EINVAL when nfds exceeds maxfilesperproc*2 instead of silently truncating.
Verdict
dopoll() silently clamps nfds to 2*kern.maxfilesperproc (65056 on guest) instead of returning EINVAL; a demonstrably-ready descriptor placed at index clamp+16 is silently dropped (poll returns 0, errno 0) while the same descriptor at index 5 returns 1. POSIX requires EINVAL; silent truncation can hang applications built for large poll sets. Low severity (correctness).
No comments yet.