diff options
author | Jeremy Cline <jcline@redhat.com> | 2019-02-06 12:54:16 -0500 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2019-02-18 07:54:53 -0500 |
commit | 32a7b4cbe93b0a0ef7e63d31ca69ce54736c4412 (patch) | |
tree | 7d576c23965430a2d3b65ff5ec107e867f7e1e07 /drivers/bluetooth | |
parent | 035a960e7a279a59d74585105dcd263559d74f24 (diff) |
Bluetooth: hci_ldisc: Initialize hci_dev before open()
The hci_dev struct hdev is referenced in work queues and timers started
by open() in some protocols. This creates a race between the
initialization function and the work or timer which can result hdev
being dereferenced while it is still null.
The syzbot report contains a reliable reproducer which causes a null
pointer dereference of hdev in hci_uart_write_work() by making the
memory allocation for hdev fail.
To fix this, ensure hdev is valid from before calling a protocol's
open() until after calling a protocol's close().
Reported-by: syzbot+257790c15bcdef6fe00c@syzkaller.appspotmail.com
Signed-off-by: Jeremy Cline <jcline@redhat.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'drivers/bluetooth')
-rw-r--r-- | drivers/bluetooth/hci_ldisc.c | 21 |
1 files changed, 14 insertions, 7 deletions
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index fbf7b4df23ab..4918fefc4a6f 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c | |||
@@ -207,11 +207,11 @@ void hci_uart_init_work(struct work_struct *work) | |||
207 | err = hci_register_dev(hu->hdev); | 207 | err = hci_register_dev(hu->hdev); |
208 | if (err < 0) { | 208 | if (err < 0) { |
209 | BT_ERR("Can't register HCI device"); | 209 | BT_ERR("Can't register HCI device"); |
210 | clear_bit(HCI_UART_PROTO_READY, &hu->flags); | ||
211 | hu->proto->close(hu); | ||
210 | hdev = hu->hdev; | 212 | hdev = hu->hdev; |
211 | hu->hdev = NULL; | 213 | hu->hdev = NULL; |
212 | hci_free_dev(hdev); | 214 | hci_free_dev(hdev); |
213 | clear_bit(HCI_UART_PROTO_READY, &hu->flags); | ||
214 | hu->proto->close(hu); | ||
215 | return; | 215 | return; |
216 | } | 216 | } |
217 | 217 | ||
@@ -616,6 +616,7 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, | |||
616 | static int hci_uart_register_dev(struct hci_uart *hu) | 616 | static int hci_uart_register_dev(struct hci_uart *hu) |
617 | { | 617 | { |
618 | struct hci_dev *hdev; | 618 | struct hci_dev *hdev; |
619 | int err; | ||
619 | 620 | ||
620 | BT_DBG(""); | 621 | BT_DBG(""); |
621 | 622 | ||
@@ -659,11 +660,22 @@ static int hci_uart_register_dev(struct hci_uart *hu) | |||
659 | else | 660 | else |
660 | hdev->dev_type = HCI_PRIMARY; | 661 | hdev->dev_type = HCI_PRIMARY; |
661 | 662 | ||
663 | /* Only call open() for the protocol after hdev is fully initialized as | ||
664 | * open() (or a timer/workqueue it starts) may attempt to reference it. | ||
665 | */ | ||
666 | err = hu->proto->open(hu); | ||
667 | if (err) { | ||
668 | hu->hdev = NULL; | ||
669 | hci_free_dev(hdev); | ||
670 | return err; | ||
671 | } | ||
672 | |||
662 | if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags)) | 673 | if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags)) |
663 | return 0; | 674 | return 0; |
664 | 675 | ||
665 | if (hci_register_dev(hdev) < 0) { | 676 | if (hci_register_dev(hdev) < 0) { |
666 | BT_ERR("Can't register HCI device"); | 677 | BT_ERR("Can't register HCI device"); |
678 | hu->proto->close(hu); | ||
667 | hu->hdev = NULL; | 679 | hu->hdev = NULL; |
668 | hci_free_dev(hdev); | 680 | hci_free_dev(hdev); |
669 | return -ENODEV; | 681 | return -ENODEV; |
@@ -683,17 +695,12 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id) | |||
683 | if (!p) | 695 | if (!p) |
684 | return -EPROTONOSUPPORT; | 696 | return -EPROTONOSUPPORT; |
685 | 697 | ||
686 | err = p->open(hu); | ||
687 | if (err) | ||
688 | return err; | ||
689 | |||
690 | hu->proto = p; | 698 | hu->proto = p; |
691 | set_bit(HCI_UART_PROTO_READY, &hu->flags); | 699 | set_bit(HCI_UART_PROTO_READY, &hu->flags); |
692 | 700 | ||
693 | err = hci_uart_register_dev(hu); | 701 | err = hci_uart_register_dev(hu); |
694 | if (err) { | 702 | if (err) { |
695 | clear_bit(HCI_UART_PROTO_READY, &hu->flags); | 703 | clear_bit(HCI_UART_PROTO_READY, &hu->flags); |
696 | p->close(hu); | ||
697 | return err; | 704 | return err; |
698 | } | 705 | } |
699 | 706 | ||