Bluetooth: remove unnecessary check on BT_CLOSED socks during accept
BT_CLOSED sockets are unlinked from teardown callback. Trying to unlink such sockets from bt_accept_dequeue may lead to NULL dereference as teardown callback does not hold lock for parent sock. bt_accept_unlink may be called from two threads, resulting in incorrect socket ref count. Return if parent is NULL. Change-Id: I957f0396079888549e082c34401322a6a8a80625 Signed-off-by: Rupesh Tatiya <rtatiya@codeaurora.org>
This commit is contained in:
parent
29eed682e0
commit
e1356ca909
|
@ -183,20 +183,25 @@ void bt_sock_unlink(struct bt_sock_list *l, struct sock *sk)
|
|||
}
|
||||
EXPORT_SYMBOL(bt_sock_unlink);
|
||||
|
||||
/* bt_accept_enqueue is used to hold sockets between L2CAP new connection and
|
||||
* connect confirmation calls only .
|
||||
*/
|
||||
void bt_accept_enqueue(struct sock *parent, struct sock *sk)
|
||||
{
|
||||
BT_DBG("parent %p, sk %p", parent, sk);
|
||||
|
||||
sock_hold(sk);
|
||||
list_add_tail(&bt_sk(sk)->accept_q, &bt_sk(parent)->accept_q);
|
||||
bt_sk(sk)->parent = parent;
|
||||
parent->sk_ack_backlog++;
|
||||
list_add_tail(&bt_sk(sk)->accept_q, &bt_sk(parent)->accept_q);
|
||||
}
|
||||
EXPORT_SYMBOL(bt_accept_enqueue);
|
||||
|
||||
void bt_accept_unlink(struct sock *sk)
|
||||
{
|
||||
BT_DBG("sk %p state %d", sk, sk->sk_state);
|
||||
if (!bt_sk(sk)->parent)
|
||||
return;
|
||||
|
||||
list_del_init(&bt_sk(sk)->accept_q);
|
||||
bt_sk(sk)->parent->sk_ack_backlog--;
|
||||
|
@ -205,6 +210,9 @@ void bt_accept_unlink(struct sock *sk)
|
|||
}
|
||||
EXPORT_SYMBOL(bt_accept_unlink);
|
||||
|
||||
/* bt_accept_dequeue is called to only on accept ioctl and it returns
|
||||
* sockets in BT_CONNECTED state
|
||||
*/
|
||||
struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
|
||||
{
|
||||
struct list_head *p, *n;
|
||||
|
@ -217,13 +225,6 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
|
|||
|
||||
lock_sock(sk);
|
||||
|
||||
/* FIXME: Is this check still needed */
|
||||
if (sk->sk_state == BT_CLOSED) {
|
||||
release_sock(sk);
|
||||
bt_accept_unlink(sk);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sk->sk_state == BT_CONNECTED || !newsock ||
|
||||
test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags)) {
|
||||
bt_accept_unlink(sk);
|
||||
|
|
|
@ -1040,6 +1040,9 @@ static void l2cap_sock_teardown_cb(struct l2cap_chan *chan, int err)
|
|||
|
||||
sk->sk_err = err;
|
||||
|
||||
/* parent can be valid only when L2CAP connection is confirmed
|
||||
* and accept ioctl call was scheduled on a timeout
|
||||
*/
|
||||
if (parent) {
|
||||
bt_accept_unlink(sk);
|
||||
parent->sk_data_ready(parent, 0);
|
||||
|
|
Loading…
Reference in New Issue