• J
    Bluetooth: Fix L2CAP deadlock · 8a96f3cd
    Jukka Taimisto 提交于
    -[0x01 Introduction
    
    We have found a programming error causing a deadlock in Bluetooth subsystem
    of Linux kernel. The problem is caused by missing release_sock() call when
    L2CAP connection creation fails due full accept queue.
    
    The issue can be reproduced with 3.15-rc5 kernel and is also present in
    earlier kernels.
    
    -[0x02 Details
    
    The problem occurs when multiple L2CAP connections are created to a PSM which
    contains listening socket (like SDP) and left pending, for example,
    configuration (the underlying ACL link is not disconnected between
    connections).
    
    When L2CAP connection request is received and listening socket is found the
    l2cap_sock_new_connection_cb() function (net/bluetooth/l2cap_sock.c) is called.
    This function locks the 'parent' socket and then checks if the accept queue
    is full.
    
    1178         lock_sock(parent);
    1179
    1180         /* Check for backlog size */
    1181         if (sk_acceptq_is_full(parent)) {
    1182                 BT_DBG("backlog full %d", parent->sk_ack_backlog);
    1183                 return NULL;
    1184         }
    
    If case the accept queue is full NULL is returned, but the 'parent' socket
    is not released. Thus when next L2CAP connection request is received the code
    blocks on lock_sock() since the parent is still locked.
    
    Also note that for connections already established and waiting for
    configuration to complete a timeout will occur and l2cap_chan_timeout()
    (net/bluetooth/l2cap_core.c) will be called. All threads calling this
    function will also be blocked waiting for the channel mutex since the thread
    which is waiting on lock_sock() alread holds the channel mutex.
    
    We were able to reproduce this by sending continuously L2CAP connection
    request followed by disconnection request containing invalid CID. This left
    the created connections pending configuration.
    
    After the deadlock occurs it is impossible to kill bluetoothd, btmon will not
    get any more data etc. requiring reboot to recover.
    
    -[0x03 Fix
    
    Releasing the 'parent' socket when l2cap_sock_new_connection_cb() returns NULL
    seems to fix the issue.
    Signed-off-by: NJukka Taimisto <jtt@codenomicon.com>
    Reported-by: NTommi Mäkilä <tmakila@codenomicon.com>
    Signed-off-by: NJohan Hedberg <johan.hedberg@intel.com>
    Cc: stable@vger.kernel.org
    8a96f3cd
l2cap_sock.c 33.9 KB