Skip site navigation (1)Skip section navigation (2)



index | | raw e-mail

diff --git a/sys/kern/tty.c b/sys/kern/tty.c
index 47f9f25cec37..508fa10fdd62 100644
--- a/sys/kern/tty.c
+++ b/sys/kern/tty.c
@@ -1262,6 +1262,10 @@ tty_drop_ctty(struct tty *tp, struct proc *p)
 	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);
diff --git a/tests/sys/kern/tty/Makefile b/tests/sys/kern/tty/Makefile
index 8628ab79875f..d134b3337a21 100644
--- a/tests/sys/kern/tty/Makefile
+++ b/tests/sys/kern/tty/Makefile
@@ -5,6 +5,7 @@ PLAIN_TESTS_PORCH+=	test_canon
 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
diff --git a/tests/sys/kern/tty/tiocnotty.c b/tests/sys/kern/tty/tiocnotty.c
new file mode 100644
index 000000000000..2581f976b2ef
--- /dev/null
+++ b/tests/sys/kern/tty/tiocnotty.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2026 Mark Johnston <markj@FreeBSD.org>
+ *
+ * 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 <sys/ioctl.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+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));
+}


home | help