]>
Commit | Line | Data |
---|---|---|
e7503a51 GKH |
1 | From foo@baz Sat Jan 5 08:30:28 CET 2019 |
2 | From: Cong Wang <xiyou.wangcong@gmail.com> | |
3 | Date: Sat, 29 Dec 2018 13:56:38 -0800 | |
4 | Subject: netrom: fix locking in nr_find_socket() | |
5 | ||
6 | From: Cong Wang <xiyou.wangcong@gmail.com> | |
7 | ||
8 | [ Upstream commit 7314f5480f3e37e570104dc5e0f28823ef849e72 ] | |
9 | ||
10 | nr_find_socket(), nr_find_peer() and nr_find_listener() lock the | |
11 | sock after finding it in the global list. However, the call path | |
12 | requires BH disabled for the sock lock consistently. | |
13 | ||
14 | Actually the locking is unnecessary at this point, we can just hold | |
15 | the sock refcnt to make sure it is not gone after we unlock the global | |
16 | list, and lock it later only when needed. | |
17 | ||
18 | Reported-and-tested-by: syzbot+f621cda8b7e598908efa@syzkaller.appspotmail.com | |
19 | Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> | |
20 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
21 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
22 | --- | |
23 | net/netrom/af_netrom.c | 15 ++++++++++----- | |
24 | 1 file changed, 10 insertions(+), 5 deletions(-) | |
25 | ||
26 | --- a/net/netrom/af_netrom.c | |
27 | +++ b/net/netrom/af_netrom.c | |
28 | @@ -153,7 +153,7 @@ static struct sock *nr_find_listener(ax2 | |
29 | sk_for_each(s, &nr_list) | |
30 | if (!ax25cmp(&nr_sk(s)->source_addr, addr) && | |
31 | s->sk_state == TCP_LISTEN) { | |
32 | - bh_lock_sock(s); | |
33 | + sock_hold(s); | |
34 | goto found; | |
35 | } | |
36 | s = NULL; | |
37 | @@ -174,7 +174,7 @@ static struct sock *nr_find_socket(unsig | |
38 | struct nr_sock *nr = nr_sk(s); | |
39 | ||
40 | if (nr->my_index == index && nr->my_id == id) { | |
41 | - bh_lock_sock(s); | |
42 | + sock_hold(s); | |
43 | goto found; | |
44 | } | |
45 | } | |
46 | @@ -198,7 +198,7 @@ static struct sock *nr_find_peer(unsigne | |
47 | ||
48 | if (nr->your_index == index && nr->your_id == id && | |
49 | !ax25cmp(&nr->dest_addr, dest)) { | |
50 | - bh_lock_sock(s); | |
51 | + sock_hold(s); | |
52 | goto found; | |
53 | } | |
54 | } | |
55 | @@ -224,7 +224,7 @@ static unsigned short nr_find_next_circu | |
56 | if (i != 0 && j != 0) { | |
57 | if ((sk=nr_find_socket(i, j)) == NULL) | |
58 | break; | |
59 | - bh_unlock_sock(sk); | |
60 | + sock_put(sk); | |
61 | } | |
62 | ||
63 | id++; | |
64 | @@ -918,6 +918,7 @@ int nr_rx_frame(struct sk_buff *skb, str | |
65 | } | |
66 | ||
67 | if (sk != NULL) { | |
68 | + bh_lock_sock(sk); | |
69 | skb_reset_transport_header(skb); | |
70 | ||
71 | if (frametype == NR_CONNACK && skb->len == 22) | |
72 | @@ -927,6 +928,7 @@ int nr_rx_frame(struct sk_buff *skb, str | |
73 | ||
74 | ret = nr_process_rx_frame(sk, skb); | |
75 | bh_unlock_sock(sk); | |
76 | + sock_put(sk); | |
77 | return ret; | |
78 | } | |
79 | ||
80 | @@ -958,10 +960,12 @@ int nr_rx_frame(struct sk_buff *skb, str | |
81 | (make = nr_make_new(sk)) == NULL) { | |
82 | nr_transmit_refusal(skb, 0); | |
83 | if (sk) | |
84 | - bh_unlock_sock(sk); | |
85 | + sock_put(sk); | |
86 | return 0; | |
87 | } | |
88 | ||
89 | + bh_lock_sock(sk); | |
90 | + | |
91 | window = skb->data[20]; | |
92 | ||
93 | skb->sk = make; | |
94 | @@ -1014,6 +1018,7 @@ int nr_rx_frame(struct sk_buff *skb, str | |
95 | sk->sk_data_ready(sk); | |
96 | ||
97 | bh_unlock_sock(sk); | |
98 | + sock_put(sk); | |
99 | ||
100 | nr_insert_socket(make); | |
101 |