[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];
bool ta_supported = false;
ogs_assert(amf_ue->num_of_slice);
slice = ogs_slice_find_by_s_nssai(
amf_ue->slice, amf_ue->num_of_slice,
(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;
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);
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() "
"failed [%d] in type [%d]",
gmm_cause, amf_ue->nas.message_type);
if (amf_ue->nas.message_type ==
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);
r = nas_5gs_send_gmm_reject(ran_ue, amf_ue, gmm_cause);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
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) {
/* 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,
amf_ue->knas_enc, amf_ue->ul_count.i32,
amf_ue->nas.access_type,

View File

@ -199,6 +199,7 @@ int amf_nudm_sdm_handle_provisioned(
continue;
}
ogs_assert(amf_ue->num_of_slice);
slice = ogs_slice_find_by_s_nssai(
amf_ue->slice, amf_ue->num_of_slice,
&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) {
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");
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) {
/* 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,
mme_ue->knas_enc, mme_ue->ul_count.i32, NAS_SECURITY_BEARER,
OGS_NAS_SECURITY_UPLINK_DIRECTION, pkbuf);

View File

@ -727,6 +727,7 @@ bool udr_nudr_dr_handle_subscription_provisioned(
goto cleanup;
};
ogs_assert(subscription_data.num_of_slice);
slice_data = ogs_slice_find_by_s_nssai(
subscription_data.slice, subscription_data.num_of_slice,
&recvmsg->param.s_nssai);
@ -1136,6 +1137,7 @@ bool udr_nudr_dr_handle_policy_data(
goto cleanup;
}
ogs_assert(subscription_data.num_of_slice);
slice_data = ogs_slice_find_by_s_nssai(
subscription_data.slice, subscription_data.num_of_slice,
&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();
}
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)
{
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_2287_v263_func, NULL);
abts_run_test(suite, issues_2287_v264_func, NULL);
abts_run_test(suite, pull_3122_v270_func, NULL);
return suite;
}

View File

@ -2669,7 +2669,7 @@ ogs_pkbuf_t *test_ngap_build_malformed_initial_ue_message(int i)
"000f007300000700 5500034002000026 001d1c0602940a5f 7f5f7e105c000209"
"00007fff00000000 004c4c585f4e5f00 79000f405f7a8a1f 58755ff001940078"
"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);
}
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)
{
suite = ADD_SUITE(suite)
abts_run_test(suite, test1_func, NULL);
abts_run_test(suite, pull_3122_v270_func, NULL);
return suite;
}