Bluetooth: hci_uart: check for missing tty operations [Linux 4.19.64]

This Linux kernel change "Bluetooth: hci_uart: check for missing tty operations" is included in the Linux 4.19.64 release. This change is authored by Vladis Dronov <vdronov [at]> on Tue Jul 30 11:33:45 2019 +0200. The commit for this change in Linux stable tree is 5696621 (patch) which is from upstream commit b36a155. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream b36a155.

Bluetooth: hci_uart: check for missing tty operations

commit b36a1552d7319bbfd5cf7f08726c23c5c66d4f73 upstream.

Certain ttys operations (pty_unix98_ops) lack tiocmget() and tiocmset()
functions which are called by the certain HCI UART protocols (hci_ath,
hci_bcm, hci_intel, hci_mrvl, hci_qca) via hci_uart_set_flow_control()
or directly. This leads to an execution at NULL and can be triggered by
an unprivileged user. Fix this by adding a helper function and a check
for the missing tty operations in the protocols code.

This fixes CVE-2019-10207. The Fixes: lines list commits where calls to
tiocm[gs]et() or hci_uart_set_flow_control() were added to the HCI UART

Reported-by: [email protected]
Cc: [email protected] # v2.6.36+
Fixes: b3190df62861 ("Bluetooth: Support for Atheros AR300x serial chip")
Fixes: 118612fb9165 ("Bluetooth: hci_bcm: Add suspend/resume PM functions")
Fixes: ff2895592f0f ("Bluetooth: hci_intel: Add Intel baudrate configuration support")
Fixes: 162f812f23ba ("Bluetooth: hci_uart: Add Marvell support")
Fixes: fa9ad876b8e0 ("Bluetooth: hci_qca: Add support for Qualcomm Bluetooth chip wcn3990")
Signed-off-by: Vladis Dronov <[email protected]>
Signed-off-by: Marcel Holtmann <[email protected]>
Reviewed-by: Yu-Chen, Cho <[email protected]>
Tested-by: Yu-Chen, Cho <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>

There are 29 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/bluetooth/hci_ath.c   |  3 +++
 drivers/bluetooth/hci_bcm.c   |  3 +++
 drivers/bluetooth/hci_intel.c |  3 +++
 drivers/bluetooth/hci_ldisc.c | 13 +++++++++++++
 drivers/bluetooth/hci_mrvl.c  |  3 +++
 drivers/bluetooth/hci_qca.c   |  3 +++
 drivers/bluetooth/hci_uart.h  |  1 +
 7 files changed, 29 insertions(+)

diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
index d568fbd..2023592 100644
--- a/drivers/bluetooth/hci_ath.c
+++ b/drivers/bluetooth/hci_ath.c
@@ -112,6 +112,9 @@ static int ath_open(struct hci_uart *hu)

    BT_DBG("hu %p", hu);

+   if (!hci_uart_has_flow_control(hu))
+       return -EOPNOTSUPP;
    ath = kzalloc(sizeof(*ath), GFP_KERNEL);
    if (!ath)
        return -ENOMEM;
diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c
index 8001323..aa6b7ed 100644
--- a/drivers/bluetooth/hci_bcm.c
+++ b/drivers/bluetooth/hci_bcm.c
@@ -369,6 +369,9 @@ static int bcm_open(struct hci_uart *hu)

    bt_dev_dbg(hu->hdev, "hu %p", hu);

+   if (!hci_uart_has_flow_control(hu))
+       return -EOPNOTSUPP;
    bcm = kzalloc(sizeof(*bcm), GFP_KERNEL);
    if (!bcm)
        return -ENOMEM;
diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c
index 46ace32..e922852 100644
--- a/drivers/bluetooth/hci_intel.c
+++ b/drivers/bluetooth/hci_intel.c
@@ -406,6 +406,9 @@ static int intel_open(struct hci_uart *hu)

    BT_DBG("hu %p", hu);

+   if (!hci_uart_has_flow_control(hu))
+       return -EOPNOTSUPP;
    intel = kzalloc(sizeof(*intel), GFP_KERNEL);
    if (!intel)
        return -ENOMEM;
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index c915daf0..efeb813 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -299,6 +299,19 @@ static int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
    return 0;

+/* Check the underlying device or tty has flow control support */
+bool hci_uart_has_flow_control(struct hci_uart *hu)
+   /* serdev nodes check if the needed operations are present */
+   if (hu->serdev)
+       return true;
+   if (hu->tty->driver->ops->tiocmget && hu->tty->driver->ops->tiocmset)
+       return true;
+   return false;
 /* Flow control or un-flow control the device */
 void hci_uart_set_flow_control(struct hci_uart *hu, bool enable)
diff --git a/drivers/bluetooth/hci_mrvl.c b/drivers/bluetooth/hci_mrvl.c
index ffb0066..23791df 100644
--- a/drivers/bluetooth/hci_mrvl.c
+++ b/drivers/bluetooth/hci_mrvl.c
@@ -66,6 +66,9 @@ static int mrvl_open(struct hci_uart *hu)

    BT_DBG("hu %p", hu);

+   if (!hci_uart_has_flow_control(hu))
+       return -EOPNOTSUPP;
    mrvl = kzalloc(sizeof(*mrvl), GFP_KERNEL);
    if (!mrvl)
        return -ENOMEM;
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index 77004c2..f96e58d 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -450,6 +450,9 @@ static int qca_open(struct hci_uart *hu)

    BT_DBG("hu %p qca_open", hu);

+   if (!hci_uart_has_flow_control(hu))
+       return -EOPNOTSUPP;
    qca = kzalloc(sizeof(struct qca_data), GFP_KERNEL);
    if (!qca)
        return -ENOMEM;
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
index 00cab2f..067a610 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -118,6 +118,7 @@ struct hci_uart {
 int hci_uart_init_ready(struct hci_uart *hu);
 void hci_uart_init_work(struct work_struct *work);
 void hci_uart_set_baudrate(struct hci_uart *hu, unsigned int speed);
+bool hci_uart_has_flow_control(struct hci_uart *hu);
 void hci_uart_set_flow_control(struct hci_uart *hu, bool enable);
 void hci_uart_set_speeds(struct hci_uart *hu, unsigned int init_speed,
             unsigned int oper_speed);

Leave a Reply

Your email address will not be published. Required fields are marked *