Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f67202f7 authored by Jeremy Cline's avatar Jeremy Cline Committed by Greg Kroah-Hartman
Browse files

Bluetooth: hci_ldisc: Initialize hci_dev before open()



commit 32a7b4cbe93b0a0ef7e63d31ca69ce54736c4412 upstream.

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: default avatar <syzbot+257790c15bcdef6fe00c@syzkaller.appspotmail.com>
Signed-off-by: default avatarJeremy Cline <jcline@redhat.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 4b390513
Loading
Loading
Loading
Loading
+14 −7
Original line number Diff line number Diff line
@@ -207,11 +207,11 @@ void hci_uart_init_work(struct work_struct *work)
	err = hci_register_dev(hu->hdev);
	if (err < 0) {
		BT_ERR("Can't register HCI device");
		clear_bit(HCI_UART_PROTO_READY, &hu->flags);
		hu->proto->close(hu);
		hdev = hu->hdev;
		hu->hdev = NULL;
		hci_free_dev(hdev);
		clear_bit(HCI_UART_PROTO_READY, &hu->flags);
		hu->proto->close(hu);
		return;
	}

@@ -616,6 +616,7 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data,
static int hci_uart_register_dev(struct hci_uart *hu)
{
	struct hci_dev *hdev;
	int err;

	BT_DBG("");

@@ -659,11 +660,22 @@ static int hci_uart_register_dev(struct hci_uart *hu)
	else
		hdev->dev_type = HCI_PRIMARY;

	/* Only call open() for the protocol after hdev is fully initialized as
	 * open() (or a timer/workqueue it starts) may attempt to reference it.
	 */
	err = hu->proto->open(hu);
	if (err) {
		hu->hdev = NULL;
		hci_free_dev(hdev);
		return err;
	}

	if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags))
		return 0;

	if (hci_register_dev(hdev) < 0) {
		BT_ERR("Can't register HCI device");
		hu->proto->close(hu);
		hu->hdev = NULL;
		hci_free_dev(hdev);
		return -ENODEV;
@@ -683,17 +695,12 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id)
	if (!p)
		return -EPROTONOSUPPORT;

	err = p->open(hu);
	if (err)
		return err;

	hu->proto = p;
	set_bit(HCI_UART_PROTO_READY, &hu->flags);

	err = hci_uart_register_dev(hu);
	if (err) {
		clear_bit(HCI_UART_PROTO_READY, &hu->flags);
		p->close(hu);
		return err;
	}