]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.19-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 23 Apr 2022 11:03:53 +0000 (13:03 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 23 Apr 2022 11:03:53 +0000 (13:03 +0200)
added patches:
alsa-usb-audio-clear-midi-port-active-flag-after-draining.patch
tcp-fix-potential-use-after-free-due-to-double-kfree.patch

queue-4.19/alsa-usb-audio-clear-midi-port-active-flag-after-draining.patch [new file with mode: 0644]
queue-4.19/series
queue-4.19/tcp-fix-potential-use-after-free-due-to-double-kfree.patch [new file with mode: 0644]
queue-4.19/tcp-fix-race-condition-when-creating-child-sockets-f.patch

diff --git a/queue-4.19/alsa-usb-audio-clear-midi-port-active-flag-after-draining.patch b/queue-4.19/alsa-usb-audio-clear-midi-port-active-flag-after-draining.patch
new file mode 100644 (file)
index 0000000..2619bf8
--- /dev/null
@@ -0,0 +1,41 @@
+From 0665886ad1392e6b5bae85d7a6ccbed48dca1522 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Wed, 20 Apr 2022 15:02:47 +0200
+Subject: ALSA: usb-audio: Clear MIDI port active flag after draining
+
+From: Takashi Iwai <tiwai@suse.de>
+
+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: <stable@vger.kernel.org>
+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 <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/usb/midi.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/sound/usb/midi.c
++++ b/sound/usb/midi.c
+@@ -1211,6 +1211,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);
+ }
index 6c3addf5ee1c31b93abb756eac8e3861d83c5a03..1bf682aee6deeab26c5214340a05ba0e21f0152f 100644 (file)
@@ -4,4 +4,6 @@ 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
 dm-integrity-fix-memory-corruption-when-tag_size-is-less-than-digest-size.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.19/tcp-fix-potential-use-after-free-due-to-double-kfree.patch b/queue-4.19/tcp-fix-potential-use-after-free-due-to-double-kfree.patch
new file mode 100644 (file)
index 0000000..5e16669
--- /dev/null
@@ -0,0 +1,76 @@
+From c89dffc70b340780e5b933832d8c3e045ef3791e Mon Sep 17 00:00:00 2001
+From: Kuniyuki Iwashima <kuniyu@amazon.co.jp>
+Date: Mon, 18 Jan 2021 14:59:20 +0900
+Subject: tcp: Fix potential use-after-free due to double kfree()
+
+From: Kuniyuki Iwashima <kuniyu@amazon.co.jp>
+
+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 <rdias@singlestore.com>
+Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.co.jp>
+Reviewed-by: Benjamin Herrenschmidt <benh@amazon.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://lore.kernel.org/r/20210118055920.82516-1-kuniyu@amazon.co.jp
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+@@ -1492,6 +1492,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
+@@ -1499,8 +1501,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;
index 24722c314bbda6ad43eddf23ad55390f07530728..bba28f3cc9dd7aa1203c3c904cf7e67db4d06ad4 100644 (file)
@@ -46,20 +46,18 @@ Link: https://lore.kernel.org/r/20201120111133.GA67501@rdias-suse-pc.lan
 Signed-off-by: Jakub Kicinski <kuba@kernel.org>
 Signed-off-by: Sasha Levin <sashal@kernel.org>
 ---
- 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 b875dcef173c..fa5fe23ca6aa 100644
 --- a/include/net/inet_hashtables.h
 +++ b/include/net/inet_hashtables.h
-@@ -232,8 +232,9 @@ void inet_hashinfo2_init(struct inet_hashinfo *h, const char *name,
+@@ -232,8 +232,9 @@ void inet_hashinfo2_init(struct inet_has
                         unsigned long low_limit,
                         unsigned long high_limit);
  
@@ -71,11 +69,9 @@ index b875dcef173c..fa5fe23ca6aa 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 439a55d1aa99..0a69f92da71b 100644
 --- a/net/ipv4/inet_connection_sock.c
 +++ b/net/ipv4/inet_connection_sock.c
-@@ -793,7 +793,7 @@ static void reqsk_queue_hash_req(struct request_sock *req,
+@@ -793,7 +793,7 @@ static void reqsk_queue_hash_req(struct
        timer_setup(&req->rsk_timer, reqsk_timer_handler, TIMER_PINNED);
        mod_timer(&req->rsk_timer, jiffies + timeout);
  
@@ -110,8 +102,6 @@ index 439a55d1aa99..0a69f92da71b 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 3a5f12f011cb..c96a5871b49d 100644
 --- a/net/ipv4/inet_hashtables.c
 +++ b/net/ipv4/inet_hashtables.c
 @@ -24,6 +24,9 @@
@@ -124,7 +114,7 @@ index 3a5f12f011cb..c96a5871b49d 100644
  #include <net/secure_seq.h>
  #include <net/ip.h>
  #include <net/tcp.h>
-@@ -513,10 +516,52 @@ static u32 inet_sk_port_offset(const struct sock *sk)
+@@ -513,10 +516,52 @@ static u32 inet_sk_port_offset(const str
                                          inet->inet_dport);
  }
  
@@ -180,7 +170,7 @@ index 3a5f12f011cb..c96a5871b49d 100644
  {
        struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo;
        struct hlist_nulls_head *list;
-@@ -535,16 +580,23 @@ bool inet_ehash_insert(struct sock *sk, struct sock *osk)
+@@ -535,16 +580,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 3a5f12f011cb..c96a5871b49d 100644
  
        if (ok) {
                sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
-@@ -588,7 +640,7 @@ int __inet_hash(struct sock *sk, struct sock *osk)
+@@ -588,7 +640,7 @@ int __inet_hash(struct sock *sk, struct
        int err = 0;
  
        if (sk->sk_state != TCP_LISTEN) {
@@ -215,7 +205,7 @@ index 3a5f12f011cb..c96a5871b49d 100644
                return 0;
        }
        WARN_ON(!sk_unhashed(sk));
-@@ -683,7 +735,7 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row,
+@@ -683,7 +735,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 3a5f12f011cb..c96a5871b49d 100644
                        spin_unlock_bh(&head->lock);
                        return 0;
                }
-@@ -759,7 +811,7 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row,
+@@ -759,7 +811,7 @@ ok:
        inet_bind_hash(sk, tb, port);
        if (sk_unhashed(sk)) {
                inet_sk(sk)->inet_sport = htons(port);
@@ -233,11 +223,9 @@ index 3a5f12f011cb..c96a5871b49d 100644
        }
        if (tw)
                inet_twsk_bind_unhash(tw, hinfo);
-diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
-index de4edfbc9e46..7ebdfab5b24a 100644
 --- a/net/ipv4/tcp_ipv4.c
 +++ b/net/ipv4/tcp_ipv4.c
-@@ -1415,6 +1415,7 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,
+@@ -1415,6 +1415,7 @@ struct sock *tcp_v4_syn_recv_sock(const
                                  bool *own_req)
  {
        struct inet_request_sock *ireq;
@@ -245,7 +233,7 @@ index de4edfbc9e46..7ebdfab5b24a 100644
        struct inet_sock *newinet;
        struct tcp_sock *newtp;
        struct sock *newsk;
-@@ -1485,12 +1486,22 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,
+@@ -1485,12 +1486,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 de4edfbc9e46..7ebdfab5b24a 100644
        }
        return newsk;
  
-diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
-index e8d206725cb7..c332f75f4e9a 100644
 --- a/net/ipv6/tcp_ipv6.c
 +++ b/net/ipv6/tcp_ipv6.c
-@@ -1090,6 +1090,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
+@@ -1090,6 +1090,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 e8d206725cb7..c332f75f4e9a 100644
        struct tcp_sock *newtp;
        struct sock *newsk;
  #ifdef CONFIG_TCP_MD5SIG
-@@ -1258,7 +1259,8 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
+@@ -1258,7 +1259,8 @@ static struct sock *tcp_v6_syn_recv_sock
                tcp_done(newsk);
                goto out;
        }
@@ -292,7 +278,7 @@ index e8d206725cb7..c332f75f4e9a 100644
        if (*own_req) {
                tcp_move_syn(newtp, req);
  
-@@ -1273,6 +1275,15 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
+@@ -1273,6 +1275,15 @@ static struct sock *tcp_v6_syn_recv_sock
                                skb_set_owner_r(newnp->pktoptions, newsk);
                        }
                }
@@ -308,6 +294,3 @@ index e8d206725cb7..c332f75f4e9a 100644
        }
  
        return newsk;
--- 
-2.35.1
-