From 62adb830ff544cfb9a8b4ce41f215e54366dcd53 Mon Sep 17 00:00:00 2001 From: Sumeet Singh Date: Wed, 17 Jan 2024 17:42:07 +0530 Subject: [PATCH] fix(nimble): Out of order messages during SMP causing DOS vulerability --- nimble/host/src/ble_sm.c | 73 ++++++++++++++++++++++++++++++++++- nimble/host/src/ble_sm_priv.h | 1 + nimble/host/src/ble_sm_sc.c | 10 +++++ 3 files changed, 83 insertions(+), 1 deletion(-) diff --git a/nimble/host/src/ble_sm.c b/nimble/host/src/ble_sm.c index 52c408b71..527cd96d2 100644 --- a/nimble/host/src/ble_sm.c +++ b/nimble/host/src/ble_sm.c @@ -755,8 +755,13 @@ static void ble_sm_rx_noop(uint16_t conn_handle, struct os_mbuf **om, struct ble_sm_result *res) { + /** + * Unsupported PDU received + * Recommended action: Ignore + */ res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CMD_NOT_SUPP); res->sm_err = BLE_SM_ERR_CMD_NOT_SUPP; + res->out_of_order = 1; } static uint8_t @@ -952,6 +957,17 @@ ble_sm_process_result(uint16_t conn_handle, struct ble_sm_result *res, rm = 0; + if (res && res->out_of_order) { + /** + * An unexpected SM PDU received. + * Spec recommends ignore the PDU. + */ + memset(res, 0, sizeof *res); + res->sm_err = BLE_SM_ERR_UNSPECIFIED; + res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_UNSPECIFIED); + return; + } + while (1) { ble_hs_lock(); proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_NONE, -1, @@ -1544,7 +1560,12 @@ ble_sm_random_rx(uint16_t conn_handle, struct os_mbuf **om, ble_hs_lock(); proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_RANDOM, -1, NULL); if (proc == NULL) { + /** + * Unexpectedly received pairing random value. + * Recommended action: Ignore + */ res->app_status = BLE_HS_ENOENT; + res->out_of_order = 1; } else { memcpy(ble_sm_peer_pair_rand(proc), cmd->value, 16); @@ -1592,7 +1613,12 @@ ble_sm_confirm_rx(uint16_t conn_handle, struct os_mbuf **om, ble_hs_lock(); proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_CONFIRM, -1, NULL); if (proc == NULL) { + /** + * Unexpectedly received pairing confirm value. + * Recommended action: Ignore + */ res->app_status = BLE_HS_ENOENT; + res->out_of_order = 1; } else { memcpy(proc->confirm_peer, cmd->value, 16); @@ -1849,12 +1875,13 @@ ble_sm_pair_req_rx(uint16_t conn_handle, struct os_mbuf **om, */ proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_NONE, -1, &prev); if (proc != NULL) { - /* Fail if procedure is in progress unless we sent a slave security + /* Ignore if procedure is in progress unless we sent a slave security * request to peer. */ if (proc->state != BLE_SM_PROC_STATE_SEC_REQ) { res->sm_err = BLE_SM_ERR_UNSPECIFIED; res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_UNSPECIFIED); + res->out_of_order = 1; ble_hs_unlock(); return; } @@ -2006,6 +2033,14 @@ ble_sm_pair_rsp_rx(uint16_t conn_handle, struct os_mbuf **om, } } } + } else { + /** + * Unexpectedly received pairing response. + * Recommended action: Ignore + */ + res->sm_err = BLE_SM_ERR_UNSPECIFIED; + res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_UNSPECIFIED); + res->out_of_order = 1; } ble_hs_unlock(); @@ -2046,6 +2081,7 @@ ble_sm_sec_req_rx(uint16_t conn_handle, struct os_mbuf **om, struct ble_hs_conn_addrs addrs; struct ble_sm_sec_req *cmd; struct ble_hs_conn *conn; + struct ble_sm_proc *proc; int authreq_mitm; res->app_status = ble_hs_mbuf_pullup_base(om, sizeof(*cmd)); @@ -2096,6 +2132,16 @@ ble_sm_sec_req_rx(uint16_t conn_handle, struct os_mbuf **om, } } + /** Make sure a procedure isn't already in progress for this connection. */ + ble_hs_lock(); + proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_NONE, -1, NULL); + ble_hs_unlock(); + if (proc != NULL) { + res->out_of_order = 1; + proc = NULL; + return; + } + if (res->app_status == 0) { res->app_status = ble_sm_enc_initiate(conn_handle, value_sec.key_size, @@ -2391,8 +2437,13 @@ ble_sm_enc_info_rx(uint16_t conn_handle, struct os_mbuf **om, proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_KEY_EXCH, -1, NULL); if (proc == NULL) { + /** + * Unexpected encryption info received + * Recommended action: Ignore + */ res->app_status = BLE_HS_ENOENT; res->sm_err = BLE_SM_ERR_UNSPECIFIED; + res->out_of_order = 1; } else { proc->rx_key_flags &= ~BLE_SM_KE_F_ENC_INFO; proc->peer_keys.ltk_valid = 1; @@ -2425,8 +2476,13 @@ ble_sm_master_id_rx(uint16_t conn_handle, struct os_mbuf **om, proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_KEY_EXCH, -1, NULL); if (proc == NULL) { + /** + * Unexpected central indentification info recieved + * Recommended action: Ignore + */ res->app_status = BLE_HS_ENOENT; res->sm_err = BLE_SM_ERR_UNSPECIFIED; + res->out_of_order = 1; } else { proc->rx_key_flags &= ~BLE_SM_KE_F_MASTER_ID; proc->peer_keys.ediv_rand_valid = 1; @@ -2460,8 +2516,13 @@ ble_sm_id_info_rx(uint16_t conn_handle, struct os_mbuf **om, proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_KEY_EXCH, -1, NULL); if (proc == NULL) { + /** + * Unexpected ID info received + * Recommended action: Ignore + */ res->app_status = BLE_HS_ENOENT; res->sm_err = BLE_SM_ERR_UNSPECIFIED; + res->out_of_order = 1; } else { proc->rx_key_flags &= ~BLE_SM_KE_F_ID_INFO; @@ -2494,8 +2555,13 @@ ble_sm_id_addr_info_rx(uint16_t conn_handle, struct os_mbuf **om, proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_KEY_EXCH, -1, NULL); if (proc == NULL) { + /** + * Unexpected identity address info received + * Recommended action: Ignore + */ res->app_status = BLE_HS_ENOENT; res->sm_err = BLE_SM_ERR_UNSPECIFIED; + res->out_of_order = 1; } else { proc->rx_key_flags &= ~BLE_SM_KE_F_ADDR_INFO; proc->peer_keys.addr_valid = 1; @@ -2528,8 +2594,13 @@ ble_sm_sign_info_rx(uint16_t conn_handle, struct os_mbuf **om, proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_KEY_EXCH, -1, NULL); if (proc == NULL) { + /** + * Unexpected signing info received + * Recommended action: Ignore + */ res->app_status = BLE_HS_ENOENT; res->sm_err = BLE_SM_ERR_UNSPECIFIED; + res->out_of_order = 1; } else { proc->rx_key_flags &= ~BLE_SM_KE_F_SIGN_INFO; diff --git a/nimble/host/src/ble_sm_priv.h b/nimble/host/src/ble_sm_priv.h index 8d9d8583d..359fdf51e 100644 --- a/nimble/host/src/ble_sm_priv.h +++ b/nimble/host/src/ble_sm_priv.h @@ -287,6 +287,7 @@ struct ble_sm_result { unsigned enc_cb : 1; unsigned bonded : 1; unsigned restore : 1; + unsigned out_of_order : 1; }; #if MYNEWT_VAL(BLE_HS_DEBUG) diff --git a/nimble/host/src/ble_sm_sc.c b/nimble/host/src/ble_sm_sc.c index 50ad196a5..10634db9b 100644 --- a/nimble/host/src/ble_sm_sc.c +++ b/nimble/host/src/ble_sm_sc.c @@ -624,8 +624,13 @@ ble_sm_sc_public_key_rx(uint16_t conn_handle, struct os_mbuf **om, proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_PUBLIC_KEY, -1, NULL); if (proc == NULL) { + /** + * Unexpected public key information received + * Recommended action: Ignore + */ res->app_status = BLE_HS_ENOENT; res->sm_err = BLE_SM_ERR_UNSPECIFIED; + res->out_of_order = 1; } else { memcpy(&proc->pub_key_peer, cmd, sizeof(*cmd)); rc = ble_sm_alg_gen_dhkey(proc->pub_key_peer.x, @@ -850,7 +855,12 @@ ble_sm_sc_dhkey_check_rx(uint16_t conn_handle, struct os_mbuf **om, proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_DHKEY_CHECK, -1, NULL); if (proc == NULL) { + /** + * Unexpected DHKey check values received + * Recommended action: Ignore + */ res->app_status = BLE_HS_ENOENT; + res->out_of_order = 1; } else { ble_sm_dhkey_check_process(proc, cmd, res); }