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

Bluetooth: hci_ldisc: Use rwlocking to avoid closing proto races

When HCI_UART_PROTO_READY is in the set state, the Data Link protocol
layer (proto) is bound to the HCI UART driver. This state allows the
registered proto function pointers to be used by the HCI UART driver.

When unbinding (closing) the Data Link protocol layer, the proto
function pointers much be prevented from being used immediately before
running the proto close function pointer. Otherwise, there is a risk
that a proto non-close function pointer is used during or after the
proto close function pointer is used. The consequences are likely to
be a kernel crash because the proto close function pointer will free
resources used in the Data Link protocol layer.

Therefore, add a reader writer lock (rwlock) solution to prevent the
close proto function pointer from running by using write_lock_irqsave()
whilst the other proto function pointers are protected using
read_lock(). This means HCI_UART_PROTO_READY can safely be cleared
in the knowledge that no proto function pointers are running.

When flag HCI_UART_PROTO_READY is put into the clear state,
proto close function pointer can safely be run. Note
flag HCI_UART_PROTO_SET being in the set state prevents the proto
open function pointer from being run so there is no race condition
between proto open and close function pointers.

Signed-off-by: Dean Jenkins <Dean_Jenkins@mentor.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>

authored by

Dean Jenkins and committed by
Marcel Holtmann
dec2c928 b56c7b25

+36 -5
+35 -5
drivers/bluetooth/hci_ldisc.c
··· 114 114 struct sk_buff *skb = hu->tx_skb; 115 115 116 116 if (!skb) { 117 + read_lock(&hu->proto_lock); 118 + 117 119 if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) 118 120 skb = hu->proto->dequeue(hu); 121 + 122 + read_unlock(&hu->proto_lock); 119 123 } else { 120 124 hu->tx_skb = NULL; 121 125 } ··· 129 125 130 126 int hci_uart_tx_wakeup(struct hci_uart *hu) 131 127 { 128 + read_lock(&hu->proto_lock); 129 + 132 130 if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) 133 - return 0; 131 + goto no_schedule; 134 132 135 133 if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) { 136 134 set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); 137 - return 0; 135 + goto no_schedule; 138 136 } 139 137 140 138 BT_DBG(""); 141 139 142 140 schedule_work(&hu->write_work); 141 + 142 + no_schedule: 143 + read_unlock(&hu->proto_lock); 143 144 144 145 return 0; 145 146 } ··· 246 237 tty_ldisc_flush(tty); 247 238 tty_driver_flush_buffer(tty); 248 239 240 + read_lock(&hu->proto_lock); 241 + 249 242 if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) 250 243 hu->proto->flush(hu); 244 + 245 + read_unlock(&hu->proto_lock); 251 246 252 247 return 0; 253 248 } ··· 274 261 BT_DBG("%s: type %d len %d", hdev->name, hci_skb_pkt_type(skb), 275 262 skb->len); 276 263 277 - if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) 264 + read_lock(&hu->proto_lock); 265 + 266 + if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) { 267 + read_unlock(&hu->proto_lock); 278 268 return -EUNATCH; 269 + } 279 270 280 271 hu->proto->enqueue(hu, skb); 272 + read_unlock(&hu->proto_lock); 281 273 282 274 hci_uart_tx_wakeup(hu); 283 275 ··· 478 460 INIT_WORK(&hu->init_ready, hci_uart_init_work); 479 461 INIT_WORK(&hu->write_work, hci_uart_write_work); 480 462 463 + rwlock_init(&hu->proto_lock); 464 + 481 465 /* Flush any pending characters in the driver */ 482 466 tty_driver_flush_buffer(tty); 483 467 ··· 495 475 { 496 476 struct hci_uart *hu = tty->disc_data; 497 477 struct hci_dev *hdev; 478 + unsigned long flags; 498 479 499 480 BT_DBG("tty %p", tty); 500 481 ··· 511 490 512 491 cancel_work_sync(&hu->write_work); 513 492 514 - if (test_and_clear_bit(HCI_UART_PROTO_READY, &hu->flags)) { 493 + if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) { 494 + write_lock_irqsave(&hu->proto_lock, flags); 495 + clear_bit(HCI_UART_PROTO_READY, &hu->flags); 496 + write_unlock_irqrestore(&hu->proto_lock, flags); 497 + 515 498 if (hdev) { 516 499 if (test_bit(HCI_UART_REGISTERED, &hu->flags)) 517 500 hci_unregister_dev(hdev); ··· 574 549 if (!hu || tty != hu->tty) 575 550 return; 576 551 577 - if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) 552 + read_lock(&hu->proto_lock); 553 + 554 + if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) { 555 + read_unlock(&hu->proto_lock); 578 556 return; 557 + } 579 558 580 559 /* It does not need a lock here as it is already protected by a mutex in 581 560 * tty caller 582 561 */ 583 562 hu->proto->recv(hu, data, count); 563 + read_unlock(&hu->proto_lock); 584 564 585 565 if (hu->hdev) 586 566 hu->hdev->stat.byte_rx += count;
+1
drivers/bluetooth/hci_uart.h
··· 87 87 struct work_struct write_work; 88 88 89 89 const struct hci_uart_proto *proto; 90 + rwlock_t proto_lock; /* Stop work for proto close */ 90 91 void *priv; 91 92 92 93 struct sk_buff *tx_skb;