--- sys/kern/tty.c.orig +++ sys/kern/tty.c @@ -1262,6 +1262,10 @@ session->s_ttydp = NULL; SESS_UNLOCK(session); + if (tp->t_session == session) { + tp->t_session = NULL; + tp->t_pgrp = NULL; + } tp->t_sessioncnt--; p->p_flag &= ~P_CONTROLT; PROC_UNLOCK(p); --- tests/sys/kern/tty/Makefile.orig +++ tests/sys/kern/tty/Makefile @@ -5,6 +5,7 @@ PLAIN_TESTS_PORCH+= test_canon_fullbuf PLAIN_TESTS_PORCH+= test_ncanon PLAIN_TESTS_PORCH+= test_recanon +PLAIN_TESTS_C+= tiocnotty ATF_TESTS_C+= test_sti PROGS+= fionread --- /dev/null +++ tests/sys/kern/tty/tiocnotty.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2026 Mark Johnston + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +/* + * A regression test that exercises a bug where TIOCNOTTY would leave some + * dangling pointers behind in the controlling terminal structure. + */ + +#include +#include + +#include +#include +#include +#include +#include + +int +main(void) +{ + int master, slave, status; + pid_t child; + + master = posix_openpt(O_RDWR | O_NOCTTY); + if (master < 0) + err(1, "posix_openpt"); + if (grantpt(master) < 0) + err(1, "grantpt"); + if (unlockpt(master) < 0) + err(1, "unlockpt"); + + child = fork(); + if (child < 0) + err(1, "fork"); + if (child == 0) { + if (setsid() < 0) + err(1, "setsid"); + slave = open(ptsname(master), O_RDWR | O_NOCTTY); + if (slave < 0) + err(2, "open"); + if (ioctl(slave, TIOCSCTTY, 0) < 0) + err(3, "ioctl(TIOCSCTTY)"); + /* Detach ourselves from the controlling terminal. */ + if (ioctl(slave, TIOCNOTTY, 0) < 0) + err(4, "ioctl(TIOCNOTTY)"); + _exit(0); + } + + if (waitpid(child, &status, 0) < 0) + err(1, "waitpid"); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + errx(1, "child exited with status %d", WEXITSTATUS(status)); + + child = fork(); + if (child < 0) + err(1, "fork"); + if (child == 0) { + struct winsize winsz; + + if (setsid() < 0) + err(1, "setsid"); + slave = open(ptsname(master), O_RDWR | O_NOCTTY); + if (slave < 0) + err(2, "open"); + /* Dereferences dangling t_pgrp pointer in the terminal. */ + memset(&winsz, 0xff, sizeof(winsz)); + if (ioctl(slave, TIOCSWINSZ, &winsz) < 0) + err(3, "ioctl(TIOCSWINSZ)"); + /* Dereferences dangling t_session pointer in the terminal. */ + if (ioctl(slave, TIOCSCTTY, 0) < 0) + err(4, "ioctl(TIOCSCTTY)"); + _exit(0); + } + + if (waitpid(child, &status, 0) < 0) + err(1, "waitpid"); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + errx(1, "child exited with status %d", WEXITSTATUS(status)); +}