DragonFlyBSD Kernel Audit
DF-2769 / fix.diff
← back to finding ↓ download raw
DF-2769: refuse master re-open while the unix98 pty slave is still open

ptcclose() disarms every admission gate a fresh ptcopen() would check:
it clears t_oproc (tty_pty.c:674), NULLs pt_prison (tty_pty.c:676) and
sets both device nodes to 0:0 mode 0666 (tty_pty.c:677-682), while
termination (and thus destruction of the master cdev) is blocked because
the slave is still open (PF_SOPEN, tty_pty.c:273).  Any process that can
name the master device (/dev/ptm/N -- DEVFS_HIDDEN by default, exposed
by devfs `show` rules such as those used for jail /dev trees) is then
admitted as the new master of a still-live slave session.  The TS_ZOMBIE
fence is cleared by the new master itself via TIOCSETAW with CLOCAL
(ttioctl, sys/kern/tty.c:1065-1072), giving it terminal input injection
(ptcwrite), output capture (ptcread) and signal injection (TIOCSIG)
against the surviving session -- verified as unprivileged command
execution in a surviving root session.

Fix: unix98 pty semantics -- once the master has been closed while the
slave is open, the pty is dead for everyone; refuse with EIO.  PF_SOPEN
can only be set after a previous master existed, so first-time master
opens are unaffected (a fresh clone is zero-allocated and /dev/pts/N
nodes only exist after a ptmx open).

--- sys/kern/tty_pty.c.orig
+++ sys/kern/tty_pty.c
@@ -584,9 +584,19 @@ ptcopen(struct dev_open_args *ap)
 	tp = dev->si_tty;
 	lwkt_gettoken(&tp->t_token);
 	if (tp->t_oproc) {
+		pti_done(pti);
+		lwkt_reltoken(&tp->t_token);
+		lwkt_reltoken(&pti->pt_tty.t_token);
+		return (EIO);
+	}
+
+	/*
+	 * Once the previous master closed while the slave side is still
+	 * open the pty is dead: do not let an unrelated process adopt
+	 * the stale master device (session hijack).
+	 */
+	if (pti->pt_flags & PF_SOPEN) {
 		pti_done(pti);
 		lwkt_reltoken(&tp->t_token);
 		lwkt_reltoken(&pti->pt_tty.t_token);
 		return (EIO);
 	}

 	/*
 	 * If the slave side is not yet open clear any left over zombie