From 8f8b81b53ba8e006be2617d5666c5264bba4be57 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 17 Jan 2019 15:00:34 +0100 Subject: [PATCH] 4.19-stable patches added patches: can-gw-ensure-dlc-boundaries-after-can-frame-modification.patch tty-don-t-hold-ldisc-lock-in-tty_reopen-if-ldisc-present.patch tty-hold-tty_ldisc_lock-during-tty_reopen.patch tty-ldsem-wake-up-readers-after-timed-out-down_write.patch tty-simplify-tty-count-math-in-tty_reopen.patch --- ...ndaries-after-can-frame-modification.patch | 91 +++++++++++++++++++ ...-lock-in-tty_reopen-if-ldisc-present.patch | 69 ++++++++++++++ ...old-tty_ldisc_lock-during-tty_reopen.patch | 71 +++++++++++++++ ...p-readers-after-timed-out-down_write.patch | 58 ++++++++++++ ...implify-tty-count-math-in-tty_reopen.patch | 48 ++++++++++ 5 files changed, 337 insertions(+) create mode 100644 queue-4.19/can-gw-ensure-dlc-boundaries-after-can-frame-modification.patch create mode 100644 queue-4.19/tty-don-t-hold-ldisc-lock-in-tty_reopen-if-ldisc-present.patch create mode 100644 queue-4.19/tty-hold-tty_ldisc_lock-during-tty_reopen.patch create mode 100644 queue-4.19/tty-ldsem-wake-up-readers-after-timed-out-down_write.patch create mode 100644 queue-4.19/tty-simplify-tty-count-math-in-tty_reopen.patch diff --git a/queue-4.19/can-gw-ensure-dlc-boundaries-after-can-frame-modification.patch b/queue-4.19/can-gw-ensure-dlc-boundaries-after-can-frame-modification.patch new file mode 100644 index 00000000000..12026e304cd --- /dev/null +++ b/queue-4.19/can-gw-ensure-dlc-boundaries-after-can-frame-modification.patch @@ -0,0 +1,91 @@ +From 0aaa81377c5a01f686bcdb8c7a6929a7bf330c68 Mon Sep 17 00:00:00 2001 +From: Oliver Hartkopp +Date: Fri, 4 Jan 2019 15:55:26 +0100 +Subject: can: gw: ensure DLC boundaries after CAN frame modification + +From: Oliver Hartkopp + +commit 0aaa81377c5a01f686bcdb8c7a6929a7bf330c68 upstream. + +Muyu Yu provided a POC where user root with CAP_NET_ADMIN can create a CAN +frame modification rule that makes the data length code a higher value than +the available CAN frame data size. In combination with a configured checksum +calculation where the result is stored relatively to the end of the data +(e.g. cgw_csum_xor_rel) the tail of the skb (e.g. frag_list pointer in +skb_shared_info) can be rewritten which finally can cause a system crash. + +Michael Kubecek suggested to drop frames that have a DLC exceeding the +available space after the modification process and provided a patch that can +handle CAN FD frames too. Within this patch we also limit the length for the +checksum calculations to the maximum of Classic CAN data length (8). + +CAN frames that are dropped by these additional checks are counted with the +CGW_DELETED counter which indicates misconfigurations in can-gw rules. + +This fixes CVE-2019-3701. + +Reported-by: Muyu Yu +Reported-by: Marcus Meissner +Suggested-by: Michal Kubecek +Tested-by: Muyu Yu +Tested-by: Oliver Hartkopp +Signed-off-by: Oliver Hartkopp +Cc: linux-stable # >= v3.2 +Signed-off-by: Marc Kleine-Budde +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + net/can/gw.c | 30 +++++++++++++++++++++++++++--- + 1 file changed, 27 insertions(+), 3 deletions(-) + +--- a/net/can/gw.c ++++ b/net/can/gw.c +@@ -416,13 +416,29 @@ static void can_can_gw_rcv(struct sk_buf + while (modidx < MAX_MODFUNCTIONS && gwj->mod.modfunc[modidx]) + (*gwj->mod.modfunc[modidx++])(cf, &gwj->mod); + +- /* check for checksum updates when the CAN frame has been modified */ ++ /* Has the CAN frame been modified? */ + if (modidx) { +- if (gwj->mod.csumfunc.crc8) ++ /* get available space for the processed CAN frame type */ ++ int max_len = nskb->len - offsetof(struct can_frame, data); ++ ++ /* dlc may have changed, make sure it fits to the CAN frame */ ++ if (cf->can_dlc > max_len) ++ goto out_delete; ++ ++ /* check for checksum updates in classic CAN length only */ ++ if (gwj->mod.csumfunc.crc8) { ++ if (cf->can_dlc > 8) ++ goto out_delete; ++ + (*gwj->mod.csumfunc.crc8)(cf, &gwj->mod.csum.crc8); ++ } ++ ++ if (gwj->mod.csumfunc.xor) { ++ if (cf->can_dlc > 8) ++ goto out_delete; + +- if (gwj->mod.csumfunc.xor) + (*gwj->mod.csumfunc.xor)(cf, &gwj->mod.csum.xor); ++ } + } + + /* clear the skb timestamp if not configured the other way */ +@@ -434,6 +450,14 @@ static void can_can_gw_rcv(struct sk_buf + gwj->dropped_frames++; + else + gwj->handled_frames++; ++ ++ return; ++ ++ out_delete: ++ /* delete frame due to misconfiguration */ ++ gwj->deleted_frames++; ++ kfree_skb(nskb); ++ return; + } + + static inline int cgw_register_filter(struct net *net, struct cgw_job *gwj) diff --git a/queue-4.19/tty-don-t-hold-ldisc-lock-in-tty_reopen-if-ldisc-present.patch b/queue-4.19/tty-don-t-hold-ldisc-lock-in-tty_reopen-if-ldisc-present.patch new file mode 100644 index 00000000000..3f6fdb77362 --- /dev/null +++ b/queue-4.19/tty-don-t-hold-ldisc-lock-in-tty_reopen-if-ldisc-present.patch @@ -0,0 +1,69 @@ +From d3736d82e8169768218ee0ef68718875918091a0 Mon Sep 17 00:00:00 2001 +From: Dmitry Safonov +Date: Wed, 9 Jan 2019 01:17:40 +0000 +Subject: tty: Don't hold ldisc lock in tty_reopen() if ldisc present + +From: Dmitry Safonov + +commit d3736d82e8169768218ee0ef68718875918091a0 upstream. + +Try to get reference for ldisc during tty_reopen(). +If ldisc present, we don't need to do tty_ldisc_reinit() and lock the +write side for line discipline semaphore. +Effectively, it optimizes fast-path for tty_reopen(), but more +importantly it won't interrupt ongoing IO on the tty as no ldisc change +is needed. +Fixes user-visible issue when tty_reopen() interrupted login process for +user with a long password, observed and reported by Lukas. + +Fixes: c96cf923a98d ("tty: Don't block on IO when ldisc change is pending") +Fixes: 83d817f41070 ("tty: Hold tty_ldisc_lock() during tty_reopen()") +Cc: Jiri Slaby +Reported-by: Lukas F. Hartmann +Tested-by: Lukas F. Hartmann +Cc: stable +Signed-off-by: Dmitry Safonov +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/tty/tty_io.c | 22 ++++++++++++++-------- + 1 file changed, 14 insertions(+), 8 deletions(-) + +--- a/drivers/tty/tty_io.c ++++ b/drivers/tty/tty_io.c +@@ -1255,7 +1255,8 @@ static void tty_driver_remove_tty(struct + static int tty_reopen(struct tty_struct *tty) + { + struct tty_driver *driver = tty->driver; +- int retval; ++ struct tty_ldisc *ld; ++ int retval = 0; + + if (driver->type == TTY_DRIVER_TYPE_PTY && + driver->subtype == PTY_TYPE_MASTER) +@@ -1267,13 +1268,18 @@ static int tty_reopen(struct tty_struct + if (test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_ADMIN)) + return -EBUSY; + +- retval = tty_ldisc_lock(tty, 5 * HZ); +- if (retval) +- return retval; +- +- if (!tty->ldisc) +- retval = tty_ldisc_reinit(tty, tty->termios.c_line); +- tty_ldisc_unlock(tty); ++ ld = tty_ldisc_ref_wait(tty); ++ if (ld) { ++ tty_ldisc_deref(ld); ++ } else { ++ retval = tty_ldisc_lock(tty, 5 * HZ); ++ if (retval) ++ return retval; ++ ++ if (!tty->ldisc) ++ retval = tty_ldisc_reinit(tty, tty->termios.c_line); ++ tty_ldisc_unlock(tty); ++ } + + if (retval == 0) + tty->count++; diff --git a/queue-4.19/tty-hold-tty_ldisc_lock-during-tty_reopen.patch b/queue-4.19/tty-hold-tty_ldisc_lock-during-tty_reopen.patch new file mode 100644 index 00000000000..889550667b1 --- /dev/null +++ b/queue-4.19/tty-hold-tty_ldisc_lock-during-tty_reopen.patch @@ -0,0 +1,71 @@ +From 83d817f41070c48bc3eb7ec18e43000a548fca5c Mon Sep 17 00:00:00 2001 +From: Dmitry Safonov +Date: Thu, 1 Nov 2018 00:24:47 +0000 +Subject: tty: Hold tty_ldisc_lock() during tty_reopen() + +From: Dmitry Safonov + +commit 83d817f41070c48bc3eb7ec18e43000a548fca5c upstream. + +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: Jiri Slaby +Cc: stable@vger.kernel.org # b027e2298bd5 ("tty: fix data race between tty_init_dev and flush of buf") +Reviewed-by: Jiri Slaby +Reported-by: syzbot+3aa9784721dfb90e984d@syzkaller.appspotmail.com +Tested-by: Mark Rutland +Tested-by: Tetsuo Handa +Signed-off-by: Dmitry Safonov +Tested-by: Tycho Andersen +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/tty/tty_io.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +--- a/drivers/tty/tty_io.c ++++ b/drivers/tty/tty_io.c +@@ -1267,15 +1267,20 @@ static int tty_reopen(struct tty_struct + if (test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_ADMIN)) + return -EBUSY; + +- tty->count++; ++ retval = tty_ldisc_lock(tty, 5 * HZ); ++ if (retval) ++ return retval; + ++ 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; + } + diff --git a/queue-4.19/tty-ldsem-wake-up-readers-after-timed-out-down_write.patch b/queue-4.19/tty-ldsem-wake-up-readers-after-timed-out-down_write.patch new file mode 100644 index 00000000000..7510e470bae --- /dev/null +++ b/queue-4.19/tty-ldsem-wake-up-readers-after-timed-out-down_write.patch @@ -0,0 +1,58 @@ +From 231f8fd0cca078bd4396dd7e380db813ac5736e2 Mon Sep 17 00:00:00 2001 +From: Dmitry Safonov +Date: Thu, 1 Nov 2018 00:24:46 +0000 +Subject: tty/ldsem: Wake up readers after timed out down_write() + +From: Dmitry Safonov + +commit 231f8fd0cca078bd4396dd7e380db813ac5736e2 upstream. + +ldsem_down_read() will sleep if there is pending writer in the queue. +If the writer times out, readers in the queue should be woken up, +otherwise they may miss a chance to acquire the semaphore until the last +active reader will do ldsem_up_read(). + +There was a couple of reports where there was one active reader and +other readers soft locked up: + Showing all locks held in the system: + 2 locks held by khungtaskd/17: + #0: (rcu_read_lock){......}, at: watchdog+0x124/0x6d1 + #1: (tasklist_lock){.+.+..}, at: debug_show_all_locks+0x72/0x2d3 + 2 locks held by askfirst/123: + #0: (&tty->ldisc_sem){.+.+.+}, at: ldsem_down_read+0x46/0x58 + #1: (&ldata->atomic_read_lock){+.+...}, at: n_tty_read+0x115/0xbe4 + +Prevent readers wait for active readers to release ldisc semaphore. + +Link: lkml.kernel.org/r/20171121132855.ajdv4k6swzhvktl6@wfg-t540p.sh.intel.com +Link: lkml.kernel.org/r/20180907045041.GF1110@shao2-debian +Cc: Jiri Slaby +Cc: Peter Zijlstra +Cc: stable@vger.kernel.org +Reported-by: kernel test robot +Signed-off-by: Dmitry Safonov +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/tty/tty_ldsem.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/tty/tty_ldsem.c ++++ b/drivers/tty/tty_ldsem.c +@@ -293,6 +293,16 @@ down_write_failed(struct ld_semaphore *s + if (!locked) + atomic_long_add_return(-LDSEM_WAIT_BIAS, &sem->count); + list_del(&waiter.list); ++ ++ /* ++ * In case of timeout, wake up every reader who gave the right of way ++ * to writer. Prevent separation readers into two groups: ++ * one that helds semaphore and another that sleeps. ++ * (in case of no contention with a writer) ++ */ ++ if (!locked && list_empty(&sem->write_wait)) ++ __ldsem_wake_readers(sem); ++ + raw_spin_unlock_irq(&sem->wait_lock); + + __set_current_state(TASK_RUNNING); diff --git a/queue-4.19/tty-simplify-tty-count-math-in-tty_reopen.patch b/queue-4.19/tty-simplify-tty-count-math-in-tty_reopen.patch new file mode 100644 index 00000000000..4481623d935 --- /dev/null +++ b/queue-4.19/tty-simplify-tty-count-math-in-tty_reopen.patch @@ -0,0 +1,48 @@ +From cf62a1a13749db0d32b5cdd800ea91a4087319de Mon Sep 17 00:00:00 2001 +From: Dmitry Safonov +Date: Thu, 1 Nov 2018 00:24:49 +0000 +Subject: tty: Simplify tty->count math in tty_reopen() + +From: Dmitry Safonov + +commit cf62a1a13749db0d32b5cdd800ea91a4087319de upstream. + +As notted by Jiri, tty_ldisc_reinit() shouldn't rely on tty counter. +Simplify math by increasing the counter after reinit success. + +Cc: Jiri Slaby +Link: lkml.kernel.org/r/<20180829022353.23568-2-dima@arista.com> +Suggested-by: Jiri Slaby +Reviewed-by: Jiri Slaby +Tested-by: Mark Rutland +Signed-off-by: Dmitry Safonov +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/tty/tty_io.c | 13 +++++-------- + 1 file changed, 5 insertions(+), 8 deletions(-) + +--- a/drivers/tty/tty_io.c ++++ b/drivers/tty/tty_io.c +@@ -1271,16 +1271,13 @@ static int tty_reopen(struct tty_struct + if (retval) + return retval; + +- tty->count++; +- if (tty->ldisc) +- goto out_unlock; ++ if (!tty->ldisc) ++ retval = tty_ldisc_reinit(tty, tty->termios.c_line); ++ tty_ldisc_unlock(tty); + +- retval = tty_ldisc_reinit(tty, tty->termios.c_line); +- if (retval) +- tty->count--; ++ if (retval == 0) ++ tty->count++; + +-out_unlock: +- tty_ldisc_unlock(tty); + return retval; + } + -- 2.47.2