Skip to content

Improper validation of LL_CHANNEL_MAP_IND allows remote DoS via reachable assertion #2203

@wqqqy

Description

@wqqqy

Dear developers,

We recently identified a potential issue in the Nimble controller. Please let us know if you need any additional information. We would also be happy to submit a patch to help resolve this issue.

Please kindly find the description and suggested fix below.

Description

Apache Mynewt NimBLE BLE Controller contains an improper input validation vulnerability in the handling of LL_CHANNEL_MAP_IND control PDUs.

In ble_ll_ctrl_rx_chanmap_req():

static int
ble_ll_ctrl_rx_chanmap_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
{
uint16_t instant;
uint16_t conn_events;
#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL)
if (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) {
return BLE_LL_CTRL_UNKNOWN_RSP;
}
#endif
/* If instant is in the past, we have to end the connection */
instant = get_le16(dptr + BLE_LL_CHAN_MAP_LEN);
conn_events = (instant - connsm->event_cntr) & 0xFFFF;
if (conn_events >= 32767) {
ble_ll_conn_timeout(connsm, BLE_ERR_INSTANT_PASSED);
} else {
connsm->chanmap_instant = instant;
memcpy(connsm->req_chanmap, dptr, BLE_LL_CHAN_MAP_LEN);
connsm->flags.chanmap_update_sched = 1;
}
return BLE_ERR_MAX;

the received 5-byte channel map (dptr[0..4]) is copied directly into connsm->req_chanmap using memcpy() without validation.

No validation is performed to ensure that the channel map contains a valid number of enabled data channels.

Impact

An attacker acting as a malicious or non-compliant central device can send a crafted LL_CHANNEL_MAP_IND control PDU with an invalid channel map (ChM) field consisting entirely of zeros.

When the channel map is applied, the controller executes the following path:

ble_ll_conn_next_event()
  → ble_ll_conn_calc_dci()
    → ble_ll_conn_calc_dci_csa1()
      → ble_ll_utils_remapped_channel()

Inside ble_ll_utils_remapped_channel():

ble_ll_utils_chan_map_remap(const uint8_t *chan_map, uint8_t remap_index)
{
uint8_t cntr;
uint8_t mask;
uint8_t usable_chans;
uint8_t chan;
int i, j;
/* NOTE: possible to build a map but this would use memory. For now,
* we just calculate
* Iterate through channel map to find this channel
*/
chan = 0;
cntr = 0;
for (i = 0; i < BLE_LL_CHMAP_LEN; i++) {
usable_chans = chan_map[i];
if (usable_chans != 0) {
mask = 0x01;
for (j = 0; j < 8; j++) {
if (usable_chans & mask) {
if (cntr == remap_index) {
return (chan + j);
}
++cntr;
}
mask <<= 1;
}
}
chan += 8;
}
/* we should never reach here */
BLE_LL_ASSERT(0);
return 0;
}

The implementation assumes that the channel map contains at least one enabled data channel. When the channel map is all zeros, no valid channel can be selected, and the function reaches: BLE_LL_ASSERT(0);

This results in a denial of service (DoS).

Suggested patch for this issue

According to the Bluetooth Core Specification (Vol 6, Part B), the minimum number of used channels in the channel map shall be 2. Therefore, an all-zero channel map is invalid.

Specifically, the fix should validate the ChM field in ble_ll_ctrl_rx_chanmap_req() before copying it into connsm->req_chanmap. Channel maps with fewer than two enabled channels should be rejected, and the connection should be terminated with BLE_ERR_INV_LMP_LL_PARM.

Reference(s)

  • Bluetooth Core Specification Vol 6, Part B, Section 4.5.8 (Channel Map Update)
  • Apache NimBLE source:
    • ble_ll_ctrl_rx_chanmap_req
    • ble_ll_utils_remapped_channel

Additional info
We identified this issue by rehosting the NimBLE controller and performing over-the-air–like testing with injected malformed Link Layer control PDUs.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions