From aab250a4f28b1a3be62636678842fd9a6cf14671 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 12 Jan 2023 14:44:18 +0100 Subject: [PATCH] 5.10-stable patches added patches: net-sched-disallow-noqueue-for-qdisc-classes.patch net-ulp-prevent-ulp-without-clone-op-from-entering-the-listen-status.patch --- ...d-disallow-noqueue-for-qdisc-classes.patch | 93 +++++++++++++++++++ ...e-op-from-entering-the-listen-status.patch | 77 +++++++++++++++ queue-5.10/series | 2 + 3 files changed, 172 insertions(+) create mode 100644 queue-5.10/net-sched-disallow-noqueue-for-qdisc-classes.patch create mode 100644 queue-5.10/net-ulp-prevent-ulp-without-clone-op-from-entering-the-listen-status.patch diff --git a/queue-5.10/net-sched-disallow-noqueue-for-qdisc-classes.patch b/queue-5.10/net-sched-disallow-noqueue-for-qdisc-classes.patch new file mode 100644 index 00000000000..68a82e18c8d --- /dev/null +++ b/queue-5.10/net-sched-disallow-noqueue-for-qdisc-classes.patch @@ -0,0 +1,93 @@ +From 96398560f26aa07e8f2969d73c8197e6a6d10407 Mon Sep 17 00:00:00 2001 +From: Frederick Lawler +Date: Mon, 9 Jan 2023 10:39:06 -0600 +Subject: net: sched: disallow noqueue for qdisc classes + +From: Frederick Lawler + +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] +[ 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] + +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 +Reviewed-by: Jakub Sitnicki +Link: https://lore.kernel.org/r/20230109163906.706000-1-fred@cloudflare.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/sched/sch_api.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/net/sched/sch_api.c ++++ b/net/sched/sch_api.c +@@ -1114,6 +1114,11 @@ skip: + return -ENOENT; + } + ++ if (new && new->ops == &noqueue_qdisc_ops) { ++ NL_SET_ERR_MSG(extack, "Cannot assign noqueue to a class"); ++ return -EINVAL; ++ } ++ + err = cops->graft(parent, cl, new, &old, extack); + if (err) + return err; diff --git a/queue-5.10/net-ulp-prevent-ulp-without-clone-op-from-entering-the-listen-status.patch b/queue-5.10/net-ulp-prevent-ulp-without-clone-op-from-entering-the-listen-status.patch new file mode 100644 index 00000000000..6adf1fc77a7 --- /dev/null +++ b/queue-5.10/net-ulp-prevent-ulp-without-clone-op-from-entering-the-listen-status.patch @@ -0,0 +1,77 @@ +From 2c02d41d71f90a5168391b6a5f2954112ba2307c Mon Sep 17 00:00:00 2001 +From: Paolo Abeni +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 + +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 +Signed-off-by: Paolo Abeni +Link: https://lore.kernel.org/r/4b80c3d1dbe3d0ab072f80450c202d9bc88b4b03.1672740602.git.pabeni@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -916,11 +916,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 +@@ -136,6 +136,10 @@ static int __tcp_set_ulp(struct sock *sk + if (icsk->icsk_ulp_ops) + goto out_err; + ++ err = -EINVAL; ++ if (!ulp_ops->clone && sk->sk_state == TCP_LISTEN) ++ goto out_err; ++ + err = ulp_ops->init(sk); + if (err) + goto out_err; diff --git a/queue-5.10/series b/queue-5.10/series index ea8b4edb469..03027416a19 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -779,3 +779,5 @@ mptcp-mark-ops-structures-as-ro_after_init.patch mptcp-remove-mptcp-ifdef-in-tcp-syn-cookies.patch mptcp-dedicated-request-sock-for-subflow-in-v6.patch mptcp-use-proper-req-destructor-for-ipv6.patch +net-sched-disallow-noqueue-for-qdisc-classes.patch +net-ulp-prevent-ulp-without-clone-op-from-entering-the-listen-status.patch -- 2.47.3