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

readv/writev/extpreadv/extpwritev accept iovcnt==0 β€” POSIX EINVAL missing; uninitialized stack iovec pointer plumbed into fo_read/fo_write

Field Value
ID DF-2732
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:N
CWE CWE-20 / CWE-457
File sys/kern/sys_generic.c
Lines 195, 227, 399, 431 (root kern_subr.c:448-456)
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

iovec_copyin validates only (u_int)iov_cnt > UIO_MAXIOV, so iovcnt==0 passes; the four vector syscalls then run with uio_iov pointing at the caller's uninitialized stack aiov, uio_iovcnt=0, uio_resid=0. POSIX mandates EINVAL for iovcnt<=0 (FreeBSD returns EINVAL). Reproduced: all ten tested forms return ret=0 errno=0. No panic reachable on stock (every surveyed consumer gates on uio_resid>0) β€” latent hazard for any consumer dereferencing uio_iov[0] before a resid check.

In iovec_copyin (kern_subr.c), before the UIO_MAXIOV check: if (iov_cnt <= 0) return (EINVAL);

Timeline

  • 2026-08-30 Discovered during pass-2 audit of sys_generic.c (GLM 5.3); behavior verified on stock same run.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2732 Β· 6 files
FileTypeDescriptionSize
iovcnt0.c β€” 2.7 KB view raw
run.log β€” 973 B view raw
run.2.log β€” 1.2 KB view raw
build.sh β€” 37 B view raw
run.sh β€” 20 B view raw
env.txt β€” 150 B view raw

Fix verification

not_testable
per-fix-DF-2732

Confirmed kernel references

Detail

Evidence (decisive lines)

['run.log (10/10 iovcnt==0 calls ret=0 errno=0; negative control -1 -> EMSGSIZE)', 'run.2.log (independent boot, identical)']

PoC changes

written fresh for this pass (no seed)

Verified recommended fix

Reject iovcnt <= 0 with EINVAL in iovec_copyin() (kern_subr.c) or at each syscall entry.

Verdict

readv/writev/extpreadv/extpwritev accept iovcnt==0 and return success on every fd type (file, socket, pipe, /dev/zero) instead of POSIX-mandated EINVAL, plumbing an uninitialized stack iovec pointer (uio_iov) with uio_iovcnt=0/uio_resid=0 into fo_read/fo_write dispatch. No memory-safety manifestation reachable on the stock kernel (all consumers gate on uio_resid>0); classified Low (correctness + latent uninit-pointer plumbing).