aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Wing <rew@FreeBSD.org>2023-12-19 00:40:46 +0000
committerRobert Wing <rew@FreeBSD.org>2023-12-19 00:40:46 +0000
commitacd5638e268a6706f6b7ad84947a8425e8d51ef7 (patch)
tree9a841980a2980a7accda05d62f7ea0eee59ac79c
parentd9b7301bb791faab48b6c7733c34078427b9a374 (diff)
downloadsrc-acd5638e268a6706f6b7ad84947a8425e8d51ef7.tar.gz
src-acd5638e268a6706f6b7ad84947a8425e8d51ef7.zip
tty: delete knotes when TTY is revoked
Do not clear knotes from the TTY until it gets dealloc'ed, unless the TTY is being revoked, in that case delete the knotes when closed is called on the TTY. When knotes are cleared from a knlist, those knotes become detached from the knlist. And when an event is triggered on a detached knote there isn't an associated knlist and therefore no lock will be taken when the event is triggered. This becomes a problem when a detached knote is triggered on a TTY since the mutex for a TTY is also used as the lock for its knlists. This scenario ends up calling the TTY event handlers without the TTY lock being held and tripping on asserts in the event handlers. PR: 272151 Reviewed by: kib, markj Differential Revision: https://reviews.freebsd.org/D41605
-rw-r--r--sys/kern/tty.c12
1 files changed, 7 insertions, 5 deletions
diff --git a/sys/kern/tty.c b/sys/kern/tty.c
index e051c66ab0c9..61a6beafa2c0 100644
--- a/sys/kern/tty.c
+++ b/sys/kern/tty.c
@@ -253,9 +253,6 @@ ttydev_leave(struct tty *tp)
ttyoutq_free(&tp->t_outq);
tp->t_outlow = 0;
- knlist_clear(&tp->t_inpoll.si_note, 1);
- knlist_clear(&tp->t_outpoll.si_note, 1);
-
if (!tty_gone(tp))
ttydevsw_close(tp);
@@ -369,7 +366,7 @@ done: tp->t_flags &= ~TF_OPENCLOSE;
static int
ttydev_close(struct cdev *dev, int fflag, int devtype __unused,
- struct thread *td __unused)
+ struct thread *td)
{
struct tty *tp = dev->si_drv1;
@@ -392,8 +389,11 @@ ttydev_close(struct cdev *dev, int fflag, int devtype __unused,
}
/* If revoking, flush output now to avoid draining it later. */
- if (fflag & FREVOKE)
+ if ((fflag & FREVOKE) != 0) {
tty_flush(tp, FWRITE);
+ knlist_delete(&tp->t_inpoll.si_note, td, 1);
+ knlist_delete(&tp->t_outpoll.si_note, td, 1);
+ }
tp->t_flags &= ~TF_EXCLUDE;
@@ -1120,6 +1120,8 @@ tty_dealloc(void *arg)
ttyoutq_free(&tp->t_outq);
seldrain(&tp->t_inpoll);
seldrain(&tp->t_outpoll);
+ knlist_clear(&tp->t_inpoll.si_note, 0);
+ knlist_clear(&tp->t_outpoll.si_note, 0);
knlist_destroy(&tp->t_inpoll.si_note);
knlist_destroy(&tp->t_outpoll.si_note);