host/ble_l2cap_coc: fix possible race condition in L2CAP COC
Two functions: `ble_l2cap_coc_continue_tx` and `ble_l2cap_coc_recv_ready`
can be reached from other task than host, for example separate thread
running in application, by calling `ble_l2cap_recv_ready` or
`ble_l2cap_send`. Because pointer to chan passed into these functions
may be outdated (connection is being terminated by host) this will lead
to either:
- triggering BLE_HS_DBG_ASSERT(conn != NULL) in ble_hs_conn_find_assert
- dereferencing NULL pointer to conn, after ble_hs_conn_find_assert
returns NULL (case with disabled BLE_HS_DEBUG)
These two cases shall not cause assert, and should be prepared for chan
not existing anymore. Now, BLE_HS_ENOTCONN is returned if connection no
longer exists.
diff --git a/nimble/host/src/ble_l2cap_coc.c b/nimble/host/src/ble_l2cap_coc.c
index 25727ee..a3d1b1c 100644
--- a/nimble/host/src/ble_l2cap_coc.c
+++ b/nimble/host/src/ble_l2cap_coc.c
@@ -506,7 +506,12 @@
goto failed;
}
- conn = ble_hs_conn_find_assert(chan->conn_handle);
+ conn = ble_hs_conn_find(chan->conn_handle);
+ if (!conn) {
+ rc = BLE_HS_ENOTCONN;
+ BLE_HS_LOG(DEBUG, "Connection does not exist");
+ goto failed;
+ }
rc = ble_l2cap_tx(conn, chan, txom);
if (rc) {
@@ -619,7 +624,13 @@
(chan->coc_rx.next_sdu_alloc_idx + 1) % BLE_L2CAP_SDU_BUFF_CNT;
ble_hs_lock();
- conn = ble_hs_conn_find_assert(chan->conn_handle);
+ conn = ble_hs_conn_find(chan->conn_handle);
+ if (!conn) {
+ BLE_HS_LOG(DEBUG, "Connection does not exist");
+ ble_hs_unlock();
+ return BLE_HS_ENOTCONN;
+ }
+
c = ble_hs_conn_chan_find_by_scid(conn, chan->scid);
if (!c) {
ble_hs_unlock();