Skip to content

Commit dec2c92

Browse files
Dean Jenkinsholtmann
authored andcommitted
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 <[email protected]> Signed-off-by: Marcel Holtmann <[email protected]>
1 parent b56c7b2 commit dec2c92

File tree

2 files changed

+36
-5
lines changed

2 files changed

+36
-5
lines changed

drivers/bluetooth/hci_ldisc.c

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,12 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu)
114114
struct sk_buff *skb = hu->tx_skb;
115115

116116
if (!skb) {
117+
read_lock(&hu->proto_lock);
118+
117119
if (test_bit(HCI_UART_PROTO_READY, &hu->flags))
118120
skb = hu->proto->dequeue(hu);
121+
122+
read_unlock(&hu->proto_lock);
119123
} else {
120124
hu->tx_skb = NULL;
121125
}
@@ -125,18 +129,23 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu)
125129

126130
int hci_uart_tx_wakeup(struct hci_uart *hu)
127131
{
132+
read_lock(&hu->proto_lock);
133+
128134
if (!test_bit(HCI_UART_PROTO_READY, &hu->flags))
129-
return 0;
135+
goto no_schedule;
130136

131137
if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) {
132138
set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
133-
return 0;
139+
goto no_schedule;
134140
}
135141

136142
BT_DBG("");
137143

138144
schedule_work(&hu->write_work);
139145

146+
no_schedule:
147+
read_unlock(&hu->proto_lock);
148+
140149
return 0;
141150
}
142151
EXPORT_SYMBOL_GPL(hci_uart_tx_wakeup);
@@ -237,9 +246,13 @@ static int hci_uart_flush(struct hci_dev *hdev)
237246
tty_ldisc_flush(tty);
238247
tty_driver_flush_buffer(tty);
239248

249+
read_lock(&hu->proto_lock);
250+
240251
if (test_bit(HCI_UART_PROTO_READY, &hu->flags))
241252
hu->proto->flush(hu);
242253

254+
read_unlock(&hu->proto_lock);
255+
243256
return 0;
244257
}
245258

@@ -261,10 +274,15 @@ static int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
261274
BT_DBG("%s: type %d len %d", hdev->name, hci_skb_pkt_type(skb),
262275
skb->len);
263276

264-
if (!test_bit(HCI_UART_PROTO_READY, &hu->flags))
277+
read_lock(&hu->proto_lock);
278+
279+
if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) {
280+
read_unlock(&hu->proto_lock);
265281
return -EUNATCH;
282+
}
266283

267284
hu->proto->enqueue(hu, skb);
285+
read_unlock(&hu->proto_lock);
268286

269287
hci_uart_tx_wakeup(hu);
270288

@@ -460,6 +478,8 @@ static int hci_uart_tty_open(struct tty_struct *tty)
460478
INIT_WORK(&hu->init_ready, hci_uart_init_work);
461479
INIT_WORK(&hu->write_work, hci_uart_write_work);
462480

481+
rwlock_init(&hu->proto_lock);
482+
463483
/* Flush any pending characters in the driver */
464484
tty_driver_flush_buffer(tty);
465485

@@ -475,6 +495,7 @@ static void hci_uart_tty_close(struct tty_struct *tty)
475495
{
476496
struct hci_uart *hu = tty->disc_data;
477497
struct hci_dev *hdev;
498+
unsigned long flags;
478499

479500
BT_DBG("tty %p", tty);
480501

@@ -490,7 +511,11 @@ static void hci_uart_tty_close(struct tty_struct *tty)
490511

491512
cancel_work_sync(&hu->write_work);
492513

493-
if (test_and_clear_bit(HCI_UART_PROTO_READY, &hu->flags)) {
514+
if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) {
515+
write_lock_irqsave(&hu->proto_lock, flags);
516+
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
517+
write_unlock_irqrestore(&hu->proto_lock, flags);
518+
494519
if (hdev) {
495520
if (test_bit(HCI_UART_REGISTERED, &hu->flags))
496521
hci_unregister_dev(hdev);
@@ -549,13 +574,18 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data,
549574
if (!hu || tty != hu->tty)
550575
return;
551576

552-
if (!test_bit(HCI_UART_PROTO_READY, &hu->flags))
577+
read_lock(&hu->proto_lock);
578+
579+
if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) {
580+
read_unlock(&hu->proto_lock);
553581
return;
582+
}
554583

555584
/* It does not need a lock here as it is already protected by a mutex in
556585
* tty caller
557586
*/
558587
hu->proto->recv(hu, data, count);
588+
read_unlock(&hu->proto_lock);
559589

560590
if (hu->hdev)
561591
hu->hdev->stat.byte_rx += count;

drivers/bluetooth/hci_uart.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ struct hci_uart {
8787
struct work_struct write_work;
8888

8989
const struct hci_uart_proto *proto;
90+
rwlock_t proto_lock; /* Stop work for proto close */
9091
void *priv;
9192

9293
struct sk_buff *tx_skb;

0 commit comments

Comments
 (0)