]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
netrom: fix locking in nr_find_socket()
authorCong Wang <xiyou.wangcong@gmail.com>
Sat, 29 Dec 2018 21:56:38 +0000 (13:56 -0800)
committerKleber Sacilotto de Souza <kleber.souza@canonical.com>
Wed, 14 Aug 2019 09:18:49 +0000 (11:18 +0200)
BugLink: https://bugs.launchpad.net/bugs/1837257
[ Upstream commit 7314f5480f3e37e570104dc5e0f28823ef849e72 ]

nr_find_socket(), nr_find_peer() and nr_find_listener() lock the
sock after finding it in the global list. However, the call path
requires BH disabled for the sock lock consistently.

Actually the locking is unnecessary at this point, we can just hold
the sock refcnt to make sure it is not gone after we unlock the global
list, and lock it later only when needed.

Reported-and-tested-by: syzbot+f621cda8b7e598908efa@syzkaller.appspotmail.com
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Andrea Righi <andrea.righi@canonical.com>
Signed-off-by: Khalid Elmously <khalid.elmously@canonical.com>
net/netrom/af_netrom.c

index 7ed9d4422a73decbe395eb603d7d106436d9f3a4..85bb2296b545e943a19f2353efeb14c634ba5b64 100644 (file)
@@ -153,7 +153,7 @@ static struct sock *nr_find_listener(ax25_address *addr)
        sk_for_each(s, &nr_list)
                if (!ax25cmp(&nr_sk(s)->source_addr, addr) &&
                    s->sk_state == TCP_LISTEN) {
-                       bh_lock_sock(s);
+                       sock_hold(s);
                        goto found;
                }
        s = NULL;
@@ -174,7 +174,7 @@ static struct sock *nr_find_socket(unsigned char index, unsigned char id)
                struct nr_sock *nr = nr_sk(s);
 
                if (nr->my_index == index && nr->my_id == id) {
-                       bh_lock_sock(s);
+                       sock_hold(s);
                        goto found;
                }
        }
@@ -198,7 +198,7 @@ static struct sock *nr_find_peer(unsigned char index, unsigned char id,
 
                if (nr->your_index == index && nr->your_id == id &&
                    !ax25cmp(&nr->dest_addr, dest)) {
-                       bh_lock_sock(s);
+                       sock_hold(s);
                        goto found;
                }
        }
@@ -224,7 +224,7 @@ static unsigned short nr_find_next_circuit(void)
                if (i != 0 && j != 0) {
                        if ((sk=nr_find_socket(i, j)) == NULL)
                                break;
-                       bh_unlock_sock(sk);
+                       sock_put(sk);
                }
 
                id++;
@@ -919,6 +919,7 @@ int nr_rx_frame(struct sk_buff *skb, struct net_device *dev)
        }
 
        if (sk != NULL) {
+               bh_lock_sock(sk);
                skb_reset_transport_header(skb);
 
                if (frametype == NR_CONNACK && skb->len == 22)
@@ -928,6 +929,7 @@ int nr_rx_frame(struct sk_buff *skb, struct net_device *dev)
 
                ret = nr_process_rx_frame(sk, skb);
                bh_unlock_sock(sk);
+               sock_put(sk);
                return ret;
        }
 
@@ -959,10 +961,12 @@ int nr_rx_frame(struct sk_buff *skb, struct net_device *dev)
            (make = nr_make_new(sk)) == NULL) {
                nr_transmit_refusal(skb, 0);
                if (sk)
-                       bh_unlock_sock(sk);
+                       sock_put(sk);
                return 0;
        }
 
+       bh_lock_sock(sk);
+
        window = skb->data[20];
 
        skb->sk             = make;
@@ -1015,6 +1019,7 @@ int nr_rx_frame(struct sk_buff *skb, struct net_device *dev)
                sk->sk_data_ready(sk);
 
        bh_unlock_sock(sk);
+       sock_put(sk);
 
        nr_insert_socket(make);