Re: [PATCH v3] tty: ldisc: fix deadlock between ldisc_sem and rtnl_mutex
"Zhou, Yun" <[email protected]> Sun, 26 Jul 2026 11:25:41 +0800
| Newsgroups | org.kernel.vger.linux-can,dev.linux.lists.sashiko-reviews |
|---|---|
| Message-ID | <[email protected]> |
On 7/25/2026 4:47 PM, [email protected] wrote: > Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: > > New issues: > - [High] The patch replaces a lockdep splat with a silent waitqueue deadlock on the success path. > > Pre-existing issues: > - [High] Incomplete fix for circular locking between ldisc_sem and rtnl_mutex, leaving deadlocks on teardown, error, and hangup paths. > -- > > --- Patch [1]: [PATCH v3] tty: ldisc: fix deadlock between ldisc_sem and rtnl_mutex --- > commit 98cde28b47f83f4a2bf71bb1e35f53d9a7a36294 > Author: Yun Zhou <[email protected]> > > tty: ldisc: fix deadlock between ldisc_sem and rtnl_mutex > > This commit attempts to fix a circular lock dependency between ldisc_sem > and rtnl_mutex reported by syzbot. It moves the tty line discipline .open() > callback outside the ldisc_sem write lock in tty_set_ldisc(). It also adds > logic in tty_ldisc_ref_wait() to wait for the ldisc transition to complete. > > Closes: https://syzkaller.appspot.com/bug?extid=de610eeef174bd59a8a3 > >> diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c >> index 27fe8236f6623..6ec93e6b84988 100644 >> --- a/drivers/tty/tty_ldisc.c >> +++ b/drivers/tty/tty_ldisc.c >> @@ -242,6 +242,16 @@ struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) >> >> ldsem_down_read(&tty->ldisc_sem, MAX_SCHEDULE_TIMEOUT); >> ld = tty->ldisc; >> + while (!ld && !test_bit(TTY_HUPPED, &tty->flags)) { >> + ldsem_up_read(&tty->ldisc_sem); >> + >> + /* ldisc may be NULL during a discipline switch; wait and retry */ >> + wait_event(tty->read_wait, >> + READ_ONCE(tty->ldisc) != NULL || >> + test_bit(TTY_HUPPED, &tty->flags)); > > [Severity: High] > Does this wait_event() create a silent waitqueue deadlock that replaces the > lockdep splat? > > If thread A switches to a network ldisc like slcan, it will set tty->ldisc > to NULL in tty_set_ldisc() and drop ldisc_sem, but then block waiting for > rtnl_mutex in the .open() callback. > > Concurrently, if thread B already holds rtnl_mutex and calls tty_poll(), > it enters tty_ldisc_ref_wait() here. Thread B will observe tty->ldisc as NULL > and block uninterruptibly in this wait_event(), waiting for thread A to > re-assign tty->ldisc. > No, this scenario does not exist. tty_poll() is only called from userspace poll/epoll/select paths, which never hold rtnl_mutex. And All callers of tty_ldisc_ref_wait() are userspace entry points: tty_read/tty_write/tty_poll/tty_ioctl/tty_open/tty_show_fdinfo/paste_selection/tty_perform_flush. None of these are reachable from any code path that holds rtnl_mutex. > Since thread A is blocked waiting for thread B to release rtnl_mutex, > will both threads hang forever without a lockdep warning? >