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

Configure Feed

Select the types of activity you want to include in your feed.

Bluetooth: hci_uart: Fix another race during initialization

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 <avkrasnov@salutedevices.com>
Reported-by: syzbot+683f8cb11b94b1824c77@syzkaller.appspotmail.com
Tested-by: syzbot+683f8cb11b94b1824c77@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/linux-bluetooth/d159c57f-8490-4c26-79da-6ad3612c4a14@salutedevices.com/
Fixes: 366ceff495f9 ("Bluetooth: hci_uart: fix race during initialization")
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

authored by

Arseniy Krasnov and committed by
Luiz Augusto von Dentz
5df5dafc 366ceff4

+15 -6
+14 -6
drivers/bluetooth/hci_ldisc.c
··· 102 102 if (!skb) { 103 103 percpu_down_read(&hu->proto_lock); 104 104 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)) 106 107 skb = hu->proto->dequeue(hu); 107 108 108 109 percpu_up_read(&hu->proto_lock); ··· 125 124 if (!percpu_down_read_trylock(&hu->proto_lock)) 126 125 return 0; 127 126 128 - if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) 127 + if (!test_bit(HCI_UART_PROTO_READY, &hu->flags) && 128 + !test_bit(HCI_UART_PROTO_INIT, &hu->flags)) 129 129 goto no_schedule; 130 130 131 131 set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); ··· 280 278 281 279 percpu_down_read(&hu->proto_lock); 282 280 283 - if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) { 281 + if (!test_bit(HCI_UART_PROTO_READY, &hu->flags) && 282 + !test_bit(HCI_UART_PROTO_INIT, &hu->flags)) { 284 283 percpu_up_read(&hu->proto_lock); 285 284 return -EUNATCH; 286 285 } ··· 588 585 if (tty != hu->tty) 589 586 return; 590 587 591 - if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) 588 + if (test_bit(HCI_UART_PROTO_READY, &hu->flags) || 589 + test_bit(HCI_UART_PROTO_INIT, &hu->flags)) 592 590 hci_uart_tx_wakeup(hu); 593 591 } 594 592 ··· 615 611 616 612 percpu_down_read(&hu->proto_lock); 617 613 618 - if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) { 614 + if (!test_bit(HCI_UART_PROTO_READY, &hu->flags) && 615 + !test_bit(HCI_UART_PROTO_INIT, &hu->flags)) { 619 616 percpu_up_read(&hu->proto_lock); 620 617 return; 621 618 } ··· 712 707 713 708 hu->proto = p; 714 709 715 - set_bit(HCI_UART_PROTO_READY, &hu->flags); 710 + set_bit(HCI_UART_PROTO_INIT, &hu->flags); 716 711 717 712 err = hci_uart_register_dev(hu); 718 713 if (err) { 719 714 return err; 720 715 } 716 + 717 + set_bit(HCI_UART_PROTO_READY, &hu->flags); 718 + clear_bit(HCI_UART_PROTO_INIT, &hu->flags); 721 719 722 720 return 0; 723 721 }
+1
drivers/bluetooth/hci_uart.h
··· 90 90 #define HCI_UART_REGISTERED 1 91 91 #define HCI_UART_PROTO_READY 2 92 92 #define HCI_UART_NO_SUSPEND_NOTIFIER 3 93 + #define HCI_UART_PROTO_INIT 4 93 94 94 95 /* TX states */ 95 96 #define HCI_UART_SENDING 1