diff options
author | Mat Martineau <mathewm@codeaurora.org> | 2012-04-27 19:50:50 -0400 |
---|---|---|
committer | Gustavo Padovan <gustavo@padovan.org> | 2012-05-09 00:40:49 -0400 |
commit | 61d6ef3e3408cdf7e622646fb90a9f7f9560b943 (patch) | |
tree | b8a711d6cb948ec81749aa8b06a53a8e2dac0b37 /net/bluetooth | |
parent | dbd89fddc1f1fc96085deb164b7b9b2361241dd3 (diff) |
Bluetooth: Make better use of l2cap_chan reference counting
L2CAP sockets contain a pointer to l2cap_chan that needs to be
reference counted in order to prevent a possible dangling pointer when
the channel is freed.
There were a few other cases where an l2cap_chan pointer on the stack
was dereferenced after a call to l2cap_chan_del. Those pointers are
also now reference counted.
Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
Signed-off-by: Gustavo Padovan <gustavo@padovan.org>
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/l2cap_core.c | 6 | ||||
-rw-r--r-- | net/bluetooth/l2cap_sock.c | 3 |
2 files changed, 9 insertions, 0 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 1192c943bf8e..b854d284d42a 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
@@ -1256,6 +1256,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) | |||
1256 | 1256 | ||
1257 | /* Kill channels */ | 1257 | /* Kill channels */ |
1258 | list_for_each_entry_safe(chan, l, &conn->chan_l, list) { | 1258 | list_for_each_entry_safe(chan, l, &conn->chan_l, list) { |
1259 | l2cap_chan_hold(chan); | ||
1259 | l2cap_chan_lock(chan); | 1260 | l2cap_chan_lock(chan); |
1260 | 1261 | ||
1261 | l2cap_chan_del(chan, err); | 1262 | l2cap_chan_del(chan, err); |
@@ -1263,6 +1264,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) | |||
1263 | l2cap_chan_unlock(chan); | 1264 | l2cap_chan_unlock(chan); |
1264 | 1265 | ||
1265 | chan->ops->close(chan->data); | 1266 | chan->ops->close(chan->data); |
1267 | l2cap_chan_put(chan); | ||
1266 | } | 1268 | } |
1267 | 1269 | ||
1268 | mutex_unlock(&conn->chan_lock); | 1270 | mutex_unlock(&conn->chan_lock); |
@@ -3375,11 +3377,13 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd | |||
3375 | sk->sk_shutdown = SHUTDOWN_MASK; | 3377 | sk->sk_shutdown = SHUTDOWN_MASK; |
3376 | release_sock(sk); | 3378 | release_sock(sk); |
3377 | 3379 | ||
3380 | l2cap_chan_hold(chan); | ||
3378 | l2cap_chan_del(chan, ECONNRESET); | 3381 | l2cap_chan_del(chan, ECONNRESET); |
3379 | 3382 | ||
3380 | l2cap_chan_unlock(chan); | 3383 | l2cap_chan_unlock(chan); |
3381 | 3384 | ||
3382 | chan->ops->close(chan->data); | 3385 | chan->ops->close(chan->data); |
3386 | l2cap_chan_put(chan); | ||
3383 | 3387 | ||
3384 | mutex_unlock(&conn->chan_lock); | 3388 | mutex_unlock(&conn->chan_lock); |
3385 | 3389 | ||
@@ -3407,11 +3411,13 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd | |||
3407 | 3411 | ||
3408 | l2cap_chan_lock(chan); | 3412 | l2cap_chan_lock(chan); |
3409 | 3413 | ||
3414 | l2cap_chan_hold(chan); | ||
3410 | l2cap_chan_del(chan, 0); | 3415 | l2cap_chan_del(chan, 0); |
3411 | 3416 | ||
3412 | l2cap_chan_unlock(chan); | 3417 | l2cap_chan_unlock(chan); |
3413 | 3418 | ||
3414 | chan->ops->close(chan->data); | 3419 | chan->ops->close(chan->data); |
3420 | l2cap_chan_put(chan); | ||
3415 | 3421 | ||
3416 | mutex_unlock(&conn->chan_lock); | 3422 | mutex_unlock(&conn->chan_lock); |
3417 | 3423 | ||
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 2b5e7e81c3c0..6bf8ff75d95f 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c | |||
@@ -956,6 +956,7 @@ static void l2cap_sock_destruct(struct sock *sk) | |||
956 | { | 956 | { |
957 | BT_DBG("sk %p", sk); | 957 | BT_DBG("sk %p", sk); |
958 | 958 | ||
959 | l2cap_chan_put(l2cap_pi(sk)->chan); | ||
959 | if (l2cap_pi(sk)->rx_busy_skb) { | 960 | if (l2cap_pi(sk)->rx_busy_skb) { |
960 | kfree_skb(l2cap_pi(sk)->rx_busy_skb); | 961 | kfree_skb(l2cap_pi(sk)->rx_busy_skb); |
961 | l2cap_pi(sk)->rx_busy_skb = NULL; | 962 | l2cap_pi(sk)->rx_busy_skb = NULL; |
@@ -1057,6 +1058,8 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p | |||
1057 | return NULL; | 1058 | return NULL; |
1058 | } | 1059 | } |
1059 | 1060 | ||
1061 | l2cap_chan_hold(chan); | ||
1062 | |||
1060 | chan->sk = sk; | 1063 | chan->sk = sk; |
1061 | 1064 | ||
1062 | l2cap_pi(sk)->chan = chan; | 1065 | l2cap_pi(sk)->chan = chan; |