From: Greg Kroah-Hartman Date: Sat, 23 Apr 2022 11:03:46 +0000 (+0200) Subject: 4.14-stable patches X-Git-Tag: v4.9.312~61 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d65cbb3d33acb085396794e08267f51b8ec5bc09;p=thirdparty%2Fkernel%2Fstable-queue.git 4.14-stable patches added patches: alsa-usb-audio-clear-midi-port-active-flag-after-draining.patch tcp-fix-potential-use-after-free-due-to-double-kfree.patch --- diff --git a/queue-4.14/alsa-usb-audio-clear-midi-port-active-flag-after-draining.patch b/queue-4.14/alsa-usb-audio-clear-midi-port-active-flag-after-draining.patch new file mode 100644 index 00000000000..9fe5ece3c26 --- /dev/null +++ b/queue-4.14/alsa-usb-audio-clear-midi-port-active-flag-after-draining.patch @@ -0,0 +1,41 @@ +From 0665886ad1392e6b5bae85d7a6ccbed48dca1522 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Wed, 20 Apr 2022 15:02:47 +0200 +Subject: ALSA: usb-audio: Clear MIDI port active flag after draining + +From: Takashi Iwai + +commit 0665886ad1392e6b5bae85d7a6ccbed48dca1522 upstream. + +When a rawmidi output stream is closed, it calls the drain at first, +then does trigger-off only when the drain returns -ERESTARTSYS as a +fallback. It implies that each driver should turn off the stream +properly after the drain. Meanwhile, USB-audio MIDI interface didn't +change the port->active flag after the drain. This may leave the +output work picking up the port that is closed right now, which +eventually leads to a use-after-free for the already released rawmidi +object. + +This patch fixes the bug by properly clearing the port->active flag +after the output drain. + +Reported-by: syzbot+70e777a39907d6d5fd0a@syzkaller.appspotmail.com +Cc: +Link: https://lore.kernel.org/r/00000000000011555605dceaff03@google.com +Link: https://lore.kernel.org/r/20220420130247.22062-1-tiwai@suse.de +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/usb/midi.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/sound/usb/midi.c ++++ b/sound/usb/midi.c +@@ -1210,6 +1210,7 @@ static void snd_usbmidi_output_drain(str + } while (drain_urbs && timeout); + finish_wait(&ep->drain_wait, &wait); + } ++ port->active = 0; + spin_unlock_irq(&ep->buffer_lock); + } + diff --git a/queue-4.14/series b/queue-4.14/series index a80f9ecbc32..69b8235e1e3 100644 --- a/queue-4.14/series +++ b/queue-4.14/series @@ -4,4 +4,6 @@ tracing-have-traceon-and-traceoff-trigger-honor-the-instance.patch tracing-dump-stacktrace-trigger-to-the-corresponding-instance.patch can-usb_8dev-usb_8dev_start_xmit-fix-double-dev_kfree_skb-in-error-path.patch gfs2-assign-rgrp-glock-before-compute_bitstructs.patch +alsa-usb-audio-clear-midi-port-active-flag-after-draining.patch tcp-fix-race-condition-when-creating-child-sockets-f.patch +tcp-fix-potential-use-after-free-due-to-double-kfree.patch diff --git a/queue-4.14/tcp-fix-potential-use-after-free-due-to-double-kfree.patch b/queue-4.14/tcp-fix-potential-use-after-free-due-to-double-kfree.patch new file mode 100644 index 00000000000..deb53c58aeb --- /dev/null +++ b/queue-4.14/tcp-fix-potential-use-after-free-due-to-double-kfree.patch @@ -0,0 +1,76 @@ +From c89dffc70b340780e5b933832d8c3e045ef3791e Mon Sep 17 00:00:00 2001 +From: Kuniyuki Iwashima +Date: Mon, 18 Jan 2021 14:59:20 +0900 +Subject: tcp: Fix potential use-after-free due to double kfree() + +From: Kuniyuki Iwashima + +commit c89dffc70b340780e5b933832d8c3e045ef3791e upstream. + +Receiving ACK with a valid SYN cookie, cookie_v4_check() allocates struct +request_sock and then can allocate inet_rsk(req)->ireq_opt. After that, +tcp_v4_syn_recv_sock() allocates struct sock and copies ireq_opt to +inet_sk(sk)->inet_opt. Normally, tcp_v4_syn_recv_sock() inserts the full +socket into ehash and sets NULL to ireq_opt. Otherwise, +tcp_v4_syn_recv_sock() has to reset inet_opt by NULL and free the full +socket. + +The commit 01770a1661657 ("tcp: fix race condition when creating child +sockets from syncookies") added a new path, in which more than one cores +create full sockets for the same SYN cookie. Currently, the core which +loses the race frees the full socket without resetting inet_opt, resulting +in that both sock_put() and reqsk_put() call kfree() for the same memory: + + sock_put + sk_free + __sk_free + sk_destruct + __sk_destruct + sk->sk_destruct/inet_sock_destruct + kfree(rcu_dereference_protected(inet->inet_opt, 1)); + + reqsk_put + reqsk_free + __reqsk_free + req->rsk_ops->destructor/tcp_v4_reqsk_destructor + kfree(rcu_dereference_protected(inet_rsk(req)->ireq_opt, 1)); + +Calling kmalloc() between the double kfree() can lead to use-after-free, so +this patch fixes it by setting NULL to inet_opt before sock_put(). + +As a side note, this kind of issue does not happen for IPv6. This is +because tcp_v6_syn_recv_sock() clones both ipv6_opt and pktopts which +correspond to ireq_opt in IPv4. + +Fixes: 01770a166165 ("tcp: fix race condition when creating child sockets from syncookies") +CC: Ricardo Dias +Signed-off-by: Kuniyuki Iwashima +Reviewed-by: Benjamin Herrenschmidt +Reviewed-by: Eric Dumazet +Link: https://lore.kernel.org/r/20210118055920.82516-1-kuniyu@amazon.co.jp +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/tcp_ipv4.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/net/ipv4/tcp_ipv4.c ++++ b/net/ipv4/tcp_ipv4.c +@@ -1421,6 +1421,8 @@ struct sock *tcp_v4_syn_recv_sock(const + tcp_move_syn(newtp, req); + ireq->ireq_opt = NULL; + } else { ++ newinet->inet_opt = NULL; ++ + if (!req_unhash && found_dup_sk) { + /* This code path should only be executed in the + * syncookie case only +@@ -1428,8 +1430,6 @@ struct sock *tcp_v4_syn_recv_sock(const + bh_unlock_sock(newsk); + sock_put(newsk); + newsk = NULL; +- } else { +- newinet->inet_opt = NULL; + } + } + return newsk; diff --git a/queue-4.14/tcp-fix-race-condition-when-creating-child-sockets-f.patch b/queue-4.14/tcp-fix-race-condition-when-creating-child-sockets-f.patch index 4dc0a528f60..eb766e900ba 100644 --- a/queue-4.14/tcp-fix-race-condition-when-creating-child-sockets-f.patch +++ b/queue-4.14/tcp-fix-race-condition-when-creating-child-sockets-f.patch @@ -46,17 +46,15 @@ Link: https://lore.kernel.org/r/20201120111133.GA67501@rdias-suse-pc.lan Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- - include/net/inet_hashtables.h | 5 ++- - net/dccp/ipv4.c | 2 +- - net/dccp/ipv6.c | 2 +- - net/ipv4/inet_connection_sock.c | 2 +- - net/ipv4/inet_hashtables.c | 68 +++++++++++++++++++++++++++++---- - net/ipv4/tcp_ipv4.c | 15 +++++++- - net/ipv6/tcp_ipv6.c | 13 ++++++- + include/net/inet_hashtables.h | 5 +- + net/dccp/ipv4.c | 2 - + net/dccp/ipv6.c | 2 - + net/ipv4/inet_connection_sock.c | 2 - + net/ipv4/inet_hashtables.c | 68 +++++++++++++++++++++++++++++++++++----- + net/ipv4/tcp_ipv4.c | 15 +++++++- + net/ipv6/tcp_ipv6.c | 13 +++++++ 7 files changed, 91 insertions(+), 16 deletions(-) -diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h -index 573ab110c9ec..e5f4d2711404 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h @@ -215,8 +215,9 @@ void inet_put_port(struct sock *sk); @@ -71,11 +69,9 @@ index 573ab110c9ec..e5f4d2711404 100644 int __inet_hash(struct sock *sk, struct sock *osk); int inet_hash(struct sock *sk); void inet_unhash(struct sock *sk); -diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c -index 176bddacc16e..7e93087d1366 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c -@@ -428,7 +428,7 @@ struct sock *dccp_v4_request_recv_sock(const struct sock *sk, +@@ -428,7 +428,7 @@ struct sock *dccp_v4_request_recv_sock(c if (__inet_inherit_port(sk, newsk) < 0) goto put_and_exit; @@ -84,11 +80,9 @@ index 176bddacc16e..7e93087d1366 100644 if (*own_req) ireq->ireq_opt = NULL; else -diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c -index 2cd3508a3786..ae4851fdbe9e 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c -@@ -538,7 +538,7 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk, +@@ -538,7 +538,7 @@ static struct sock *dccp_v6_request_recv dccp_done(newsk); goto out; } @@ -97,11 +91,9 @@ index 2cd3508a3786..ae4851fdbe9e 100644 /* Clone pktoptions received with SYN, if we own the req */ if (*own_req && ireq->pktopts) { newnp->pktoptions = skb_clone(ireq->pktopts, GFP_ATOMIC); -diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c -index 08ba0f91f2ab..44b1d630c40b 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c -@@ -784,7 +784,7 @@ static void reqsk_queue_hash_req(struct request_sock *req, +@@ -784,7 +784,7 @@ static void reqsk_queue_hash_req(struct (unsigned long)req); mod_timer(&req->rsk_timer, jiffies + timeout); @@ -110,8 +102,6 @@ index 08ba0f91f2ab..44b1d630c40b 100644 /* before letting lookups find us, make sure all req fields * are committed to memory and refcnt initialized. */ -diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c -index 8a54babf5c90..1346e45cf8d1 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -23,6 +23,9 @@ @@ -124,7 +114,7 @@ index 8a54babf5c90..1346e45cf8d1 100644 #include #include #include -@@ -395,10 +398,52 @@ static u32 inet_sk_port_offset(const struct sock *sk) +@@ -395,10 +398,52 @@ static u32 inet_sk_port_offset(const str inet->inet_dport); } @@ -180,7 +170,7 @@ index 8a54babf5c90..1346e45cf8d1 100644 { struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; struct hlist_nulls_head *list; -@@ -417,16 +462,23 @@ bool inet_ehash_insert(struct sock *sk, struct sock *osk) +@@ -417,16 +462,23 @@ bool inet_ehash_insert(struct sock *sk, if (osk) { WARN_ON_ONCE(sk->sk_hash != osk->sk_hash); ret = sk_nulls_del_node_init_rcu(osk); @@ -206,7 +196,7 @@ index 8a54babf5c90..1346e45cf8d1 100644 if (ok) { sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); -@@ -469,7 +521,7 @@ int __inet_hash(struct sock *sk, struct sock *osk) +@@ -469,7 +521,7 @@ int __inet_hash(struct sock *sk, struct int err = 0; if (sk->sk_state != TCP_LISTEN) { @@ -215,7 +205,7 @@ index 8a54babf5c90..1346e45cf8d1 100644 return 0; } WARN_ON(!sk_unhashed(sk)); -@@ -556,7 +608,7 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row, +@@ -556,7 +608,7 @@ int __inet_hash_connect(struct inet_time tb = inet_csk(sk)->icsk_bind_hash; spin_lock_bh(&head->lock); if (sk_head(&tb->owners) == sk && !sk->sk_bind_node.next) { @@ -224,7 +214,7 @@ index 8a54babf5c90..1346e45cf8d1 100644 spin_unlock_bh(&head->lock); return 0; } -@@ -632,7 +684,7 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row, +@@ -632,7 +684,7 @@ ok: inet_bind_hash(sk, tb, port); if (sk_unhashed(sk)) { inet_sk(sk)->inet_sport = htons(port); @@ -233,11 +223,9 @@ index 8a54babf5c90..1346e45cf8d1 100644 } if (tw) inet_twsk_bind_unhash(tw, hinfo); -diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c -index 744479c8b91f..a598c5153434 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c -@@ -1344,6 +1344,7 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, +@@ -1344,6 +1344,7 @@ struct sock *tcp_v4_syn_recv_sock(const bool *own_req) { struct inet_request_sock *ireq; @@ -245,7 +233,7 @@ index 744479c8b91f..a598c5153434 100644 struct inet_sock *newinet; struct tcp_sock *newtp; struct sock *newsk; -@@ -1414,12 +1415,22 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, +@@ -1414,12 +1415,22 @@ struct sock *tcp_v4_syn_recv_sock(const if (__inet_inherit_port(sk, newsk) < 0) goto put_and_exit; @@ -270,11 +258,9 @@ index 744479c8b91f..a598c5153434 100644 } return newsk; -diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c -index 0f0772c48bf0..21637031fbab 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c -@@ -1064,6 +1064,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff * +@@ -1064,6 +1064,7 @@ static struct sock *tcp_v6_syn_recv_sock struct ipv6_txoptions *opt; struct tcp6_sock *newtcp6sk; struct inet_sock *newinet; @@ -282,7 +268,7 @@ index 0f0772c48bf0..21637031fbab 100644 struct tcp_sock *newtp; struct sock *newsk; #ifdef CONFIG_TCP_MD5SIG -@@ -1232,7 +1233,8 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff * +@@ -1232,7 +1233,8 @@ static struct sock *tcp_v6_syn_recv_sock tcp_done(newsk); goto out; } @@ -292,7 +278,7 @@ index 0f0772c48bf0..21637031fbab 100644 if (*own_req) { tcp_move_syn(newtp, req); -@@ -1247,6 +1249,15 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff * +@@ -1247,6 +1249,15 @@ static struct sock *tcp_v6_syn_recv_sock skb_set_owner_r(newnp->pktoptions, newsk); } } @@ -308,6 +294,3 @@ index 0f0772c48bf0..21637031fbab 100644 } return newsk; --- -2.35.1 -