• Johan Hedberg's avatar
    Bluetooth: Fix race condition with HCI_RESET flag · 600b2150
    Johan Hedberg authored
    During the HCI init phase a completed request might be the last part of
    the setup procedure after which the actual init procedure starts. The
    init procedure begins with a call to hci_reset_req() which sets the
    HCI_RESET flag. The purpose of this flag is to make us ignore any
    updates to ncmd/cmd_cnt as long as we haven't received the command
    complete event for the HCI_Reset. There's a potential race with this
    however:
    
    	hci_req_cmd_complete(hdev, opcode, status);
    
    	if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) {
    		atomic_set(&hdev->cmd_cnt, 1);
    		if (!skb_queue_empty(&hdev->cmd_q))
    			queue_work(hdev->workqueue, &hdev->cmd_work);
    	}
    
    Since the hci_req_cmd_complete() will trigger the completion of the
    setup stage, it's possible that hci_reset_req() gets called before we
    try to read ev->ncmd and the HCI_RESET flag. Because of this the cmd_cnt
    would never be updated and the hci_reset_req() in practice ends up
    blocking itself.
    
    This patch fixes the issue by updating cmd_cnt before notifying the
    request completion, and then reading it again to determine whether the
    cmd_work should be queued or not.
    Signed-off-by: default avatarJohan Hedberg <johan.hedberg@intel.com>
    Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
    600b2150
hci_event.c 123 KB