diff options
author | Vladis Dronov <vdronov@redhat.com> | 2019-07-30 05:33:45 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-07-31 16:17:33 -0400 |
commit | b36a1552d7319bbfd5cf7f08726c23c5c66d4f73 (patch) | |
tree | 591549f6646a88adedd924b4611ce6c514df17d6 | |
parent | 1b7e816fc80e668f0ccc8542cec20b9259abace1 (diff) |
Bluetooth: hci_uart: check for missing tty operations
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
protocols.
Link: https://syzkaller.appspot.com/bug?id=1b42faa2848963564a5b1b7f8c837ea7b55ffa50
Reported-by: syzbot+79337b501d6aa974d0f6@syzkaller.appspotmail.com
Cc: stable@vger.kernel.org # 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 <vdronov@redhat.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Reviewed-by: Yu-Chen, Cho <acho@suse.com>
Tested-by: Yu-Chen, Cho <acho@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/bluetooth/hci_ath.c | 3 | ||||
-rw-r--r-- | drivers/bluetooth/hci_bcm.c | 3 | ||||
-rw-r--r-- | drivers/bluetooth/hci_intel.c | 3 | ||||
-rw-r--r-- | drivers/bluetooth/hci_ldisc.c | 13 | ||||
-rw-r--r-- | drivers/bluetooth/hci_mrvl.c | 3 | ||||
-rw-r--r-- | drivers/bluetooth/hci_qca.c | 3 | ||||
-rw-r--r-- | drivers/bluetooth/hci_uart.h | 1 |
7 files changed, 29 insertions, 0 deletions
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c index a55be205b91a..dbfe34664633 100644 --- a/drivers/bluetooth/hci_ath.c +++ b/drivers/bluetooth/hci_ath.c | |||
@@ -98,6 +98,9 @@ static int ath_open(struct hci_uart *hu) | |||
98 | 98 | ||
99 | BT_DBG("hu %p", hu); | 99 | BT_DBG("hu %p", hu); |
100 | 100 | ||
101 | if (!hci_uart_has_flow_control(hu)) | ||
102 | return -EOPNOTSUPP; | ||
103 | |||
101 | ath = kzalloc(sizeof(*ath), GFP_KERNEL); | 104 | ath = kzalloc(sizeof(*ath), GFP_KERNEL); |
102 | if (!ath) | 105 | if (!ath) |
103 | return -ENOMEM; | 106 | return -ENOMEM; |
diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c index 8905ad2edde7..ae2624fce913 100644 --- a/drivers/bluetooth/hci_bcm.c +++ b/drivers/bluetooth/hci_bcm.c | |||
@@ -406,6 +406,9 @@ static int bcm_open(struct hci_uart *hu) | |||
406 | 406 | ||
407 | bt_dev_dbg(hu->hdev, "hu %p", hu); | 407 | bt_dev_dbg(hu->hdev, "hu %p", hu); |
408 | 408 | ||
409 | if (!hci_uart_has_flow_control(hu)) | ||
410 | return -EOPNOTSUPP; | ||
411 | |||
409 | bcm = kzalloc(sizeof(*bcm), GFP_KERNEL); | 412 | bcm = kzalloc(sizeof(*bcm), GFP_KERNEL); |
410 | if (!bcm) | 413 | if (!bcm) |
411 | return -ENOMEM; | 414 | return -ENOMEM; |
diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c index 207bae5e0d46..31f25153087d 100644 --- a/drivers/bluetooth/hci_intel.c +++ b/drivers/bluetooth/hci_intel.c | |||
@@ -391,6 +391,9 @@ static int intel_open(struct hci_uart *hu) | |||
391 | 391 | ||
392 | BT_DBG("hu %p", hu); | 392 | BT_DBG("hu %p", hu); |
393 | 393 | ||
394 | if (!hci_uart_has_flow_control(hu)) | ||
395 | return -EOPNOTSUPP; | ||
396 | |||
394 | intel = kzalloc(sizeof(*intel), GFP_KERNEL); | 397 | intel = kzalloc(sizeof(*intel), GFP_KERNEL); |
395 | if (!intel) | 398 | if (!intel) |
396 | return -ENOMEM; | 399 | return -ENOMEM; |
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 8950e07889fe..85a30fb9177b 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c | |||
@@ -292,6 +292,19 @@ static int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb) | |||
292 | return 0; | 292 | return 0; |
293 | } | 293 | } |
294 | 294 | ||
295 | /* Check the underlying device or tty has flow control support */ | ||
296 | bool hci_uart_has_flow_control(struct hci_uart *hu) | ||
297 | { | ||
298 | /* serdev nodes check if the needed operations are present */ | ||
299 | if (hu->serdev) | ||
300 | return true; | ||
301 | |||
302 | if (hu->tty->driver->ops->tiocmget && hu->tty->driver->ops->tiocmset) | ||
303 | return true; | ||
304 | |||
305 | return false; | ||
306 | } | ||
307 | |||
295 | /* Flow control or un-flow control the device */ | 308 | /* Flow control or un-flow control the device */ |
296 | void hci_uart_set_flow_control(struct hci_uart *hu, bool enable) | 309 | void hci_uart_set_flow_control(struct hci_uart *hu, bool enable) |
297 | { | 310 | { |
diff --git a/drivers/bluetooth/hci_mrvl.c b/drivers/bluetooth/hci_mrvl.c index f98e5cc343b2..fbc3f7c3a5c7 100644 --- a/drivers/bluetooth/hci_mrvl.c +++ b/drivers/bluetooth/hci_mrvl.c | |||
@@ -59,6 +59,9 @@ static int mrvl_open(struct hci_uart *hu) | |||
59 | 59 | ||
60 | BT_DBG("hu %p", hu); | 60 | BT_DBG("hu %p", hu); |
61 | 61 | ||
62 | if (!hci_uart_has_flow_control(hu)) | ||
63 | return -EOPNOTSUPP; | ||
64 | |||
62 | mrvl = kzalloc(sizeof(*mrvl), GFP_KERNEL); | 65 | mrvl = kzalloc(sizeof(*mrvl), GFP_KERNEL); |
63 | if (!mrvl) | 66 | if (!mrvl) |
64 | return -ENOMEM; | 67 | return -ENOMEM; |
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 9a5c9c1f9484..82a0a3691a63 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c | |||
@@ -473,6 +473,9 @@ static int qca_open(struct hci_uart *hu) | |||
473 | 473 | ||
474 | BT_DBG("hu %p qca_open", hu); | 474 | BT_DBG("hu %p qca_open", hu); |
475 | 475 | ||
476 | if (!hci_uart_has_flow_control(hu)) | ||
477 | return -EOPNOTSUPP; | ||
478 | |||
476 | qca = kzalloc(sizeof(struct qca_data), GFP_KERNEL); | 479 | qca = kzalloc(sizeof(struct qca_data), GFP_KERNEL); |
477 | if (!qca) | 480 | if (!qca) |
478 | return -ENOMEM; | 481 | return -ENOMEM; |
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index f11af3912ce6..6ab631101019 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h | |||
@@ -104,6 +104,7 @@ int hci_uart_wait_until_sent(struct hci_uart *hu); | |||
104 | int hci_uart_init_ready(struct hci_uart *hu); | 104 | int hci_uart_init_ready(struct hci_uart *hu); |
105 | void hci_uart_init_work(struct work_struct *work); | 105 | void hci_uart_init_work(struct work_struct *work); |
106 | void hci_uart_set_baudrate(struct hci_uart *hu, unsigned int speed); | 106 | void hci_uart_set_baudrate(struct hci_uart *hu, unsigned int speed); |
107 | bool hci_uart_has_flow_control(struct hci_uart *hu); | ||
107 | void hci_uart_set_flow_control(struct hci_uart *hu, bool enable); | 108 | void hci_uart_set_flow_control(struct hci_uart *hu, bool enable); |
108 | void hci_uart_set_speeds(struct hci_uart *hu, unsigned int init_speed, | 109 | void hci_uart_set_speeds(struct hci_uart *hu, unsigned int init_speed, |
109 | unsigned int oper_speed); | 110 | unsigned int oper_speed); |