Re: [PATCH] tty: ldisc: fix deadlock between ldisc_sem and rtnl_mutex
[email protected] Fri, 17 Jul 2026 06:48:05 +0000
| Newsgroups | org.kernel.vger.linux-can |
|---|---|
| Message-ID | <[email protected]> |
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: New issues: - [High] Concurrent read/write/poll system calls spuriously return EOF or EIO during line discipline transitions, breaking UAPI. Pre-existing issues: - [High] The circular lock dependency between ldisc_sem and rtnl_mutex is not fully resolved, remaining on the error handling and hangup paths. -- --- Patch [1]: [PATCH] tty: ldisc: fix deadlock between ldisc_sem and rtnl_mutex --- commit bb627a1c685e7cab3f8500d0d87506f028ebe9fe Author: Yun Zhou <[email protected]> tty: ldisc: fix deadlock between ldisc_sem and rtnl_mutex This commit aims to fix a circular lock dependency between the tty ldisc_sem and the networking rtnl_mutex. It does this by modifying tty_set_ldisc() to call the line discipline open() callback outside of the ldisc_sem write lock. Closes: https://syzkaller.appspot.com/bug?extid=de610eeef174bd59a8a3 > diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c > index 27fe8236f6623..248a6995cc53a 100644 > --- a/drivers/tty/tty_ldisc.c > +++ b/drivers/tty/tty_ldisc.c > @@ -556,15 +556,28 @@ int tty_set_ldisc(struct tty_struct *tty, int disc) > /* Shutdown the old discipline. */ > tty_ldisc_close(tty, old_ldisc); > > - /* Now set up the new line discipline. */ > - tty->ldisc = new_ldisc; > + /* Clear tty->ldisc so concurrent readers back off during transition */ > + tty->ldisc = NULL; > tty_set_termios_ldisc(tty, disc); > + tty_ldisc_unlock(tty); [Severity: High] Does unlocking the semaphore while the ldisc pointer is NULL introduce a UAPI break for concurrent operations? If a concurrent process calls read(), write(), or poll() during this unlocked window, it can enter tty_ldisc_ref_wait() in drivers/tty/tty_io.c. Because the semaphore was unlocked here, tty_ldisc_ref_wait() will successfully acquire the read lock but observe tty->ldisc as NULL. This causes the reader to immediately return EOF or -EIO, potentially aborting userspace applications unexpectedly during a line discipline transition. > + > + /* > + * Open the new discipline outside ldisc_sem. The ldisc .open() > + * may acquire locks (e.g., rtnl_mutex) that would create circular > + * dependencies if taken under ldisc_sem. tty_lock is still held, > + * preventing concurrent ldisc changes and hangup. > + */ > retval = tty_ldisc_open(tty, new_ldisc); > + > + tty_ldisc_lock(tty, MAX_SCHEDULE_TIMEOUT); > + > if (retval < 0) { > /* Back to the old one or N_TTY if we can't */ > tty_ldisc_put(new_ldisc); > tty_ldisc_restore(tty, old_ldisc); [Severity: High] This is a pre-existing issue, but does this fully resolve the circular lock dependency? If tty_ldisc_open() fails above, the error path calls tty_ldisc_restore(), which eventually calls tty_ldisc_failto(). Inside tty_ldisc_failto(), tty_ldisc_open() is called while the ldisc_sem write lock is held. Similarly, during hangup processing, tty_ldisc_reinit() calls tty_ldisc_open() while holding the ldisc_sem write lock. If the restored or reinitialized discipline acquires rtnl_mutex on these paths, it appears the lock inversion and potential deadlock would still occur. > + } else { > + /* Success - install new ldisc */ > + tty->ldisc = new_ldisc; > } -- Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=1