Skip to content

Double free in ble_hci_emspi_rx_acl() on host ACL delivery failure #2260

Description

@K-ANOY

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:

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

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:

/* 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:

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    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