The first two fixes are worth to have in stables as we've hit it on v4.9 stable.
And for linux-next - adding lockdep asserts for line discipline changing code, verifying that write ldisc sem will be held forthwith.
Changes since v1: - Added tested-by/reported-by tags - Dropped 3/4 (locking tty pair for lockdep sake), Because of that - not adding lockdep_assert_held() in tty_ldisc_open() - Added 4/4 cleanup to inc tty->count only on success of tty_ldisc_reinit() - lock ldisc without (5*HZ) timeout in tty_reopen()
v1 link: lkml.kernel.org/r/20180829022353.23568-1-dima@arista.com
Huuge cc list: Cc: Daniel Axtens dja@axtens.net Cc: Dmitry Vyukov dvyukov@google.com Cc: Michael Neuling mikey@neuling.org Cc: Mikulas Patocka mpatocka@redhat.com Cc: Nathan March nathan@gt.net Cc: Pasi Kärkkäinen pasik@iki.fi Cc: Peter Hurley peter@hurleysoftware.com Cc: Sergey Senozhatsky sergey.senozhatsky.work@gmail.com Cc: Tan Xiaojun tanxiaojun@huawei.com Cc: Tetsuo Handa penguin-kernel@I-love.SAKURA.ne.jp (please, ignore if I Cc'ed you mistakenly)
Dmitry Safonov (4): tty: Drop tty->count on tty_reopen() failure tty: Hold tty_ldisc_lock() during tty_reopen() tty/lockdep: Add ldisc_sem asserts tty: Simplify tty->count math in tty_reopen()
drivers/tty/tty_io.c | 12 ++++++++---- drivers/tty/tty_ldisc.c | 5 +++++ 2 files changed, 13 insertions(+), 4 deletions(-)
In case of tty_ldisc_reinit() failure, tty->count should be decremented back, otherwise we will never release_tty(). Tetsuo reported that it fixes noisy warnings on tty release like: pts pts4033: tty_release: tty->count(10529) != (#fd's(7) + #kopen's(0))
Cc: Greg Kroah-Hartman gregkh@linuxfoundation.org Cc: Jiri Slaby jslaby@suse.com Cc: stable@vger.kernel.org # v4.6+ Fixes: commit 892d1fa7eaae ("tty: Destroy ldisc instance on hangup") Tested-by: Jiri Slaby jslaby@suse.com Tested-by: Tetsuo Handa penguin-kernel@i-love.sakura.ne.jp Signed-off-by: Dmitry Safonov dima@arista.com --- drivers/tty/tty_io.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 32bc3e3fe4d3..5e5da9acaf0a 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1255,6 +1255,7 @@ static void tty_driver_remove_tty(struct tty_driver *driver, struct tty_struct * static int tty_reopen(struct tty_struct *tty) { struct tty_driver *driver = tty->driver; + int retval;
if (driver->type == TTY_DRIVER_TYPE_PTY && driver->subtype == PTY_TYPE_MASTER) @@ -1268,10 +1269,14 @@ static int tty_reopen(struct tty_struct *tty)
tty->count++;
- if (!tty->ldisc) - return tty_ldisc_reinit(tty, tty->termios.c_line); + if (tty->ldisc) + return 0;
- return 0; + retval = tty_ldisc_reinit(tty, tty->termios.c_line); + if (retval) + tty->count--; + + return retval; }
/**
On 09/03/2018, 06:52 PM, Dmitry Safonov wrote:
In case of tty_ldisc_reinit() failure, tty->count should be decremented back, otherwise we will never release_tty(). Tetsuo reported that it fixes noisy warnings on tty release like: pts pts4033: tty_release: tty->count(10529) != (#fd's(7) + #kopen's(0))
Cc: Greg Kroah-Hartman gregkh@linuxfoundation.org Cc: Jiri Slaby jslaby@suse.com Cc: stable@vger.kernel.org # v4.6+ Fixes: commit 892d1fa7eaae ("tty: Destroy ldisc instance on hangup") Tested-by: Jiri Slaby jslaby@suse.com
Reviewed-by: Jiri Slaby jslaby@suse.cz
Tested-by: Tetsuo Handa penguin-kernel@i-love.sakura.ne.jp Signed-off-by: Dmitry Safonov dima@arista.com
thanks,
tty_ldisc_reinit() doesn't race with neither tty_ldisc_hangup() nor set_ldisc() nor tty_ldisc_release() as they use tty lock. But it races with anyone who expects line discipline to be the same after hoding read semaphore in tty_ldisc_ref().
We've seen the following crash on v4.9.108 stable:
BUG: unable to handle kernel paging request at 0000000000002260 IP: [..] n_tty_receive_buf_common+0x5f/0x86d Workqueue: events_unbound flush_to_ldisc Call Trace: [..] n_tty_receive_buf2 [..] tty_ldisc_receive_buf [..] flush_to_ldisc [..] process_one_work [..] worker_thread [..] kthread [..] ret_from_fork
tty_ldisc_reinit() should be called with ldisc_sem hold for writing, which will protect any reader against line discipline changes.
Cc: Greg Kroah-Hartman gregkh@linuxfoundation.org Cc: Jiri Slaby jslaby@suse.com Cc: stable@vger.kernel.org # depends on commit b027e2298bd5 ("tty: fix data race between tty_init_dev and flush of buf") Reported-by: syzbot+3aa9784721dfb90e984d@syzkaller.appspotmail.com Tested-by: Tetsuo Handa penguin-kernel@i-love.sakura.ne.jp Signed-off-by: Dmitry Safonov dima@arista.com --- drivers/tty/tty_io.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 5e5da9acaf0a..a947719b4626 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1255,7 +1255,7 @@ static void tty_driver_remove_tty(struct tty_driver *driver, struct tty_struct * static int tty_reopen(struct tty_struct *tty) { struct tty_driver *driver = tty->driver; - int retval; + int retval = 0;
if (driver->type == TTY_DRIVER_TYPE_PTY && driver->subtype == PTY_TYPE_MASTER) @@ -1267,15 +1267,18 @@ static int tty_reopen(struct tty_struct *tty) if (test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_ADMIN)) return -EBUSY;
- tty->count++; + tty_ldisc_lock(tty, MAX_SCHEDULE_TIMEOUT);
+ tty->count++; if (tty->ldisc) - return 0; + goto out_unlock;
retval = tty_ldisc_reinit(tty, tty->termios.c_line); if (retval) tty->count--;
+out_unlock: + tty_ldisc_unlock(tty); return retval; }
On (09/03/18 17:52), Dmitry Safonov wrote:
We've seen the following crash on v4.9.108 stable:
BUG: unable to handle kernel paging request at 0000000000002260 IP: [..] n_tty_receive_buf_common+0x5f/0x86d Workqueue: events_unbound flush_to_ldisc Call Trace: [..] n_tty_receive_buf2 [..] tty_ldisc_receive_buf [..] flush_to_ldisc [..] process_one_work [..] worker_thread [..] kthread [..] ret_from_fork
tty_ldisc_reinit() should be called with ldisc_sem hold for writing, which will protect any reader against line discipline changes.
Cc: Greg Kroah-Hartman gregkh@linuxfoundation.org Cc: Jiri Slaby jslaby@suse.com Cc: stable@vger.kernel.org # depends on commit b027e2298bd5 ("tty: fix data race between tty_init_dev and flush of buf")
I believe there's a "Fixes" tag for that
Fixes: b027e2298bd5 ("tty: fix data race between tty_init_dev and flush of buf") Cc: stable@vger.kernel.org
-ss
On 09/04/2018, 03:51 AM, Sergey Senozhatsky wrote:
On (09/03/18 17:52), Dmitry Safonov wrote:
We've seen the following crash on v4.9.108 stable:
BUG: unable to handle kernel paging request at 0000000000002260 IP: [..] n_tty_receive_buf_common+0x5f/0x86d Workqueue: events_unbound flush_to_ldisc Call Trace: [..] n_tty_receive_buf2 [..] tty_ldisc_receive_buf [..] flush_to_ldisc [..] process_one_work [..] worker_thread [..] kthread [..] ret_from_fork
tty_ldisc_reinit() should be called with ldisc_sem hold for writing, which will protect any reader against line discipline changes.
Cc: Greg Kroah-Hartman gregkh@linuxfoundation.org Cc: Jiri Slaby jslaby@suse.com Cc: stable@vger.kernel.org # depends on commit b027e2298bd5 ("tty: fix data race between tty_init_dev and flush of buf")
I believe there's a "Fixes" tag for that
Fixes: b027e2298bd5 ("tty: fix data race between tty_init_dev and flush of buf") Cc: stable@vger.kernel.org
Nope, it would be translated as: Backport-first: b027e2298bd5 :)
thanks,
On (09/04/18 08:30), Jiri Slaby wrote:
Cc: stable@vger.kernel.org # depends on commit b027e2298bd5 ("tty: fix data race between tty_init_dev and flush of buf")
I believe there's a "Fixes" tag for that
Fixes: b027e2298bd5 ("tty: fix data race between tty_init_dev and flush of buf") Cc: stable@vger.kernel.org
Nope, it would be translated as: Backport-first: b027e2298bd5 :)
:) Ah, OK. So this "Backport-first:" is for pre-4.9 longterm kernels. As far as I can see linux-4.9.y picked up b027e2298bd5:
commit 55eaecffe3d663d02084023b9fc06d5f39b97389 Author: Gaurav Kohli Date: Tue Jan 23 13:16:34 2018 +0530
tty: fix data race between tty_init_dev and flush of buf
commit b027e2298bd588d6fa36ed2eda97447fb3eac078 upstream.
-ss
On 09/03/2018, 06:52 PM, Dmitry Safonov wrote:
tty_ldisc_reinit() doesn't race with neither tty_ldisc_hangup() nor set_ldisc() nor tty_ldisc_release() as they use tty lock. But it races with anyone who expects line discipline to be the same after hoding read semaphore in tty_ldisc_ref().
We've seen the following crash on v4.9.108 stable:
BUG: unable to handle kernel paging request at 0000000000002260 IP: [..] n_tty_receive_buf_common+0x5f/0x86d Workqueue: events_unbound flush_to_ldisc Call Trace: [..] n_tty_receive_buf2 [..] tty_ldisc_receive_buf [..] flush_to_ldisc [..] process_one_work [..] worker_thread [..] kthread [..] ret_from_fork
tty_ldisc_reinit() should be called with ldisc_sem hold for writing, which will protect any reader against line discipline changes.
Cc: Greg Kroah-Hartman gregkh@linuxfoundation.org Cc: Jiri Slaby jslaby@suse.com
Reviewed-by: Jiri Slaby jslaby@suse.cz
Cc: stable@vger.kernel.org # depends on commit b027e2298bd5 ("tty: fix data race between tty_init_dev and flush of buf") Reported-by: syzbot+3aa9784721dfb90e984d@syzkaller.appspotmail.com Tested-by: Tetsuo Handa penguin-kernel@i-love.sakura.ne.jp Signed-off-by: Dmitry Safonov dima@arista.com
thanks,
linux-stable-mirror@lists.linaro.org