Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Bluetooth: vhci: Fix race at creating hci device

hci_vhci driver creates a hci device object dynamically upon each
HCI_VENDOR_PKT write. Although it checks the already created object
and returns an error, it's still racy and may build multiple hci_dev
objects concurrently when parallel writes are performed, as the device
tracks only a single hci_dev object.

This patch introduces a mutex to protect against the concurrent device
creations.

Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>

authored by

Takashi Iwai and committed by
Marcel Holtmann
c7c999cb 60f5f5d3

+17 -6
+17 -6
drivers/bluetooth/hci_vhci.c
··· 50 50 wait_queue_head_t read_wait; 51 51 struct sk_buff_head readq; 52 52 53 + struct mutex open_mutex; 53 54 struct delayed_work open_timeout; 54 55 }; 55 56 ··· 88 87 return 0; 89 88 } 90 89 91 - static int vhci_create_device(struct vhci_data *data, __u8 opcode) 90 + static int __vhci_create_device(struct vhci_data *data, __u8 opcode) 92 91 { 93 92 struct hci_dev *hdev; 94 93 struct sk_buff *skb; 95 94 __u8 dev_type; 95 + 96 + if (data->hdev) 97 + return -EBADFD; 96 98 97 99 /* bits 0-1 are dev_type (BR/EDR or AMP) */ 98 100 dev_type = opcode & 0x03; ··· 155 151 return 0; 156 152 } 157 153 154 + static int vhci_create_device(struct vhci_data *data, __u8 opcode) 155 + { 156 + int err; 157 + 158 + mutex_lock(&data->open_mutex); 159 + err = __vhci_create_device(data, opcode); 160 + mutex_unlock(&data->open_mutex); 161 + 162 + return err; 163 + } 164 + 158 165 static inline ssize_t vhci_get_user(struct vhci_data *data, 159 166 struct iov_iter *from) 160 167 { ··· 205 190 206 191 case HCI_VENDOR_PKT: 207 192 cancel_delayed_work_sync(&data->open_timeout); 208 - 209 - if (data->hdev) { 210 - kfree_skb(skb); 211 - return -EBADFD; 212 - } 213 193 214 194 opcode = *((__u8 *) skb->data); 215 195 skb_pull(skb, 1); ··· 330 320 skb_queue_head_init(&data->readq); 331 321 init_waitqueue_head(&data->read_wait); 332 322 323 + mutex_init(&data->open_mutex); 333 324 INIT_DELAYED_WORK(&data->open_timeout, vhci_open_timeout); 334 325 335 326 file->private_data = data;