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;
}
|
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
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
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:zephyr/subsys/bluetooth/host/hci_core.c
Lines 2895 to 2901 in 426c51a
le_read_buffer_size_complete
casts the response into abt_hci_rp_le_read_buffer_size
struct but only checks thatle_max_len
is set:zephyr/subsys/bluetooth/host/hci_core.c
Lines 2575 to 2583 in 426c51a
it passes the unchecked
rp->le_max_num
intok_sem_init
:zephyr/subsys/bluetooth/host/hci_core.c
Line 2588 in 426c51a
However
k_sem_init
requires the limit to be greater than zero or skips the initialization otherwise:zephyr/kernel/sem.c
Lines 41 to 51 in 426c51a
This ultimately leads to a nullptr-deref when the
wait_q
of the semaphore is used inz_impl_k_sem_take
.Impact
Proposed Fix
rp->le_max_num
is a valid value inle_read_buffer_size_complete
max(1, rp->le_max_num)
Patches
For more information
If you have any questions or comments about this advisory:
embargo: 2023-01-03