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

This Linux kernel change "Bluetooth: hci_uart: check for missing tty operations" is included in the Linux 4.4.187 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 37fb924 (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

Cc: # 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 <>
Signed-off-by: Marcel Holtmann <>
Reviewed-by: Yu-Chen, Cho <>
Tested-by: Yu-Chen, Cho <>
Signed-off-by: Linus Torvalds <>
Signed-off-by: Greg Kroah-Hartman <>

There are 19 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 | 9 +++++++++
 drivers/bluetooth/hci_uart.h  | 1 +
 5 files changed, 19 insertions(+)

diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
index d776dfd..16f2131 100644
--- a/drivers/bluetooth/hci_ath.c
+++ b/drivers/bluetooth/hci_ath.c
@@ -101,6 +101,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 f9b569e..20a1b4d 100644
--- a/drivers/bluetooth/hci_bcm.c
+++ b/drivers/bluetooth/hci_bcm.c
@@ -279,6 +279,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 0c63fce..929674e 100644
--- a/drivers/bluetooth/hci_intel.c
+++ b/drivers/bluetooth/hci_intel.c
@@ -407,6 +407,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 96bcec5..d5db233 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -257,6 +257,15 @@ 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)
+   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_uart.h b/drivers/bluetooth/hci_uart.h
index 82c92f1..ce00c02 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -105,6 +105,7 @@ struct hci_uart {
 int hci_uart_init_ready(struct hci_uart *hu);
 void hci_uart_init_tty(struct hci_uart *hu);
 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 *