From 38868918330a83fad59292bfcea53801ee6137f5 Mon Sep 17 00:00:00 2001 From: Sukchan Lee Date: Thu, 25 Jan 2024 23:25:47 +0900 Subject: [PATCH] [MME] Crash due to a race condition A race condition can occur in the following situations. In conclusion, we can use this situation to determine whether or not the UE Context has been removed and avoiding a crash. For example, suppose a UE Context is removed in the followings. 1. Attach Request 2. Authentication-Information-Request 3. Authentication-Information-Answer 4. Authentication Request 5. Authentication Response(MAC Failed) 6. Authentication Reject 7. UEContextReleaseCommand 8. UEContextReleaseComplete The MME then sends a Purge-UE-request to the HSS and deletes the UE context as soon as it receives a Purge-UE-Answer. Suppose an Attach Request is received from the same UE between Purge-UE-Request/Answer, then the MME and HSS start the Authentication-Information-Request/Answer process. This can lead to the following situations. 1. Purge-UE-Request 2. Attach Request 3. Authentication-Information-Request 4. Purge-UE-Answer 5. [UE Context Removed] 6. Authentication-Information-Answer Since the UE Context has already been deleted when the Authentication-Information-Answer is received, it cannot be processed properly. Therefore, mme_ue_cycle() is used to check whether the UE Context has been deleted and decide whether to process or ignore the Authentication-Information-Answer as shown below. --- lib/core/ogs-timer.c | 1 - src/mme/mme-sm.c | 51 ++++++++++++++++++++++++++++++++++++++++++-- src/mme/s1ap-build.c | 23 +++++++++++++++++++- 3 files changed, 71 insertions(+), 4 deletions(-) diff --git a/lib/core/ogs-timer.c b/lib/core/ogs-timer.c index 90c01c9db..cc14a7675 100644 --- a/lib/core/ogs-timer.c +++ b/lib/core/ogs-timer.c @@ -146,7 +146,6 @@ void ogs_timer_stop_debug(ogs_timer_t *timer, const char *file_line) manager = timer->manager; ogs_assert(manager); timer = ogs_timer_cycle(manager, timer); - ogs_assert(timer); if (!timer) { ogs_fatal("ogs_timer_stop() failed in %s", file_line); ogs_assert_if_reached(); diff --git a/src/mme/mme-sm.c b/src/mme/mme-sm.c index 039d53b97..ea006cc24 100644 --- a/src/mme/mme-sm.c +++ b/src/mme/mme-sm.c @@ -407,8 +407,53 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e) break; case MME_EVENT_S6A_MESSAGE: - mme_ue = e->mme_ue; - ogs_assert(mme_ue); + /* + * A race condition can occur in the following situations. + * In conclusion, we can use this situation to determine + * whether or not the UE Context has been removed and avoiding a crash. + * + * For example, suppose a UE Context is removed in the followings. + * + * 1. Attach Request + * 2. Authentication-Information-Request + * 3. Authentication-Information-Answer + * 4. Authentication Request + * 5. Authentication Response(MAC Failed) + * 6. Authentication Reject + * 7. UEContextReleaseCommand + * 8. UEContextReleaseComplete + * + * The MME then sends a Purge-UE-request to the HSS and deletes + * the UE context as soon as it receives a Purge-UE-Answer. + * + * Suppose an Attach Request is received from the same UE + * between Purge-UE-Request/Answer, then the MME and HSS start + * the Authentication-Information-Request/Answer process. + * + * This can lead to the following situations. + * + * 1. Purge-UE-Request + * 2. Attach Request + * 3. Authentication-Information-Request + * 4. Purge-UE-Answer + * 5. [UE Context Removed] + * 6. Authentication-Information-Answer + * + * Since the UE Context has already been deleted + * when the Authentication-Information-Answer is received, + * it cannot be processed properly. + * + * Therefore, mme_ue_cycle() is used to check + * whether the UE Context has been deleted and + * decide whether to process or + * ignore the Authentication-Information-Answer as shown below. + */ + mme_ue = mme_ue_cycle(e->mme_ue); + if (!mme_ue) { + ogs_error("UE(mme-ue) context has already been removed"); + goto cleanup; + } + s6a_message = e->s6a_message; ogs_assert(s6a_message); @@ -473,6 +518,8 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e) ogs_error("Invalid Type[%d]", s6a_message->cmd_code); break; } + +cleanup: ogs_subscription_data_free(&s6a_message->idr_message.subscription_data); ogs_subscription_data_free(&s6a_message->ula_message.subscription_data); ogs_free(s6a_message); diff --git a/src/mme/s1ap-build.c b/src/mme/s1ap-build.c index 3c336968e..d4dde8eaa 100644 --- a/src/mme/s1ap-build.c +++ b/src/mme/s1ap-build.c @@ -574,7 +574,28 @@ ogs_pkbuf_t *s1ap_build_initial_context_setup_request( emmbuf = NULL; } - ogs_assert(E_RABToBeSetupListCtxtSUReq->list.count); + if (!E_RABToBeSetupListCtxtSUReq->list.count) { + ogs_error(" IMSI[%s] NAS-EPS Type[%d] " + "ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]", + mme_ue->imsi_bcd, mme_ue->nas_eps.type, + enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id); + ogs_list_for_each(&mme_ue->sess_list, sess) { + ogs_error(" APN[%s]", + sess->session ? sess->session->name : "Unknown"); + ogs_list_for_each(&sess->bearer_list, bearer) { + if (OGS_FSM_CHECK(&bearer->sm, esm_state_inactive)) + ogs_error(" IN-ACTIVE"); + else if (OGS_FSM_CHECK(&bearer->sm, esm_state_active)) + ogs_error(" ACTIVE"); + else + ogs_error(" OTHER STATE"); + + ogs_error(" EBI[%d] QCI[%d] SGW-S1U-TEID[%d]", + bearer->ebi, bearer->qos.index, bearer->sgw_s1u_teid); + } + } + return NULL; + } ie = CALLOC(1, sizeof(S1AP_InitialContextSetupRequestIEs_t)); ASN_SEQUENCE_ADD(&InitialContextSetupRequest->protocolIEs, ie);