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
