]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 17 Jan 2019 14:00:16 +0000 (15:00 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 17 Jan 2019 14:00:16 +0000 (15:00 +0100)
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

queue-4.14/can-gw-ensure-dlc-boundaries-after-can-frame-modification.patch [new file with mode: 0644]
queue-4.14/tty-don-t-hold-ldisc-lock-in-tty_reopen-if-ldisc-present.patch [new file with mode: 0644]
queue-4.14/tty-hold-tty_ldisc_lock-during-tty_reopen.patch [new file with mode: 0644]
queue-4.14/tty-ldsem-wake-up-readers-after-timed-out-down_write.patch [new file with mode: 0644]
queue-4.14/tty-simplify-tty-count-math-in-tty_reopen.patch [new file with mode: 0644]

diff --git a/queue-4.14/can-gw-ensure-dlc-boundaries-after-can-frame-modification.patch b/queue-4.14/can-gw-ensure-dlc-boundaries-after-can-frame-modification.patch
new file mode 100644 (file)
index 0000000..12026e3
--- /dev/null
@@ -0,0 +1,91 @@
+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)
diff --git a/queue-4.14/tty-don-t-hold-ldisc-lock-in-tty_reopen-if-ldisc-present.patch b/queue-4.14/tty-don-t-hold-ldisc-lock-in-tty_reopen-if-ldisc-present.patch
new file mode 100644 (file)
index 0000000..8ad553c
--- /dev/null
@@ -0,0 +1,69 @@
+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++;
diff --git a/queue-4.14/tty-hold-tty_ldisc_lock-during-tty_reopen.patch b/queue-4.14/tty-hold-tty_ldisc_lock-during-tty_reopen.patch
new file mode 100644 (file)
index 0000000..396de21
--- /dev/null
@@ -0,0 +1,71 @@
+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;
+ }
diff --git a/queue-4.14/tty-ldsem-wake-up-readers-after-timed-out-down_write.patch b/queue-4.14/tty-ldsem-wake-up-readers-after-timed-out-down_write.patch
new file mode 100644 (file)
index 0000000..ca797e9
--- /dev/null
@@ -0,0 +1,58 @@
+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);
diff --git a/queue-4.14/tty-simplify-tty-count-math-in-tty_reopen.patch b/queue-4.14/tty-simplify-tty-count-math-in-tty_reopen.patch
new file mode 100644 (file)
index 0000000..a2e773d
--- /dev/null
@@ -0,0 +1,48 @@
+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;
+ }