Commit a90401c5 authored by Cong Wang's avatar Cong Wang Committed by Juerg Haefliger

netrom: fix locking in nr_find_socket()

BugLink: https://bugs.launchpad.net/bugs/1811647

[ Upstream commit 7314f548 ]

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: default avatarCong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarJuerg Haefliger <juergh@canonical.com>
Signed-off-by: default avatarStefan Bader <stefan.bader@canonical.com>
parent d1502c2f
...@@ -153,7 +153,7 @@ static struct sock *nr_find_listener(ax25_address *addr) ...@@ -153,7 +153,7 @@ static struct sock *nr_find_listener(ax25_address *addr)
sk_for_each(s, &nr_list) sk_for_each(s, &nr_list)
if (!ax25cmp(&nr_sk(s)->source_addr, addr) && if (!ax25cmp(&nr_sk(s)->source_addr, addr) &&
s->sk_state == TCP_LISTEN) { s->sk_state == TCP_LISTEN) {
bh_lock_sock(s); sock_hold(s);
goto found; goto found;
} }
s = NULL; s = NULL;
...@@ -174,7 +174,7 @@ static struct sock *nr_find_socket(unsigned char index, unsigned char id) ...@@ -174,7 +174,7 @@ static struct sock *nr_find_socket(unsigned char index, unsigned char id)
struct nr_sock *nr = nr_sk(s); struct nr_sock *nr = nr_sk(s);
if (nr->my_index == index && nr->my_id == id) { if (nr->my_index == index && nr->my_id == id) {
bh_lock_sock(s); sock_hold(s);
goto found; goto found;
} }
} }
...@@ -198,7 +198,7 @@ static struct sock *nr_find_peer(unsigned char index, unsigned char id, ...@@ -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 && if (nr->your_index == index && nr->your_id == id &&
!ax25cmp(&nr->dest_addr, dest)) { !ax25cmp(&nr->dest_addr, dest)) {
bh_lock_sock(s); sock_hold(s);
goto found; goto found;
} }
} }
...@@ -224,7 +224,7 @@ static unsigned short nr_find_next_circuit(void) ...@@ -224,7 +224,7 @@ static unsigned short nr_find_next_circuit(void)
if (i != 0 && j != 0) { if (i != 0 && j != 0) {
if ((sk=nr_find_socket(i, j)) == NULL) if ((sk=nr_find_socket(i, j)) == NULL)
break; break;
bh_unlock_sock(sk); sock_put(sk);
} }
id++; id++;
...@@ -918,6 +918,7 @@ int nr_rx_frame(struct sk_buff *skb, struct net_device *dev) ...@@ -918,6 +918,7 @@ int nr_rx_frame(struct sk_buff *skb, struct net_device *dev)
} }
if (sk != NULL) { if (sk != NULL) {
bh_lock_sock(sk);
skb_reset_transport_header(skb); skb_reset_transport_header(skb);
if (frametype == NR_CONNACK && skb->len == 22) if (frametype == NR_CONNACK && skb->len == 22)
...@@ -927,6 +928,7 @@ int nr_rx_frame(struct sk_buff *skb, struct net_device *dev) ...@@ -927,6 +928,7 @@ int nr_rx_frame(struct sk_buff *skb, struct net_device *dev)
ret = nr_process_rx_frame(sk, skb); ret = nr_process_rx_frame(sk, skb);
bh_unlock_sock(sk); bh_unlock_sock(sk);
sock_put(sk);
return ret; return ret;
} }
...@@ -958,10 +960,12 @@ int nr_rx_frame(struct sk_buff *skb, struct net_device *dev) ...@@ -958,10 +960,12 @@ int nr_rx_frame(struct sk_buff *skb, struct net_device *dev)
(make = nr_make_new(sk)) == NULL) { (make = nr_make_new(sk)) == NULL) {
nr_transmit_refusal(skb, 0); nr_transmit_refusal(skb, 0);
if (sk) if (sk)
bh_unlock_sock(sk); sock_put(sk);
return 0; return 0;
} }
bh_lock_sock(sk);
window = skb->data[20]; window = skb->data[20];
skb->sk = make; skb->sk = make;
...@@ -1014,6 +1018,7 @@ int nr_rx_frame(struct sk_buff *skb, struct net_device *dev) ...@@ -1014,6 +1018,7 @@ int nr_rx_frame(struct sk_buff *skb, struct net_device *dev)
sk->sk_data_ready(sk); sk->sk_data_ready(sk);
bh_unlock_sock(sk); bh_unlock_sock(sk);
sock_put(sk);
nr_insert_socket(make); nr_insert_socket(make);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment