Skip to content

DoS: Invalid Initialization in `le_read_buffer_size_complete`

Moderate
ceolin published GHSA-wc2h-h868-q7hj Jan 19, 2023

Package

zephyr (west)

Affected versions

<= 3.2

Patched versions

None

Description

Summary

A malicious / defect bluetooth controller can cause a Denial of Service due to unchecked input in le_read_buffer_size_complete.

Description

LE Buffer Size is requested from bluehtooh controller and passed into le_read_buffer_size_complete without further checks:

bt_hci_cmd_send_sync(BT_HCI_OP_LE_READ_BUFFER_SIZE, NULL, &rsp);
le_read_buffer_size_complete(rsp);

/* Read LE Buffer Size */
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_READ_BUFFER_SIZE,
NULL, &rsp);
if (err) {
return err;
}
le_read_buffer_size_complete(rsp);

le_read_buffer_size_complete casts the response into a bt_hci_rp_le_read_buffer_size struct but only checks that le_max_len is set:

static void le_read_buffer_size_complete(struct net_buf *buf) {
	struct bt_hci_rp_le_read_buffer_size *rp = (void *)buf->data;
	bt_dev.le.acl_mtu = sys_le16_to_cpu(rp->le_max_len);
	if (!bt_dev.le.acl_mtu) { return; }

struct bt_hci_rp_le_read_buffer_size *rp = (void *)buf->data;
BT_DBG("status 0x%02x", rp->status);
#if defined(CONFIG_BT_CONN)
bt_dev.le.acl_mtu = sys_le16_to_cpu(rp->le_max_len);
if (!bt_dev.le.acl_mtu) {
return;
}

it passes the unchecked rp->le_max_num into k_sem_init:

k_sem_init(&bt_dev.le.acl_pkts, rp->le_max_num, rp->le_max_num);

k_sem_init(&bt_dev.le.acl_pkts, rp->le_max_num, rp->le_max_num);

However k_sem_init requires the limit to be greater than zero or skips the initialization otherwise:

int z_impl_k_sem_init(struct k_sem *sem, unsigned int initial_count, unsigned int limit) {
	CHECKIF(limit == 0U || limit > K_SEM_MAX_LIMIT || initial_count > limit) {
		return -EINVAL;
	}

zephyr/kernel/sem.c

Lines 41 to 51 in 426c51a

int z_impl_k_sem_init(struct k_sem *sem, unsigned int initial_count,
unsigned int limit)
{
/*
* Limit cannot be zero and count cannot be greater than limit
*/
CHECKIF(limit == 0U || limit > K_SEM_MAX_LIMIT || initial_count > limit) {
SYS_PORT_TRACING_OBJ_FUNC(k_sem, init, sem, -EINVAL);
return -EINVAL;
}

This ultimately leads to a nullptr-deref when the wait_q of the semaphore is used in z_impl_k_sem_take.

Impact

  • Denial of Service

Proposed Fix

  • Verify rp->le_max_num is a valid value in le_read_buffer_size_complete
    • Either return an error if not or use max(1, rp->le_max_num)

Patches

For more information

If you have any questions or comments about this advisory:

embargo: 2023-01-03

Severity

Moderate
6.0
/ 10

CVSS base metrics

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

CVE ID

CVE-2023-0397

Weaknesses