Commit b85483c5 authored by Loic Poulain's avatar Loic Poulain Committed by Jiri Slaby

Bluetooth: hci_ldisc: Fix null pointer derefence in case of early data

commit 84cb3df0 upstream.

HCI_UART_PROTO_SET flag is set before hci_uart_set_proto call. If we
receive data from tty layer during this procedure, proto pointer may
not be assigned yet, leading to null pointer dereference in rx method
hci_uart_tty_receive.

This patch fixes this issue by introducing HCI_UART_PROTO_READY flag in
order to avoid any proto operation before proto opening and assignment.
Signed-off-by: default avatarLoic Poulain <loic.poulain@intel.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
Cc: Oliver Neukum <oliver@neukum.org>
Signed-off-by: default avatarJiri Slaby <jslaby@suse.cz>
parent 94e3230b
...@@ -225,7 +225,7 @@ static int hci_uart_flush(struct hci_dev *hdev) ...@@ -225,7 +225,7 @@ static int hci_uart_flush(struct hci_dev *hdev)
tty_ldisc_flush(tty); tty_ldisc_flush(tty);
tty_driver_flush_buffer(tty); tty_driver_flush_buffer(tty);
if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) if (test_bit(HCI_UART_PROTO_READY, &hu->flags))
hu->proto->flush(hu); hu->proto->flush(hu);
return 0; return 0;
...@@ -340,7 +340,7 @@ static void hci_uart_tty_close(struct tty_struct *tty) ...@@ -340,7 +340,7 @@ static void hci_uart_tty_close(struct tty_struct *tty)
cancel_work_sync(&hu->write_work); cancel_work_sync(&hu->write_work);
if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { if (test_and_clear_bit(HCI_UART_PROTO_READY, &hu->flags)) {
if (hdev) { if (hdev) {
if (test_bit(HCI_UART_REGISTERED, &hu->flags)) if (test_bit(HCI_UART_REGISTERED, &hu->flags))
hci_unregister_dev(hdev); hci_unregister_dev(hdev);
...@@ -348,6 +348,7 @@ static void hci_uart_tty_close(struct tty_struct *tty) ...@@ -348,6 +348,7 @@ static void hci_uart_tty_close(struct tty_struct *tty)
} }
hu->proto->close(hu); hu->proto->close(hu);
} }
clear_bit(HCI_UART_PROTO_SET, &hu->flags);
kfree(hu); kfree(hu);
} }
...@@ -374,7 +375,7 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty) ...@@ -374,7 +375,7 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty)
if (tty != hu->tty) if (tty != hu->tty)
return; return;
if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) if (test_bit(HCI_UART_PROTO_READY, &hu->flags))
hci_uart_tx_wakeup(hu); hci_uart_tx_wakeup(hu);
} }
...@@ -397,7 +398,7 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *f ...@@ -397,7 +398,7 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *f
if (!hu || tty != hu->tty) if (!hu || tty != hu->tty)
return; return;
if (!test_bit(HCI_UART_PROTO_SET, &hu->flags)) if (!test_bit(HCI_UART_PROTO_READY, &hu->flags))
return; return;
spin_lock(&hu->rx_lock); spin_lock(&hu->rx_lock);
...@@ -474,9 +475,11 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id) ...@@ -474,9 +475,11 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id)
return err; return err;
hu->proto = p; hu->proto = p;
set_bit(HCI_UART_PROTO_READY, &hu->flags);
err = hci_uart_register_dev(hu); err = hci_uart_register_dev(hu);
if (err) { if (err) {
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
p->close(hu); p->close(hu);
return err; return err;
} }
......
...@@ -81,6 +81,7 @@ struct hci_uart { ...@@ -81,6 +81,7 @@ struct hci_uart {
/* HCI_UART proto flag bits */ /* HCI_UART proto flag bits */
#define HCI_UART_PROTO_SET 0 #define HCI_UART_PROTO_SET 0
#define HCI_UART_REGISTERED 1 #define HCI_UART_REGISTERED 1
#define HCI_UART_PROTO_READY 2
/* TX states */ /* TX states */
#define HCI_UART_SENDING 1 #define HCI_UART_SENDING 1
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment