Skip to content

Buffer overflow vulnerabilities in the Zephyr Bluetooth subsystem

Moderate
ceolin published GHSA-hmpr-px56-rvww Oct 24, 2023

Package

Zephyr

Affected versions

<= 3.4.0

Patched versions

None

Description

Summary

I spotted some additional buffer overflow vulnerabilities at the following locations in the Zephyr Bluetooth subsystem source code:
https://github.com/zephyrproject-rtos/zephyr/blob/main/subsys/bluetooth/controller/ll_sw/ull_adv.c
https://github.com/zephyrproject-rtos/zephyr/blob/main/subsys/bluetooth/host/hci_core.c
https://github.com/zephyrproject-rtos/zephyr/blob/main/subsys/bluetooth/host/iso.c

Details

Potential integer underflow due to ineffective assert check leading to buffer overflow in /subsys/bluetooth/controller/ll_sw/ull_adv.c:

uint8_t ll_adv_params_set(uint16_t interval, uint8_t adv_type,
		       uint8_t own_addr_type, uint8_t direct_addr_type,
		       uint8_t const *const direct_addr, uint8_t chan_map,
		       uint8_t filter_policy)
{
...
#if defined(CONFIG_BT_CTLR_AD_DATA_BACKUP)
	/* Backup the legacy AD Data if switching to legacy directed advertising
	 * or to Extended Advertising.
	 */
	if (((pdu->type == PDU_ADV_TYPE_DIRECT_IND) ||
	     (IS_ENABLED(CONFIG_BT_CTLR_ADV_EXT) &&
	      (pdu->type == PDU_ADV_TYPE_EXT_IND))) &&
	    (pdu_type_prev != PDU_ADV_TYPE_DIRECT_IND) &&
	    (!IS_ENABLED(CONFIG_BT_CTLR_ADV_EXT) ||
	     (pdu_type_prev != PDU_ADV_TYPE_EXT_IND))) {
		if (pdu->len == 0U) {
			adv->ad_data_backup.len = 0U;
		} else {
			LL_ASSERT(pdu->len >=
				  offsetof(struct pdu_adv_adv_ind, data)); /* VULN: assert */

			adv->ad_data_backup.len = pdu->len -
				offsetof(struct pdu_adv_adv_ind, data); /* VULN: integer underflow */
			memcpy(adv->ad_data_backup.data, pdu->adv_ind.data,
			       adv->ad_data_backup.len); /* VULN: buffer overflow */
		}
	}
#endif /* CONFIG_BT_CTLR_AD_DATA_BACKUP */
...

Buffer overflows due to assert in /subsys/bluetooth/host/hci_core.c:

#if defined(CONFIG_BT_CONN)
static void hci_acl(struct net_buf *buf)
{
	struct bt_hci_acl_hdr *hdr;
	uint16_t handle, len;
	struct bt_conn *conn;
	uint8_t flags;

	LOG_DBG("buf %p", buf);

	BT_ASSERT(buf->len >= sizeof(*hdr)); /* VULN: assert */

	hdr = net_buf_pull_mem(buf, sizeof(*hdr)); /* VULN: buffer overflow */
	len = sys_le16_to_cpu(hdr->len);
	handle = sys_le16_to_cpu(hdr->handle);
	flags = bt_acl_flags(handle);
...

static void hci_event(struct net_buf *buf)
{
	struct bt_hci_evt_hdr *hdr;

	BT_ASSERT(buf->len >= sizeof(*hdr)); /* VULN: assert */

	hdr = net_buf_pull_mem(buf, sizeof(*hdr)); /* VULN: buffer overflow */
	LOG_DBG("event 0x%02x", hdr->evt);
	BT_ASSERT(bt_hci_evt_get_flags(hdr->evt) & BT_HCI_EVT_FLAG_RECV); 

	handle_event(hdr->evt, buf, normal_events, ARRAY_SIZE(normal_events));

	net_buf_unref(buf);
}
...

void hci_event_prio(struct net_buf *buf)
{
	struct net_buf_simple_state state;
	struct bt_hci_evt_hdr *hdr;
	uint8_t evt_flags;

	net_buf_simple_save(&buf->b, &state);

	BT_ASSERT(buf->len >= sizeof(*hdr)); /* VULN: assert */

	hdr = net_buf_pull_mem(buf, sizeof(*hdr)); /* VULN: buffer overflow */
	evt_flags = bt_hci_evt_get_flags(hdr->evt);
	BT_ASSERT(evt_flags & BT_HCI_EVT_FLAG_RECV_PRIO);

	handle_event(hdr->evt, buf, prio_events, ARRAY_SIZE(prio_events));

	if (evt_flags & BT_HCI_EVT_FLAG_RECV) {
		net_buf_simple_restore(&buf->b, &state);
	} else {
		net_buf_unref(buf);
	}
}

Buffer overflow due to assert in /subsys/bluetooth/host/iso.c:

void hci_iso(struct net_buf *buf)
{
	struct bt_hci_iso_hdr *hdr;
	uint16_t handle, len;
	struct bt_conn *iso;
	uint8_t flags;

	BT_ISO_DATA_DBG("buf %p", buf);

	BT_ASSERT(buf->len >= sizeof(*hdr)); /* VULN: assert */

	hdr = net_buf_pull_mem(buf, sizeof(*hdr)); /* VULN: buffer overflow */
	len = bt_iso_hdr_len(sys_le16_to_cpu(hdr->len));
	handle = sys_le16_to_cpu(hdr->handle);
	flags = bt_iso_flags(handle);
...

In addition, the following helper functions in /subsys/net/buf_simple.c use assertions to check input, which renders checks ineffective:

  • net_buf_simple_add()
  • net_buf_simple_remove_mem()
  • net_buf_simple_push()
  • net_buf_simple_pull()
  • net_buf_simple_pull_mem()

PoC

I haven't tried to reproduce these potential vulnerabilities against a live install of the Zephyr OS.

Impact

If the unchecked input above is attacker-controlled and crosses a security boundary, the impact of buffer overflow vulnerabilities could range from denial of service to arbitrary code execution.

Patches

This has been fixed in:

Note that the first item in this advisory, the one involving /subsys/bluetooth/controller/ll_sw/ull_adv.c, has not been addressed because the pdu length that is being asserted on has been set by the controller itself prior to the execution of this code, and so it is not coming from the outside world. Hence, an assertion is correct in that particular case.

For more information

If you have any questions or comments about this advisory:

Severity

Moderate
6.3
/ 10

CVSS base metrics

Attack vector
Adjacent
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
Low
Integrity
Low
Availability
Low
CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L

CVE ID

CVE-2023-5753

Credits