I've discovered that there's a use-after-free bug that is triggered by multiply-opened tty(4) devices where one process uses FIOSETOWN and then exits. It occurs, for example, when first ntpd(8) opens a GPS_NMEA(0) refclock (/dev/gps0 -> /dev/ttyU0), and subsequently gpsd(8) opens the same tty. ntpd(8) does a FIOSETOWN ioctl on this tty soon after startup that sets tp->t_pgrp. (gpsd does not seem to explicitly FIOSETOWN or TIOCSCTTY.) Subsequently when you stop the ntpd process (with gpsd still running) tp->t_pgrp points to freed chunk of memory. Soon, ttysigintr() tries to send SIGIO to this process group, and things explode (the symptom may vary, as the pgrp memory could have been re-used, or kASan may have intercepted it, or you just segfault in the kernel).
I see that the TIOCSCTTY case in ttioctl() calls proc_sesshold(), but the FIOSETOWN or TIOCSPGRP cases, which are vaguely similar, do not. The attached patch prevents the UAF bug I observed, but I'm not confident it's correct; and I'm even less confident for the TIOCSPGRP case which I was unable to test. I am mostly concerned it may result in a memory leak, or at worst a deadlock, but perhaps that's better than crashing the kernel. Jonathan Kollasch
Index: src/sys/kern/tty.c =================================================================== RCS file: /cvsroot/src/sys/kern/tty.c,v retrieving revision 1.312 diff -d -u -a -p -r1.312 tty.c --- src/sys/kern/tty.c 7 Dec 2023 09:00:32 -0000 1.312 +++ src/sys/kern/tty.c 24 Apr 2024 01:58:14 -0000 @@ -1441,6 +1441,7 @@ unlock_constty: mutex_exit(&constty_lock return (EPERM); } mutex_spin_enter(&tty_lock); + proc_sesshold(pgrp->pg_session); tp->t_pgrp = pgrp; mutex_spin_exit(&tty_lock); mutex_exit(&proc_lock); @@ -1464,6 +1465,7 @@ unlock_constty: mutex_exit(&constty_lock return (EPERM); } mutex_spin_enter(&tty_lock); + proc_sesshold(pgrp->pg_session); tp->t_pgrp = pgrp; mutex_spin_exit(&tty_lock); mutex_exit(&proc_lock);