β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-2933

xio_init_kbuf: size_t→int truncation of kbytes at kern_xio.c:121 corrupts xio_bytes negative while returning success

Field Value
ID DF-2933
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:L
CWE CWE-197 / CWE-190
File sys/kern/kern_xio.c
Lines 119-121, 131
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

In xio_init_kbuf's load loop, kbytes (size_t) is assigned into n (int) at :121. For a caller requesting kbytes β‰₯ 2^31+4097 with a page-aligned kbase, the first iteration consumes one page leaving kbytes > INT_MAX; (int)kbytes wraps negative, so the second iteration executes kbytes -= n (wraps up to exactly 2^32) and xio_bytes += n (signed overflow β†’ β‰ˆ βˆ’2147475455), after which n==0 exits the loop. The error guard at :131 does not fire because n==0 β€” the function returns 0 (success) holding only 2 pages while xio_bytes is negative garbage. Distinct mechanism from DF-0160 (different line, different threshold, corrupts xio_bytes rather than truncating). Proven by exact two's-complement arithmetic simulation. Latent: xio_init_kbuf has ZERO in-tree callers (only the prototype in xio.h); reachable only by a third-party KLD passing a >2GiB kernel buffer. Fail-safe direction downstream (negative xio_bytes makes copy guards EFAULT) β€” corrupted API state/DoS-class at worst, not memory unsafety. Fix: keep byte counters in a single wide type (diff in row) / reject kbytes > INT_MAX up front.

Timeline

  • 2026-09-02 Discovered during pass-2 audit of kern_xio.c (GLM 5.3). Known DF-0157-0160 re-verified still present, not re-reported.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2933 Β· 10 files
FileTypeDescriptionSize
README.md β€” 773 B ↓ raw
VERDICT.md β€” 1009 B ↓ raw
build.sh β€” 50 B view raw
env.txt β€” 509 B view raw
fix.diff β€” 562 B view raw
h41.c β€” 14.9 KB view raw
harness.log β€” 2.0 KB view raw
manifest.json β€” 501 B view raw
run.sh β€” 105 B view raw
verdict.json β€” 2.0 KB view raw

DF-2933 β€” xio_init_kbuf int truncation corrupts xio_bytes (Info-tier hardening verification)

What

xio_init_kbuf int truncation corrupts xio_bytes

Build

cd /root/h41 && make

Run

kldload ./h41.ko; sysctl -w debug.h41.cmd=11

Expected

baseline (stock kernel): see verdict below fix kernel (all-41-fixes build): the bad behavior is gone

A/B one-liner: baseline: ret 0 xio_bytes<0 | fix: ret 22 EINVAL

Files

README.md VERDICT.md build.sh env.txt fix.diff h41.c harness.log manifest.json run.sh verdict.json

Shared harness: h41.c (combined KLD, sysctl debug.h41.cmd=N driven). Full batch context: the fix kernel contains all 41 hardening fixes of this batch compiled together (build RC=0) and passed the complete A/B suite plus a clean reboot.

VERDICT.md
↓ download raw

DF-2933 β€” VERDICT

status: reproduced | reproduced: 1 | impact: none | confidence: certain

Mechanically reproduced via the harness on the stock guest with kbytes = 0x80001001 (2GiB+4097) and a valid 2-page kernel buffer: xio_init_kbuf returned 0 (success) with xio_bytes = -2147479551 (exactly 4096 + (int)0x80000001 two's-complement garbage) and npages=2 - the size_t kbytes -> int n truncation at kern_xio.c:121 wraps negative, the second iteration wraps kbytes to 2^32, xio_bytes overflows signed, and the n==0 exit dodges the error guard at :131. Distinct mechanism from DF-0160 (line :121 vs :113/:131, 2GiB threshold vs 128KiB, corrupts xio_bytes rather than truncating). Latent: zero in-tree callers (prototype-only API); downstream consumers treat negative xio_bytes as error (fail-safe). On the fix kernel the call returns EINVAL with xio_bytes untouched.

Baseline vs fix kernel

baseline: baseline: ret 0 xio_bytes<0 | fix: ret 22 EINVAL fix: behavior changed as designed (see verdict)

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

A/B: baseline returns success holding negative xio_bytes; fix kernel rejects kbytes > INT_MAX up front.

↓ fix.diffDragonFly dfbsd 6.5-DEVELOPMENT #1: Mon Oct 26 01:57:23 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64 (h41 fix kernel, all 41 hardening fixes applied)

Confirmed kernel references

Detail

Evidence (decisive lines)

harness.log T11: ret=0 bytes=-2147479551; fix kernel T11: ret=22/EINVAL

PoC changes

2 valid kernel pages suffice to drive the two-iteration wrap

Verified recommended fix

Reject kbytes > INT_MAX before the load loop

Verdict

Mechanically reproduced via the harness on the stock guest with kbytes = 0x80001001 (2GiB+4097) and a valid 2-page kernel buffer: xio_init_kbuf returned 0 (success) with xio_bytes = -2147479551 (exactly 4096 + (int)0x80000001 twos-complement garbage) and npages=2 - the size_t kbytes -> int n truncation at kern_xio.c:121 wraps negative, the second iteration wraps kbytes to 2^32, xio_bytes overflows signed, and the n==0 exit dodges the error guard at :131. Distinct mechanism from DF-0160 (line :121 vs :113/:131, 2GiB threshold vs 128KiB, corrupts xio_bytes rather than truncating). Latent: zero in-tree callers (prototype-only API); downstream consumers treat negative xio_bytes as error (fail-safe). On the fix kernel the call returns EINVAL with xio_bytes untouched.