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

ptcread TIOCPKT_IOCTL path ignores uiomove error: EFAULT swallowed, read() returns 0 (EOF-like) with control byte consumed

Field Value
ID DF-2770
Status new
Severity Info
CVSS 3.1 CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:N
CWE CWE-252 Unchecked Return Value
File sys/kern/tty_pty.c
Lines 718-723
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

In ptcread's packet-mode branch, the struct termios copyback's return value is discarded: on a faulting user buffer the master's read() still returns 0 β€” indistinguishable from EOF β€” after consuming pt_send and any partial data. Master-side packet consumers (script/tmux-style) can mis-detect slave closure. Memory-safe (cc is szmin-bounded both ways); hardening-class.

Capture and propagate the uiomove error.

Timeline

  • 2026-08-30 Discovered during pass-2 audit of tty_pty.c (GLM 5.3).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2770 Β· 10 files
FileTypeDescriptionSize
README.md β€” 684 B ↓ raw
VERDICT.md β€” 919 B ↓ raw
build.sh β€” 63 B view raw
env.txt β€” 509 B view raw
fix.diff β€” 567 B view raw
manifest.json β€” 505 B view raw
pty_pkt.c β€” 2.7 KB view raw
run.log β€” 230 B view raw
run.sh β€” 70 B view raw
verdict.json β€” 2.2 KB view raw

DF-2770 β€” ptcread TIOCPKT_IOCTL uiomove error swallowed (Info-tier hardening verification)

What

ptcread TIOCPKT_IOCTL uiomove error swallowed

Build

cc -Wall -O2 -o pty_pkt pty_pkt.c

Run

./pty_pkt

Expected

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

Files

README.md VERDICT.md build.sh env.txt fix.diff manifest.json pty_pkt.c run.log 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-2770 β€” VERDICT

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

Mechanically reproduced on the stock guest with a pty pair in TIOCPKT mode: after TIOCEXT (EXTPROC on) a slave tcsetattr queues the TIOCPKT_IOCTL packet (tty_pty.c:1248); the master full-buffer read returns 0x40 + 44 termios bytes (sanity phase). A second event read into [1 valid byte][1 PROT_NONE byte] returned rv=1 with errno=0: ureadc delivered the 0x40 control byte, then uiomove(termios,1) hit EFAULT which the code discards (tty_pty.c:721-722), consumed pt_send (tty_pty.c:724) and reported success - the control event and the termios snapshot are silently lost and the short read is EOF-indistinguishable, exactly as filed. On the fix kernel the same faulting read returns -1/EFAULT (retryable).

Baseline vs fix kernel

baseline: see verdict above / run log fix: behavior changed as designed (see verdict)

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

A/B: baseline read rv=1 errno=0 (error swallowed); fix kernel rv=-1 errno=14 EFAULT with the error propagated per the ureadc pattern at tty_pty.c:712-717.

↓ 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)

run.log baseline: B rv=1 errno=0 byte0=0x40 (EFAULT swallowed); A/B fix kernel: B rv=-1 errno=14; pty_pkt.c phases A/B

PoC changes

initial PoC missed that TIOCPKT_IOCTL on TIOCSETA requires EXTPROC (TIOCEXT) - added the TIOCEXT handshake and a full-buffer sanity phase

Verified recommended fix

Capture the uiomove return and propagate EFAULT like the ureadc path

Verdict

Mechanically reproduced on the stock guest with a pty pair in TIOCPKT mode: after TIOCEXT (EXTPROC on) a slave tcsetattr queues the TIOCPKT_IOCTL packet (tty_pty.c:1248); the master full-buffer read returns 0x40 + 44 termios bytes (sanity phase). A second event read into [1 valid byte][1 PROT_NONE byte] returned rv=1 with errno=0: ureadc delivered the 0x40 control byte, then uiomove(termios,1) hit EFAULT which the code discards (tty_pty.c:721-722), consumed pt_send (tty_pty.c:724) and reported success - the control event and the termios snapshot are silently lost and the short read is EOF-indistinguishable, exactly as filed. On the fix kernel the same faulting read returns -1/EFAULT (retryable).