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

Subsystems: bluetooth drivers, the rest

STALE3810d

2 messages, 2 authors, 2016-03-11 · open the first message on its own page

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

From: Loic Poulain <hidden>
Date: 2016-03-11 11:19:26

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 by setting the HCI_UART_PROTO_SET flag once proto
is fully initialized and introduces HCI_UART_PROTO_BUSY flag to avoid
concurrent call to set_proto. We could have fixed this with a mutex as
well.

Signed-off-by: Loic Poulain <redacted>
---
 drivers/bluetooth/hci_ldisc.c | 16 +++++++++-------
 drivers/bluetooth/hci_uart.h  |  1 +
 2 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index c00168a..fab2641 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -638,6 +638,7 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id)
 		return err;
 
 	hu->proto = p;
+	set_bit(HCI_UART_PROTO_SET, &hu->flags);
 
 	err = hci_uart_register_dev(hu);
 	if (err) {
@@ -692,14 +693,15 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file *file,
 
 	switch (cmd) {
 	case HCIUARTSETPROTO:
-		if (!test_and_set_bit(HCI_UART_PROTO_SET, &hu->flags)) {
-			err = hci_uart_set_proto(hu, arg);
-			if (err) {
-				clear_bit(HCI_UART_PROTO_SET, &hu->flags);
-				return err;
-			}
-		} else
+		if (test_and_set_bit(HCI_UART_PROTO_BUSY, &hu->flags))
 			return -EBUSY;
+		if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
+			err = -EBUSY;
+		else
+			err = hci_uart_set_proto(hu, arg);
+		clear_bit(HCI_UART_PROTO_BUSY, &hu->flags);
+		if (err)
+			return err;
 		break;
 
 	case HCIUARTGETPROTO:
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
index 4814ff0..1a97fa9 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -95,6 +95,7 @@ struct hci_uart {
 /* HCI_UART proto flag bits */
 #define HCI_UART_PROTO_SET	0
 #define HCI_UART_REGISTERED	1
+#define HCI_UART_PROTO_BUSY	2
 
 /* TX states  */
 #define HCI_UART_SENDING	1
-- 
1.9.1

Re: [PATCH] Bluetooth: hci_ldisc: Fix null pointer derefence in case of early data

From: Marcel Holtmann <marcel@holtmann.org>
Date: 2016-03-11 15:34:24

Hi Loic,
quoted hunk
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 by setting the HCI_UART_PROTO_SET flag once proto
is fully initialized and introduces HCI_UART_PROTO_BUSY flag to avoid
concurrent call to set_proto. We could have fixed this with a mutex as
well.

Signed-off-by: Loic Poulain <redacted>
---
drivers/bluetooth/hci_ldisc.c | 16 +++++++++-------
drivers/bluetooth/hci_uart.h  |  1 +
2 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index c00168a..fab2641 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -638,6 +638,7 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id)
		return err;

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

	err = hci_uart_register_dev(hu);
	if (err) {
@@ -692,14 +693,15 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file *file,
	switch (cmd) {
	case HCIUARTSETPROTO:
-		if (!test_and_set_bit(HCI_UART_PROTO_SET, &hu->flags)) {
-			err = hci_uart_set_proto(hu, arg);
-			if (err) {
-				clear_bit(HCI_UART_PROTO_SET, &hu->flags);
-				return err;
-			}
-		} else
+		if (test_and_set_bit(HCI_UART_PROTO_BUSY, &hu->flags))
			return -EBUSY;
+		if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
+			err = -EBUSY;
+		else
+			err = hci_uart_set_proto(hu, arg);
+		clear_bit(HCI_UART_PROTO_BUSY, &hu->flags);
+		if (err)
+			return err;
		break;
I do not like overloading the PROTO_SET flag since that is only suppose to be used when the ioctl has been called. I think what we really want to introduce a PROTO_READY and set + check that later on.

Regards

Marcel
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help