apache / apache/mynewt-nimble

Double free in `ble_hci_emspi_rx_acl()` on host ACL delivery failure

Open Beginner friendly
#2,260 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
C
Stars
893
Forks
512
Avg merge
13d 31m
Merged PRs (30d)
7

Description

I found a possible double free in the EMSPI HCI transport receive path when an incoming ACL packet is passed to the host and host-side queuing fails.

File: `nimble/transport/emspi/src/ble_hci_emspi.c`

Function: `ble_hci_emspi_rx_acl`

Relevant code:

```c
om = ble_transport_alloc_acl_from_ll();
assert(om != NULL);

rc = ble_hci_emspi_rx(om->om_data, BLE_HCI_DATA_HDR_SZ);
if (rc != 0) {
goto err;
}

...

rc = ble_transport_to_hs_acl(om);
if (rc != 0) {
goto err;
}

return 0;

err:
os_mbuf_free_chain(om);
return rc;
```

The error label is correct for failures that occur before ownership is passed
to the host. However, `ble_transport_to_hs_acl()` eventually calls the host
implementation:

File: `nimble/host/src/ble_hs.c`

```c
ble_transport_to_hs_acl_impl(struct os_mbuf *om)
{
return ble_hs_rx_data(om, NULL);
}
```

`ble_hs_rx_data()` documents and implements that it consumes the mbuf regardless
of the outcome:

```c
/* Called when a data packet is received from the controller. This function
* consumes the supplied mbuf, regardless of the outcome.
*/
static int
ble_hs_rx_data(struct os_mbuf *om, void *arg)
{
...
rc = ble_mqueue_put(&ble_hs_rx_q, ble_hs_evq, om);
if (rc != 0) {
os_mbuf_free_chain(om);
return BLE_HS_EOS;
}

return 0;
}
```

So when `ble_mqueue_put()` fails, `ble_hs_rx_data()` already frees `om` and
returns an error. `ble_hci_emspi_rx_acl()` then sees the non-zero return value,
jumps to `err`, and frees the same mbuf again.

This can happen under low-memory or queue-allocation failure conditions in the
host receive path.

Suggested fix: after calling `ble_transport_to_hs_acl(om)`, do not free `om` on
failure because ownership has already been transferred. One option is to return
the error directly:

```c
rc = ble_transport_to_hs_acl(om);
if (rc != 0) {
return rc;
}
```

Contributor guide

No contributing guide indexed for this repository

Research direction

Start in nimble/transport/emspi/src/ble_hci_emspi.c at ble_hci_emspi_rx_acl(), then read ble_transport_to_hs_acl_impl() in nimble/host/src/ble_hs.c and the ownership comment in ble_hs_rx_data(). Trace the ble_mqueue_put() failure path and verify that a host delivery failure consumes the mbuf only once, while earlier receive failures retain their existing cleanup.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
embedded-iot
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.