From 199f4c7add495422985f9edfd230dd2b7e55505b Mon Sep 17 00:00:00 2001 From: Sukchan Lee Date: Mon, 4 Mar 2024 20:59:23 +0900 Subject: [PATCH] [AMF] Fixed crash in no context setup (#2999) Remove ogs_assert((__sESS)->gsm_message.n1buf) from AMF_SESS_STORE_5GSM_MESSAGE because N1 buffer can become NULL during PDU session release. --- lib/nas/common/types.h | 2 - src/amf/context.h | 4 +- tests/registration/abts-main.c | 2 - tests/registration/meson.build | 1 - tests/slice/abts-main.c | 2 + tests/slice/meson.build | 1 + tests/{registration => slice}/paging-test.c | 355 ++++++++++++++++++++ 7 files changed, 361 insertions(+), 6 deletions(-) rename tests/{registration => slice}/paging-test.c (90%) diff --git a/lib/nas/common/types.h b/lib/nas/common/types.h index 9c5497a33..c5f6538d7 100644 --- a/lib/nas/common/types.h +++ b/lib/nas/common/types.h @@ -42,8 +42,6 @@ extern "C" { #define OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED_AND_PARTICALLY_CIPHTERD 5 #define OGS_NAS_SECURITY_HEADER_FOR_SERVICE_REQUEST_MESSAGE 12 -#define OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED 0 - #define OGS_NAS_CLEAR_DATA(__dATA) \ do { \ ogs_assert((__dATA)); \ diff --git a/src/amf/context.h b/src/amf/context.h index c141d2636..83ab14b4a 100644 --- a/src/amf/context.h +++ b/src/amf/context.h @@ -654,14 +654,16 @@ typedef struct amf_sess_s { ogs_pkbuf_free((__sESS)->gsm_message.n1buf); \ } \ (__sESS)->gsm_message.n1buf = __n1Buf; \ - ogs_assert((__sESS)->gsm_message.n1buf); \ + \ if ((__sESS)->gsm_message.n2buf) { \ ogs_warn("[%s:%d] N2 message duplicated. Overwritten", \ ((__sESS)->amf_ue)->supi, (__sESS)->psi); \ ogs_pkbuf_free((__sESS)->gsm_message.n2buf); \ } \ (__sESS)->gsm_message.n2buf = __n2Buf; \ + \ ogs_assert((__sESS)->gsm_message.n2buf); \ + \ (__sESS)->gsm_message.type = __tYPE; \ } while(0); diff --git a/tests/registration/abts-main.c b/tests/registration/abts-main.c index 7596b2f39..1c438903d 100644 --- a/tests/registration/abts-main.c +++ b/tests/registration/abts-main.c @@ -25,7 +25,6 @@ abts_suite *test_auth(abts_suite *suite); abts_suite *test_ecc(abts_suite *suite); abts_suite *test_idle(abts_suite *suite); abts_suite *test_dereg(abts_suite *suite); -abts_suite *test_paging(abts_suite *suite); abts_suite *test_identity(abts_suite *suite); abts_suite *test_gmm_status(abts_suite *suite); abts_suite *test_ue_context(abts_suite *suite); @@ -42,7 +41,6 @@ const struct testlist { {test_ecc}, {test_idle}, {test_dereg}, - {test_paging}, {test_identity}, {test_gmm_status}, {test_ue_context}, diff --git a/tests/registration/meson.build b/tests/registration/meson.build index 76540e23a..f49dae5b6 100644 --- a/tests/registration/meson.build +++ b/tests/registration/meson.build @@ -23,7 +23,6 @@ test5gc_registration_sources = files(''' ecc-test.c idle-test.c dereg-test.c - paging-test.c identity-test.c gmm-status-test.c ue-context-test.c diff --git a/tests/slice/abts-main.c b/tests/slice/abts-main.c index d2ef2f36b..5865dac02 100644 --- a/tests/slice/abts-main.c +++ b/tests/slice/abts-main.c @@ -21,12 +21,14 @@ abts_suite *test_same_dnn(abts_suite *suite); abts_suite *test_different_dnn(abts_suite *suite); +abts_suite *test_paging(abts_suite *suite); const struct testlist { abts_suite *(*func)(abts_suite *suite); } alltests[] = { {test_same_dnn}, {test_different_dnn}, + {test_paging}, {NULL}, }; diff --git a/tests/slice/meson.build b/tests/slice/meson.build index 77e0f8a3d..3aee0f058 100644 --- a/tests/slice/meson.build +++ b/tests/slice/meson.build @@ -19,6 +19,7 @@ test5gc_slice_sources = files(''' abts-main.c same-dnn-test.c different-dnn-test.c + paging-test.c '''.split()) test5gc_slice_exe = executable('slice', diff --git a/tests/registration/paging-test.c b/tests/slice/paging-test.c similarity index 90% rename from tests/registration/paging-test.c rename to tests/slice/paging-test.c index d601095ec..782b361f1 100644 --- a/tests/registration/paging-test.c +++ b/tests/slice/paging-test.c @@ -1549,6 +1549,359 @@ static void cm_connected_error_indication_func(abts_case *tc, void *data) test_ue_remove(test_ue); } +static void cm_context_setup_is_not_established_error_indication_func( + abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *ngap; + ogs_socknode_t *gtpu; + ogs_pkbuf_t *gmmbuf; + ogs_pkbuf_t *gsmbuf; + ogs_pkbuf_t *nasbuf; + ogs_pkbuf_t *sendbuf; + ogs_pkbuf_t *recvbuf; + ogs_ngap_message_t message; + int i; + + ogs_nas_5gs_mobile_identity_suci_t mobile_identity_suci; + test_ue_t *test_ue = NULL; + test_sess_t *sess = NULL; + test_bearer_t *qos_flow = NULL; + + bson_t *doc = NULL; + + /* Setup Test UE & Session Context */ + memset(&mobile_identity_suci, 0, sizeof(mobile_identity_suci)); + + mobile_identity_suci.h.supi_format = OGS_NAS_5GS_SUPI_FORMAT_IMSI; + mobile_identity_suci.h.type = OGS_NAS_5GS_MOBILE_IDENTITY_SUCI; + mobile_identity_suci.routing_indicator1 = 0; + mobile_identity_suci.routing_indicator2 = 0xf; + mobile_identity_suci.routing_indicator3 = 0xf; + mobile_identity_suci.routing_indicator4 = 0xf; + mobile_identity_suci.protection_scheme_id = OGS_PROTECTION_SCHEME_NULL; + mobile_identity_suci.home_network_pki_value = 0; + + test_ue = test_ue_add_by_suci(&mobile_identity_suci, "0000203190"); + ogs_assert(test_ue); + + test_ue->nr_cgi.cell_id = 0x40001; + + test_ue->nas.registration.tsc = 0; + test_ue->nas.registration.ksi = OGS_NAS_KSI_NO_KEY_IS_AVAILABLE; + test_ue->nas.registration.follow_on_request = 1; + test_ue->nas.registration.value = OGS_NAS_5GS_REGISTRATION_TYPE_INITIAL; + + test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; + test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; + + /* gNB connects to AMF */ + ngap = testngap_client(AF_INET); + ABTS_PTR_NOTNULL(tc, ngap); + + /* gNB connects to UPF */ + gtpu = test_gtpu_server(1, AF_INET); + ABTS_PTR_NOTNULL(tc, gtpu); + + /* Send NG-Setup Reqeust */ + sendbuf = testngap_build_ng_setup_request(0x4000, 23); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive NG-Setup Response */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /********** Insert Subscriber in Database */ + doc = test_db_new_simple(test_ue); + ABTS_PTR_NOTNULL(tc, doc); + ABTS_INT_EQUAL(tc, OGS_OK, test_db_insert_ue(test_ue, doc)); + + /* Send Registration request */ + gmmbuf = testgmm_build_registration_request(test_ue, NULL, false, false); + ABTS_PTR_NOTNULL(tc, gmmbuf); + + test_ue->registration_request_param.gmm_capability = 1; + test_ue->registration_request_param.s1_ue_network_capability = 1; + test_ue->registration_request_param.requested_nssai = 1; + test_ue->registration_request_param.last_visited_registered_tai = 1; + test_ue->registration_request_param.ue_usage_setting = 1; + nasbuf = testgmm_build_registration_request(test_ue, NULL, false, false); + ABTS_PTR_NOTNULL(tc, nasbuf); + + sendbuf = testngap_build_initial_ue_message(test_ue, gmmbuf, + NGAP_RRCEstablishmentCause_mo_Signalling, false, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication request */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send Authentication response */ + gmmbuf = testgmm_build_authentication_response(test_ue); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send Security mode complete */ + gmmbuf = testgmm_build_security_mode_complete(test_ue, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive InitialContextSetupRequest + + * Registration accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue->ngap_procedure_code); + + /* Send UERadioCapabilityInfoIndication */ + sendbuf = testngap_build_ue_radio_capability_info_indication(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send InitialContextSetupResponse */ + sendbuf = testngap_build_initial_context_setup_response(test_ue, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Registration complete */ + gmmbuf = testgmm_build_registration_complete(test_ue); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Configuration update command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send PDU session establishment request */ + sess = test_sess_add_by_dnn_and_psi(test_ue, "internet", 5); + ogs_assert(sess); + + sess->ul_nas_transport_param.request_type = + OGS_NAS_5GS_REQUEST_TYPE_INITIAL; + sess->ul_nas_transport_param.dnn = 1; + sess->ul_nas_transport_param.s_nssai = 1; + + sess->pdu_session_establishment_param.ssc_mode = 1; + sess->pdu_session_establishment_param.epco = 1; + + gsmbuf = testgsm_build_pdu_session_establishment_request(sess); + ABTS_PTR_NOTNULL(tc, gsmbuf); + gmmbuf = testgmm_build_ul_nas_transport(sess, + OGS_NAS_PAYLOAD_CONTAINER_N1_SM_INFORMATION, gsmbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDUSessionResourceSetupRequest + + * DL NAS transport + + * PDU session establishment accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceSetup, + test_ue->ngap_procedure_code); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Wait to setup N3 data connection + * + * Otherwise, the following case could occur: + * + * 1. PDUSessionResourceSetupResponse + * 2. UEContextReleaseRequest + * 3. /nsmf-pdusession/v1/sm-contexts/{smContextRef}/modify + * 4. /nsmf-pdusession/v1/sm-contexts/{smContextRef}/modify + * 5. PFCP Session Modifcation Request (Deactivated) + * 6. PFCP Session Modifcation Request (OuterHeaderCreation) + * 7. PFCP Session Modifcation Response + * 8. PFCP Session Modifcation Response + * + * As such, N3 status could be activated. + * + * To prevent this situation, we'll use ogs_msleep(100). + */ + ogs_msleep(100); + + /* Send UEContextReleaseRequest */ + sendbuf = testngap_build_ue_context_release_request(test_ue, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity, + true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UEContextReleaseCommand */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_UEContextRelease, + test_ue->ngap_procedure_code); + + /* Send UEContextReleaseComplete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* + * Send InitialUEMessage + + * Service request + * - Type: Mobile terminated services(2) + * - PDU Session Status + */ + test_ue->service_request_param.pdu_session_status = 0; + nasbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_MOBILE_TERMINATED_SERVICES, + NULL, false, false); + ABTS_PTR_NOTNULL(tc, nasbuf); + + test_ue->service_request_param.pdu_session_status = 0; + gmmbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_MOBILE_TERMINATED_SERVICES, + nasbuf, true, false); + ABTS_PTR_NOTNULL(tc, gmmbuf); + + sendbuf = testngap_build_initial_ue_message(test_ue, gmmbuf, + NGAP_RRCEstablishmentCause_mo_Signalling, true, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive InitialContextSetupRequest + + * Service accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue->ngap_procedure_code); + + /* Send Error Indication */ + qos_flow = test_qos_flow_find_by_qfi(sess, 1); + ogs_assert(qos_flow); + rv = test_gtpu_send_error_indication(gtpu, qos_flow); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Wait to test CONTEXT_SETUP_ESTABLISHED() */ + ogs_msleep(100); + + /* Send InitialContextSetupResponse */ + sendbuf = testngap_build_initial_context_setup_response(test_ue, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDUSessionResourceReleaseCommand */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceRelease, + test_ue->ngap_procedure_code); + + /* Send PDUSessionResourceReleaseResponse */ + sendbuf = testngap_build_pdu_session_resource_release_response(sess); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDUSessionResourceSetupRequest */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceSetup, + test_ue->ngap_procedure_code); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Wait to setup N3 data connection. + * Otherwise, network-triggered service request is initiated */ + ogs_msleep(100); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send UEContextReleaseRequest */ + sendbuf = testngap_build_ue_context_release_request(test_ue, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity, + false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UEContextReleaseCommand */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_UEContextRelease, + test_ue->ngap_procedure_code); + + /* Send UEContextReleaseComplete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + ABTS_INT_EQUAL(tc, OGS_OK, test_db_remove_ue(test_ue)); + + /* gNB disonncect from UPF */ + testgnb_gtpu_close(gtpu); + + /* gNB disonncect from AMF */ + testgnb_ngap_close(ngap); + + /* Clear Test UE Context */ + test_ue_remove(test_ue); +} + static void vonr_qos_flow_test1_func(abts_case *tc, void *data) { int rv; @@ -3276,6 +3629,8 @@ abts_suite *test_paging(abts_suite *suite) abts_run_test(suite, cm_connected_paging_func, NULL); abts_run_test(suite, cm_idle_error_indication_func, NULL); abts_run_test(suite, cm_connected_error_indication_func, NULL); + abts_run_test(suite, + cm_context_setup_is_not_established_error_indication_func, NULL); abts_run_test(suite, vonr_qos_flow_test1_func, NULL); abts_run_test(suite, vonr_session_test2_func, NULL); abts_run_test(suite, registration_ue_context_test4_func, NULL);