Skip to content

Commit 281782d

Browse files
Arseniy Krasnovgregkh
authored andcommitted
Bluetooth: hci_uart: Fix another race during initialization
commit 5df5daf upstream. Do not set 'HCI_UART_PROTO_READY' before call 'hci_uart_register_dev()'. Possible race is when someone calls 'hci_tty_uart_close()' after this bit is set, but 'hci_uart_register_dev()' wasn't done. This leads to access to uninitialized fields. To fix it let's set this bit after device was registered (as before patch c411c62cc133) and to fix previous problem let's add one more bit in addition to 'HCI_UART_PROTO_READY' which allows to perform power up without original bit set (pls see commit c411c62cc133). Crash backtrace from syzbot report: RIP: 0010:skb_queue_empty_lockless include/linux/skbuff.h:1887 [inline] RIP: 0010:skb_queue_purge_reason+0x6d/0x140 net/core/skbuff.c:3936 Call Trace: <TASK> skb_queue_purge include/linux/skbuff.h:3364 [inline] mrvl_close+0x2f/0x90 drivers/bluetooth/hci_mrvl.c:100 hci_uart_tty_close+0xb6/0x120 drivers/bluetooth/hci_ldisc.c:557 tty_ldisc_close drivers/tty/tty_ldisc.c:455 [inline] tty_ldisc_kill+0x66/0xc0 drivers/tty/tty_ldisc.c:613 tty_ldisc_release+0xc9/0x120 drivers/tty/tty_ldisc.c:781 tty_release_struct+0x10/0x80 drivers/tty/tty_io.c:1690 tty_release+0x4ef/0x640 drivers/tty/tty_io.c:1861 __fput+0x86/0x2a0 fs/file_table.c:450 task_work_run+0x82/0xb0 kernel/task_work.c:239 resume_user_mode_work include/linux/resume_user_mode.h:50 [inline] exit_to_user_mode_loop kernel/entry/common.c:114 [inline] exit_to_user_mode_prepare include/linux/entry-common.h:329 [inline] __syscall_exit_to_user_mode_work kernel/entry/common.c:207 [inline] syscall_exit_to_user_mode+0xa3/0x1b0 kernel/entry/common.c:218 do_syscall_64+0x9a/0x190 arch/x86/entry/common.c:89 entry_SYSCALL_64_after_hwframe+0x77/0x7f Signed-off-by: Arseniy Krasnov <[email protected]> Reported-by: [email protected] Tested-by: [email protected] Closes: https://lore.kernel.org/linux-bluetooth/[email protected]/ Fixes: 366ceff ("Bluetooth: hci_uart: fix race during initialization") Signed-off-by: Luiz Augusto von Dentz <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent f87626a commit 281782d

File tree

2 files changed

+15
-6
lines changed

2 files changed

+15
-6
lines changed

drivers/bluetooth/hci_ldisc.c

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu)
102102
if (!skb) {
103103
percpu_down_read(&hu->proto_lock);
104104

105-
if (test_bit(HCI_UART_PROTO_READY, &hu->flags))
105+
if (test_bit(HCI_UART_PROTO_READY, &hu->flags) ||
106+
test_bit(HCI_UART_PROTO_INIT, &hu->flags))
106107
skb = hu->proto->dequeue(hu);
107108

108109
percpu_up_read(&hu->proto_lock);
@@ -124,7 +125,8 @@ int hci_uart_tx_wakeup(struct hci_uart *hu)
124125
if (!percpu_down_read_trylock(&hu->proto_lock))
125126
return 0;
126127

127-
if (!test_bit(HCI_UART_PROTO_READY, &hu->flags))
128+
if (!test_bit(HCI_UART_PROTO_READY, &hu->flags) &&
129+
!test_bit(HCI_UART_PROTO_INIT, &hu->flags))
128130
goto no_schedule;
129131

130132
set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
@@ -278,7 +280,8 @@ static int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
278280

279281
percpu_down_read(&hu->proto_lock);
280282

281-
if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) {
283+
if (!test_bit(HCI_UART_PROTO_READY, &hu->flags) &&
284+
!test_bit(HCI_UART_PROTO_INIT, &hu->flags)) {
282285
percpu_up_read(&hu->proto_lock);
283286
return -EUNATCH;
284287
}
@@ -585,7 +588,8 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty)
585588
if (tty != hu->tty)
586589
return;
587590

588-
if (test_bit(HCI_UART_PROTO_READY, &hu->flags))
591+
if (test_bit(HCI_UART_PROTO_READY, &hu->flags) ||
592+
test_bit(HCI_UART_PROTO_INIT, &hu->flags))
589593
hci_uart_tx_wakeup(hu);
590594
}
591595

@@ -611,7 +615,8 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data,
611615

612616
percpu_down_read(&hu->proto_lock);
613617

614-
if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) {
618+
if (!test_bit(HCI_UART_PROTO_READY, &hu->flags) &&
619+
!test_bit(HCI_UART_PROTO_INIT, &hu->flags)) {
615620
percpu_up_read(&hu->proto_lock);
616621
return;
617622
}
@@ -707,13 +712,16 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id)
707712

708713
hu->proto = p;
709714

710-
set_bit(HCI_UART_PROTO_READY, &hu->flags);
715+
set_bit(HCI_UART_PROTO_INIT, &hu->flags);
711716

712717
err = hci_uart_register_dev(hu);
713718
if (err) {
714719
return err;
715720
}
716721

722+
set_bit(HCI_UART_PROTO_READY, &hu->flags);
723+
clear_bit(HCI_UART_PROTO_INIT, &hu->flags);
724+
717725
return 0;
718726
}
719727

drivers/bluetooth/hci_uart.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ struct hci_uart {
9090
#define HCI_UART_REGISTERED 1
9191
#define HCI_UART_PROTO_READY 2
9292
#define HCI_UART_NO_SUSPEND_NOTIFIER 3
93+
#define HCI_UART_PROTO_INIT 4
9394

9495
/* TX states */
9596
#define HCI_UART_SENDING 1

0 commit comments

Comments
 (0)