[SEC] Crash and Protocol Violations

The AMF will crash on the following locations when it receives a sequence
of NAS messages from a UE.

- ogs_nas_encrypt: Assertion `pkbuf->len' failed. (../lib/nas/common/security.c:86)
- gmm_state_authentication: Assertion `r != OGS_ERROR' failed. (../src/amf/gmm-sm.c:1561)

Besides the crashes found above, an incorrect protocol transition
is identified in Open5GS. Without any Registration/Attach Request message,
when the Identity Response message sent, the Core Network responds
with an Authentication Request message. According to the standard,
only the Registration/Attach Request message can start a state transition
from the 5GMM/EMM-DEREGISTERED state to the 5GMM/EMM-COMMON-PROCEDURE-INITIATED.

So I've modified the relevant code to address these issues.
This commit is contained in:
Sukchan Lee 2024-04-09 16:20:18 +09:00
parent 09410eba08
commit cd76dc641d
10 changed files with 266 additions and 13 deletions

View File

@ -2852,7 +2852,7 @@ bool amf_update_allowed_nssai(amf_ue_t *amf_ue)
s_nssai[amf_ue->rejected_nssai.num_of_s_nssai]; s_nssai[amf_ue->rejected_nssai.num_of_s_nssai];
bool ta_supported = false; bool ta_supported = false;
ogs_assert(amf_ue->num_of_slice);
slice = ogs_slice_find_by_s_nssai( slice = ogs_slice_find_by_s_nssai(
amf_ue->slice, amf_ue->num_of_slice, amf_ue->slice, amf_ue->num_of_slice,
(ogs_s_nssai_t *)requested); (ogs_s_nssai_t *)requested);

View File

@ -1475,6 +1475,18 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e,
break; break;
case OGS_NAS_5GS_IDENTITY_RESPONSE: case OGS_NAS_5GS_IDENTITY_RESPONSE:
if (amf_ue->nas.message_type == 0) {
ogs_warn("No Received NAS message");
r = ngap_send_error_indication2(
ran_ue,
NGAP_Cause_PR_protocol,
NGAP_CauseProtocol_semantic_error);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, gmm_state_exception);
break;
}
CLEAR_AMF_UE_TIMER(amf_ue->t3570); CLEAR_AMF_UE_TIMER(amf_ue->t3570);
ogs_info("Identity response"); ogs_info("Identity response");
@ -1484,17 +1496,7 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e,
ogs_error("gmm_handle_identity_response() " ogs_error("gmm_handle_identity_response() "
"failed [%d] in type [%d]", "failed [%d] in type [%d]",
gmm_cause, amf_ue->nas.message_type); gmm_cause, amf_ue->nas.message_type);
if (amf_ue->nas.message_type == r = nas_5gs_send_gmm_reject(ran_ue, amf_ue, gmm_cause);
OGS_NAS_5GS_REGISTRATION_REQUEST ||
amf_ue->nas.message_type ==
OGS_NAS_5GS_SERVICE_REQUEST)
r = nas_5gs_send_gmm_reject(ran_ue, amf_ue, gmm_cause);
else
r = ngap_send_error_indication2(
ran_ue,
NGAP_Cause_PR_protocol,
NGAP_CauseProtocol_semantic_error);
ogs_expect(r == OGS_OK); ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR); ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, gmm_state_exception); OGS_FSM_TRAN(s, gmm_state_exception);

View File

@ -178,6 +178,10 @@ int nas_5gs_security_decode(amf_ue_t *amf_ue,
if (security_header_type.ciphered) { if (security_header_type.ciphered) {
/* decrypt NAS message */ /* decrypt NAS message */
if (pkbuf->len == 0) {
ogs_error("Cannot decrypt Malformed NAS Message");
return OGS_ERROR;
}
ogs_nas_encrypt(amf_ue->selected_enc_algorithm, ogs_nas_encrypt(amf_ue->selected_enc_algorithm,
amf_ue->knas_enc, amf_ue->ul_count.i32, amf_ue->knas_enc, amf_ue->ul_count.i32,
amf_ue->nas.access_type, amf_ue->nas.access_type,

View File

@ -199,6 +199,7 @@ int amf_nudm_sdm_handle_provisioned(
continue; continue;
} }
ogs_assert(amf_ue->num_of_slice);
slice = ogs_slice_find_by_s_nssai( slice = ogs_slice_find_by_s_nssai(
amf_ue->slice, amf_ue->num_of_slice, amf_ue->slice, amf_ue->num_of_slice,
&s_nssai); &s_nssai);

View File

@ -390,6 +390,16 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
switch (message->emm.h.message_type) { switch (message->emm.h.message_type) {
case OGS_NAS_EPS_IDENTITY_RESPONSE: case OGS_NAS_EPS_IDENTITY_RESPONSE:
if (mme_ue->nas_eps.type == 0) {
ogs_warn("No Received NAS message");
r = s1ap_send_error_indication2(mme_ue,
S1AP_Cause_PR_protocol, S1AP_CauseProtocol_semantic_error);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, emm_state_exception);
break;
}
ogs_info("Identity response"); ogs_info("Identity response");
CLEAR_MME_UE_TIMER(mme_ue->t3470); CLEAR_MME_UE_TIMER(mme_ue->t3470);

View File

@ -223,6 +223,10 @@ int nas_eps_security_decode(mme_ue_t *mme_ue,
if (security_header_type.ciphered) { if (security_header_type.ciphered) {
/* decrypt NAS message */ /* decrypt NAS message */
if (pkbuf->len == 0) {
ogs_error("Cannot decrypt Malformed NAS Message");
return OGS_ERROR;
}
ogs_nas_encrypt(mme_ue->selected_enc_algorithm, ogs_nas_encrypt(mme_ue->selected_enc_algorithm,
mme_ue->knas_enc, mme_ue->ul_count.i32, NAS_SECURITY_BEARER, mme_ue->knas_enc, mme_ue->ul_count.i32, NAS_SECURITY_BEARER,
OGS_NAS_SECURITY_UPLINK_DIRECTION, pkbuf); OGS_NAS_SECURITY_UPLINK_DIRECTION, pkbuf);

View File

@ -727,6 +727,7 @@ bool udr_nudr_dr_handle_subscription_provisioned(
goto cleanup; goto cleanup;
}; };
ogs_assert(subscription_data.num_of_slice);
slice_data = ogs_slice_find_by_s_nssai( slice_data = ogs_slice_find_by_s_nssai(
subscription_data.slice, subscription_data.num_of_slice, subscription_data.slice, subscription_data.num_of_slice,
&recvmsg->param.s_nssai); &recvmsg->param.s_nssai);
@ -1136,6 +1137,7 @@ bool udr_nudr_dr_handle_policy_data(
goto cleanup; goto cleanup;
} }
ogs_assert(subscription_data.num_of_slice);
slice_data = ogs_slice_find_by_s_nssai( slice_data = ogs_slice_find_by_s_nssai(
subscription_data.slice, subscription_data.num_of_slice, subscription_data.slice, subscription_data.num_of_slice,
&recvmsg->param.s_nssai); &recvmsg->param.s_nssai);

View File

@ -1862,6 +1862,118 @@ static void issues_2287_v264_func(abts_case *tc, void *data)
test_ue_remove_all(); test_ue_remove_all();
} }
static void pull_3122_v270_func(abts_case *tc, void *data)
{
int rv;
ogs_socknode_t *s1ap;
ogs_socknode_t *gtpu;
ogs_pkbuf_t *emmbuf;
ogs_pkbuf_t *esmbuf;
ogs_pkbuf_t *sendbuf;
ogs_pkbuf_t *recvbuf;
ogs_s1ap_message_t message;
ogs_nas_5gs_mobile_identity_suci_t mobile_identity_suci;
test_ue_t *test_ue = NULL;
test_sess_t *sess = NULL;
test_bearer_t *bearer = NULL;
uint32_t enb_ue_s1ap_id;
uint64_t mme_ue_s1ap_id;
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, "3746000006");
ogs_assert(test_ue);
test_ue->e_cgi.cell_id = 0x1079baf0;
test_ue->nas.ksi = 0;
test_ue->nas.value = OGS_NAS_ATTACH_TYPE_COMBINED_EPS_IMSI_ATTACH;
test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc";
test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca";
sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP2_RAT_TYPE_EUTRAN);
ogs_assert(sess);
/* eNB connects to MME */
s1ap = tests1ap_client(AF_INET);
ABTS_PTR_NOTNULL(tc, s1ap);
/* eNB connects to SGW */
gtpu = test_gtpu_server(1, AF_INET);
ABTS_PTR_NOTNULL(tc, gtpu);
/* Send S1-Setup Reqeust */
sendbuf = test_s1ap_build_s1_setup_request(
S1AP_ENB_ID_PR_macroENB_ID, 0x54f64);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive S1-Setup Response */
recvbuf = testenb_s1ap_read(s1ap);
ABTS_PTR_NOTNULL(tc, recvbuf);
tests1ap_recv(NULL, 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 Attach Request */
emmbuf = testemm_build_identity_response(test_ue);
ABTS_PTR_NOTNULL(tc, emmbuf);
memset(&test_ue->initial_ue_param, 0, sizeof(test_ue->initial_ue_param));
sendbuf = test_s1ap_build_initial_ue_message(
test_ue, emmbuf, S1AP_RRC_Establishment_Cause_mo_Signalling, false);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive ErrorIndication */
recvbuf = testenb_s1ap_read(s1ap);
ABTS_PTR_NOTNULL(tc, recvbuf);
tests1ap_recv(test_ue, recvbuf);
/* Receive UEContextReleaseCommand */
recvbuf = testenb_s1ap_read(s1ap);
ABTS_PTR_NOTNULL(tc, recvbuf);
tests1ap_recv(test_ue, recvbuf);
/* Send UEContextReleaseComplete */
sendbuf = test_s1ap_build_ue_context_release_complete(test_ue);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, 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));
/* eNB disonncect from MME */
testenb_s1ap_close(s1ap);
/* eNB disonncect from SGW */
test_gtpu_close(gtpu);
test_ue_remove(test_ue);
}
abts_suite *test_issues(abts_suite *suite) abts_suite *test_issues(abts_suite *suite)
{ {
suite = ADD_SUITE(suite) suite = ADD_SUITE(suite)
@ -1869,6 +1981,7 @@ abts_suite *test_issues(abts_suite *suite)
abts_run_test(suite, issues_1431_func, NULL); abts_run_test(suite, issues_1431_func, NULL);
abts_run_test(suite, issues_2287_v263_func, NULL); abts_run_test(suite, issues_2287_v263_func, NULL);
abts_run_test(suite, issues_2287_v264_func, NULL); abts_run_test(suite, issues_2287_v264_func, NULL);
abts_run_test(suite, pull_3122_v270_func, NULL);
return suite; return suite;
} }

View File

@ -2669,7 +2669,7 @@ ogs_pkbuf_t *test_ngap_build_malformed_initial_ue_message(int i)
"000f007300000700 5500034002000026 001d1c0602940a5f 7f5f7e105c000209" "000f007300000700 5500034002000026 001d1c0602940a5f 7f5f7e105c000209"
"00007fff00000000 004c4c585f4e5f00 79000f405f7a8a1f 58755ff001940078" "00007fff00000000 004c4c585f4e5f00 79000f405f7a8a1f 58755ff001940078"
"954e005a40012800 0340025fc0007040 010000ab4021205f 5f5f5f4f3d7fff10" "954e005a40012800 0340025fc0007040 010000ab4021205f 5f5f5f4f3d7fff10"
"de5f5f765f000000 0000000000000000 00000000000000" "de5f5f765f000000 0000000000000000 00000000000000",
"", "",
"", "",

View File

@ -354,11 +354,128 @@ static void test1_func(abts_case *tc, void *data)
test_ue_remove(test_ue); test_ue_remove(test_ue);
} }
static void pull_3122_v270_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, 29);
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 Identity response */
test_ue->ran_ue_ngap_id = 1;
gmmbuf = testgmm_build_identity_response(test_ue);
ABTS_PTR_NOTNULL(tc, gmmbuf);
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 ErrorIndication */
recvbuf = testgnb_ngap_read(ngap);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
ABTS_INT_EQUAL(tc,
NGAP_ProcedureCode_id_ErrorIndication,
test_ue->ngap_procedure_code);
/* 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);
}
abts_suite *test_identity(abts_suite *suite) abts_suite *test_identity(abts_suite *suite)
{ {
suite = ADD_SUITE(suite) suite = ADD_SUITE(suite)
abts_run_test(suite, test1_func, NULL); abts_run_test(suite, test1_func, NULL);
abts_run_test(suite, pull_3122_v270_func, NULL);
return suite; return suite;
} }