--- /dev/null
+From 0aaa81377c5a01f686bcdb8c7a6929a7bf330c68 Mon Sep 17 00:00:00 2001
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+Date: Fri, 4 Jan 2019 15:55:26 +0100
+Subject: can: gw: ensure DLC boundaries after CAN frame modification
+
+From: Oliver Hartkopp <socketcan@hartkopp.net>
+
+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 <ieatmuttonchuan@gmail.com>
+Reported-by: Marcus Meissner <meissner@suse.de>
+Suggested-by: Michal Kubecek <mkubecek@suse.cz>
+Tested-by: Muyu Yu <ieatmuttonchuan@gmail.com>
+Tested-by: Oliver Hartkopp <socketcan@hartkopp.net>
+Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
+Cc: linux-stable <stable@vger.kernel.org> # >= v3.2
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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)
--- /dev/null
+From d3736d82e8169768218ee0ef68718875918091a0 Mon Sep 17 00:00:00 2001
+From: Dmitry Safonov <dima@arista.com>
+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 <dima@arista.com>
+
+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 <jslaby@suse.com>
+Reported-by: Lukas F. Hartmann <lukas@mntmn.com>
+Tested-by: Lukas F. Hartmann <lukas@mntmn.com>
+Cc: stable <stable@vger.kernel.org>
+Signed-off-by: Dmitry Safonov <dima@arista.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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
+@@ -1254,7 +1254,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)
+@@ -1266,13 +1267,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++;
--- /dev/null
+From 83d817f41070c48bc3eb7ec18e43000a548fca5c Mon Sep 17 00:00:00 2001
+From: Dmitry Safonov <dima@arista.com>
+Date: Thu, 1 Nov 2018 00:24:47 +0000
+Subject: tty: Hold tty_ldisc_lock() during tty_reopen()
+
+From: Dmitry Safonov <dima@arista.com>
+
+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 <jslaby@suse.com>
+Cc: stable@vger.kernel.org # b027e2298bd5 ("tty: fix data race between tty_init_dev and flush of buf")
+Reviewed-by: Jiri Slaby <jslaby@suse.cz>
+Reported-by: syzbot+3aa9784721dfb90e984d@syzkaller.appspotmail.com
+Tested-by: Mark Rutland <mark.rutland@arm.com>
+Tested-by: Tetsuo Handa <penguin-kernel@i-love.sakura.ne.jp>
+Signed-off-by: Dmitry Safonov <dima@arista.com>
+Tested-by: Tycho Andersen <tycho@tycho.ws>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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
+@@ -1266,15 +1266,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;
+ }
+
--- /dev/null
+From 231f8fd0cca078bd4396dd7e380db813ac5736e2 Mon Sep 17 00:00:00 2001
+From: Dmitry Safonov <dima@arista.com>
+Date: Thu, 1 Nov 2018 00:24:46 +0000
+Subject: tty/ldsem: Wake up readers after timed out down_write()
+
+From: Dmitry Safonov <dima@arista.com>
+
+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 <jslaby@suse.com>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: stable@vger.kernel.org
+Reported-by: kernel test robot <rong.a.chen@intel.com>
+Signed-off-by: Dmitry Safonov <dima@arista.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/tty/tty_ldsem.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/tty/tty_ldsem.c
++++ b/drivers/tty/tty_ldsem.c
+@@ -307,6 +307,16 @@ down_write_failed(struct ld_semaphore *s
+ if (!locked)
+ ldsem_atomic_update(-LDSEM_WAIT_BIAS, sem);
+ 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);
--- /dev/null
+From cf62a1a13749db0d32b5cdd800ea91a4087319de Mon Sep 17 00:00:00 2001
+From: Dmitry Safonov <dima@arista.com>
+Date: Thu, 1 Nov 2018 00:24:49 +0000
+Subject: tty: Simplify tty->count math in tty_reopen()
+
+From: Dmitry Safonov <dima@arista.com>
+
+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 <jslaby@suse.com>
+Link: lkml.kernel.org/r/<20180829022353.23568-2-dima@arista.com>
+Suggested-by: Jiri Slaby <jslaby@suse.com>
+Reviewed-by: Jiri Slaby <jslaby@suse.cz>
+Tested-by: Mark Rutland <mark.rutland@arm.com>
+Signed-off-by: Dmitry Safonov <dima@arista.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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
+@@ -1270,16 +1270,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;
+ }
+