]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 12 Jan 2023 13:43:41 +0000 (14:43 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 12 Jan 2023 13:43:41 +0000 (14:43 +0100)
added patches:
net-sched-disallow-noqueue-for-qdisc-classes.patch
net-ulp-prevent-ulp-without-clone-op-from-entering-the-listen-status.patch

queue-4.14/net-sched-disallow-noqueue-for-qdisc-classes.patch [new file with mode: 0644]
queue-4.14/net-ulp-prevent-ulp-without-clone-op-from-entering-the-listen-status.patch [new file with mode: 0644]
queue-4.14/series

diff --git a/queue-4.14/net-sched-disallow-noqueue-for-qdisc-classes.patch b/queue-4.14/net-sched-disallow-noqueue-for-qdisc-classes.patch
new file mode 100644 (file)
index 0000000..5d8986a
--- /dev/null
@@ -0,0 +1,99 @@
+From 96398560f26aa07e8f2969d73c8197e6a6d10407 Mon Sep 17 00:00:00 2001
+From: Frederick Lawler <fred@cloudflare.com>
+Date: Mon, 9 Jan 2023 10:39:06 -0600
+Subject: net: sched: disallow noqueue for qdisc classes
+
+From: Frederick Lawler <fred@cloudflare.com>
+
+commit 96398560f26aa07e8f2969d73c8197e6a6d10407 upstream.
+
+While experimenting with applying noqueue to a classful queue discipline,
+we discovered a NULL pointer dereference in the __dev_queue_xmit()
+path that generates a kernel OOPS:
+
+    # dev=enp0s5
+    # tc qdisc replace dev $dev root handle 1: htb default 1
+    # tc class add dev $dev parent 1: classid 1:1 htb rate 10mbit
+    # tc qdisc add dev $dev parent 1:1 handle 10: noqueue
+    # ping -I $dev -w 1 -c 1 1.1.1.1
+
+[    2.172856] BUG: kernel NULL pointer dereference, address: 0000000000000000
+[    2.173217] #PF: supervisor instruction fetch in kernel mode
+...
+[    2.178451] Call Trace:
+[    2.178577]  <TASK>
+[    2.178686]  htb_enqueue+0x1c8/0x370
+[    2.178880]  dev_qdisc_enqueue+0x15/0x90
+[    2.179093]  __dev_queue_xmit+0x798/0xd00
+[    2.179305]  ? _raw_write_lock_bh+0xe/0x30
+[    2.179522]  ? __local_bh_enable_ip+0x32/0x70
+[    2.179759]  ? ___neigh_create+0x610/0x840
+[    2.179968]  ? eth_header+0x21/0xc0
+[    2.180144]  ip_finish_output2+0x15e/0x4f0
+[    2.180348]  ? dst_output+0x30/0x30
+[    2.180525]  ip_push_pending_frames+0x9d/0xb0
+[    2.180739]  raw_sendmsg+0x601/0xcb0
+[    2.180916]  ? _raw_spin_trylock+0xe/0x50
+[    2.181112]  ? _raw_spin_unlock_irqrestore+0x16/0x30
+[    2.181354]  ? get_page_from_freelist+0xcd6/0xdf0
+[    2.181594]  ? sock_sendmsg+0x56/0x60
+[    2.181781]  sock_sendmsg+0x56/0x60
+[    2.181958]  __sys_sendto+0xf7/0x160
+[    2.182139]  ? handle_mm_fault+0x6e/0x1d0
+[    2.182366]  ? do_user_addr_fault+0x1e1/0x660
+[    2.182627]  __x64_sys_sendto+0x1b/0x30
+[    2.182881]  do_syscall_64+0x38/0x90
+[    2.183085]  entry_SYSCALL_64_after_hwframe+0x63/0xcd
+...
+[    2.187402]  </TASK>
+
+Previously in commit d66d6c3152e8 ("net: sched: register noqueue
+qdisc"), NULL was set for the noqueue discipline on noqueue init
+so that __dev_queue_xmit() falls through for the noqueue case. This
+also sets a bypass of the enqueue NULL check in the
+register_qdisc() function for the struct noqueue_disc_ops.
+
+Classful queue disciplines make it past the NULL check in
+__dev_queue_xmit() because the discipline is set to htb (in this case),
+and then in the call to __dev_xmit_skb(), it calls into htb_enqueue()
+which grabs a leaf node for a class and then calls qdisc_enqueue() by
+passing in a queue discipline which assumes ->enqueue() is not set to NULL.
+
+Fix this by not allowing classes to be assigned to the noqueue
+discipline. Linux TC Notes states that classes cannot be set to
+the noqueue discipline. [1] Let's enforce that here.
+
+Links:
+1. https://linux-tc-notes.sourceforge.net/tc/doc/sch_noqueue.txt
+
+Fixes: d66d6c3152e8 ("net: sched: register noqueue qdisc")
+Cc: stable@vger.kernel.org
+Signed-off-by: Frederick Lawler <fred@cloudflare.com>
+Reviewed-by: Jakub Sitnicki <jakub@cloudflare.com>
+Link: https://lore.kernel.org/r/20230109163906.706000-1-fred@cloudflare.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/sched/sch_api.c |   10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+--- a/net/sched/sch_api.c
++++ b/net/sched/sch_api.c
+@@ -959,10 +959,14 @@ skip:
+               if (cops && cops->graft) {
+                       unsigned long cl = cops->find(parent, classid);
+-                      if (cl)
+-                              err = cops->graft(parent, cl, new, &old);
+-                      else
++                      if (cl) {
++                              if (new && new->ops == &noqueue_qdisc_ops)
++                                      err = -EINVAL;
++                              else
++                                      err = cops->graft(parent, cl, new, &old);
++                      } else {
+                               err = -ENOENT;
++                      }
+               }
+               if (!err)
+                       notify_and_destroy(net, skb, n, classid, old, new);
diff --git a/queue-4.14/net-ulp-prevent-ulp-without-clone-op-from-entering-the-listen-status.patch b/queue-4.14/net-ulp-prevent-ulp-without-clone-op-from-entering-the-listen-status.patch
new file mode 100644 (file)
index 0000000..d750171
--- /dev/null
@@ -0,0 +1,77 @@
+From 2c02d41d71f90a5168391b6a5f2954112ba2307c Mon Sep 17 00:00:00 2001
+From: Paolo Abeni <pabeni@redhat.com>
+Date: Tue, 3 Jan 2023 12:19:17 +0100
+Subject: net/ulp: prevent ULP without clone op from entering the LISTEN status
+
+From: Paolo Abeni <pabeni@redhat.com>
+
+commit 2c02d41d71f90a5168391b6a5f2954112ba2307c upstream.
+
+When an ULP-enabled socket enters the LISTEN status, the listener ULP data
+pointer is copied inside the child/accepted sockets by sk_clone_lock().
+
+The relevant ULP can take care of de-duplicating the context pointer via
+the clone() operation, but only MPTCP and SMC implement such op.
+
+Other ULPs may end-up with a double-free at socket disposal time.
+
+We can't simply clear the ULP data at clone time, as TLS replaces the
+socket ops with custom ones assuming a valid TLS ULP context is
+available.
+
+Instead completely prevent clone-less ULP sockets from entering the
+LISTEN status.
+
+Fixes: 734942cc4ea6 ("tcp: ULP infrastructure")
+Reported-by: slipper <slipper.alive@gmail.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Link: https://lore.kernel.org/r/4b80c3d1dbe3d0ab072f80450c202d9bc88b4b03.1672740602.git.pabeni@redhat.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/ipv4/inet_connection_sock.c |   16 +++++++++++++++-
+ net/ipv4/tcp_ulp.c              |    4 ++++
+ 2 files changed, 19 insertions(+), 1 deletion(-)
+
+--- a/net/ipv4/inet_connection_sock.c
++++ b/net/ipv4/inet_connection_sock.c
+@@ -894,11 +894,25 @@ void inet_csk_prepare_forced_close(struc
+ }
+ EXPORT_SYMBOL(inet_csk_prepare_forced_close);
++static int inet_ulp_can_listen(const struct sock *sk)
++{
++      const struct inet_connection_sock *icsk = inet_csk(sk);
++
++      if (icsk->icsk_ulp_ops && !icsk->icsk_ulp_ops->clone)
++              return -EINVAL;
++
++      return 0;
++}
++
+ int inet_csk_listen_start(struct sock *sk, int backlog)
+ {
+       struct inet_connection_sock *icsk = inet_csk(sk);
+       struct inet_sock *inet = inet_sk(sk);
+-      int err = -EADDRINUSE;
++      int err;
++
++      err = inet_ulp_can_listen(sk);
++      if (unlikely(err))
++              return err;
+       reqsk_queue_alloc(&icsk->icsk_accept_queue);
+--- a/net/ipv4/tcp_ulp.c
++++ b/net/ipv4/tcp_ulp.c
+@@ -124,6 +124,10 @@ int tcp_set_ulp(struct sock *sk, const c
+       if (!ulp_ops)
+               return -ENOENT;
++      err = -EINVAL;
++      if (!ulp_ops->clone && sk->sk_state == TCP_LISTEN)
++              goto out_err;
++
+       err = ulp_ops->init(sk);
+       if (err) {
+               module_put(ulp_ops->owner);
index b47a34fa51343f673913a2e12fb8d97d52a5feb0..02ba4f95d88b5aea2bfdade22dd784e5d7d47892 100644 (file)
@@ -321,3 +321,5 @@ hfs-hfsplus-avoid-warn_on-for-sanity-check-use-proper-error-handling.patch
 parisc-align-parisc-madv_xxx-constants-with-all-other-architectures.patch
 driver-core-fix-bus_type.match-error-handling-in-__driver_attach.patch
 ravb-fix-failed-to-switch-device-to-config-mode-message-during-unbind.patch
+net-sched-disallow-noqueue-for-qdisc-classes.patch
+net-ulp-prevent-ulp-without-clone-op-from-entering-the-listen-status.patch