Skip to content

Latest commit

 

History

History
57 lines (37 loc) · 2.28 KB

CVE-2023-0397-hci-le_read_buffer_size-DoS.md

File metadata and controls

57 lines (37 loc) · 2.28 KB

DoS: Invalid Initialization in le_read_buffer_size_complete

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);

https://github.com/zephyrproject-rtos/zephyr/blob/426c51af7617ca576cec4bba6c30911be9f59a3a/subsys/bluetooth/host/hci_core.c#L2895-L2901

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; }

https://github.com/zephyrproject-rtos/zephyr/blob/426c51af7617ca576cec4bba6c30911be9f59a3a/subsys/bluetooth/host/hci_core.c#L2575-L2583

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);

https://github.com/zephyrproject-rtos/zephyr/blob/426c51af7617ca576cec4bba6c30911be9f59a3a/subsys/bluetooth/host/hci_core.c#L2588

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;
	}

https://github.com/zephyrproject-rtos/zephyr/blob/426c51af7617ca576cec4bba6c30911be9f59a3a/kernel/sem.c#L41-L51

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)