From 110b89282f658593a5a4a96a300d5aa51f1bf88f Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Thu, 1 Nov 2018 00:24:51 +0000 Subject: tty/ldsem: Add lockdep asserts for ldisc_sem Make sure under CONFIG_LOCKDEP that each change to line discipline is done with held write semaphor. Otherwise potential reader will have a good time dereferencing incomplete/uninitialized ldisc. An exception here is tty_ldisc_open(), as it's called without ldisc_sem locked by tty_init_dev() => tty_ldisc_setup() for the tty->link. It seem valid as tty_init_dev() will call tty_driver_install_tty() which will find ops->install(). Install will establish tty->link in pty_common_install(), just after allocation of slave tty with alloc_tty_struct(). So, no one should have a reference to slave pty yet. Cc: Jiri Slaby Cc: Peter Zijlstra Signed-off-by: Dmitry Safonov Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_ldisc.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 9434d20cf3ca..45eda69b150c 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -478,6 +478,7 @@ static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld) static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld) { + lockdep_assert_held_exclusive(&tty->ldisc_sem); WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags)); clear_bit(TTY_LDISC_OPEN, &tty->flags); if (ld->ops->close) @@ -499,6 +500,7 @@ static int tty_ldisc_failto(struct tty_struct *tty, int ld) struct tty_ldisc *disc = tty_ldisc_get(tty, ld); int r; + lockdep_assert_held_exclusive(&tty->ldisc_sem); if (IS_ERR(disc)) return PTR_ERR(disc); tty->ldisc = disc; @@ -622,6 +624,7 @@ EXPORT_SYMBOL_GPL(tty_set_ldisc); */ static void tty_ldisc_kill(struct tty_struct *tty) { + lockdep_assert_held_exclusive(&tty->ldisc_sem); if (!tty->ldisc) return; /* @@ -669,6 +672,7 @@ int tty_ldisc_reinit(struct tty_struct *tty, int disc) struct tty_ldisc *ld; int retval; + lockdep_assert_held_exclusive(&tty->ldisc_sem); ld = tty_ldisc_get(tty, disc); if (IS_ERR(ld)) { BUG_ON(disc == N_TTY); @@ -767,6 +771,10 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty) return retval; if (o_tty) { + /* + * Called without o_tty->ldisc_sem held, as o_tty has been + * just allocated and no one has a reference to it. + */ retval = tty_ldisc_open(o_tty, o_tty->ldisc); if (retval) { tty_ldisc_close(tty, tty->ldisc); @@ -832,6 +840,7 @@ int tty_ldisc_init(struct tty_struct *tty) */ void tty_ldisc_deinit(struct tty_struct *tty) { + /* no ldisc_sem, tty is being destroyed */ if (tty->ldisc) tty_ldisc_put(tty->ldisc); tty->ldisc = NULL; -- cgit v1.2.3