[AMF] Fix crash on malformed NGSetupRequest PLMNIdentity

When the NGSetupRequest contains an invalid GlobalRANNodeID or
BroadcastPLMNItem with a malformed PLMNIdentity, the AMF previously
performed memcpy() without checking the buffer size. This could lead
to invalid memory access and crash.

Fix by validating PLMNIdentity size against sizeof(ogs_plmn_id_t) and
sending NGSetupFailure with CauseProtocol_semantic_error if invalid.

Also add regression tests:
- Build malformed NGSetupRequest with incorrect PLMNIdentity size
- Verify AMF does not crash and returns NGSetupFailure

This resolves the crash reported in issue #4087.
This commit is contained in:
Sukchan Lee
2025-09-23 23:08:42 +09:00
parent 9d8e94f176
commit 3978db2fa6
4 changed files with 74 additions and 0 deletions

View File

@@ -183,6 +183,18 @@ void ngap_handle_ng_setup_request(amf_gnb_t *gnb, ogs_ngap_message_t *message)
return; return;
} }
if (globalGNB_ID->pLMNIdentity.size != sizeof(gnb->plmn_id)) {
ogs_error("Invalid PLMNIdentity size = %d (expected %d)",
(int)globalGNB_ID->pLMNIdentity.size,
(int)sizeof(gnb->plmn_id));
group = NGAP_Cause_PR_protocol;
cause = NGAP_CauseProtocol_semantic_error;
r = ngap_send_ng_setup_failure(gnb, group, cause);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
return;
}
if (!SupportedTAList) { if (!SupportedTAList) {
ogs_error("No SupportedTAList"); ogs_error("No SupportedTAList");
group = NGAP_Cause_PR_protocol; group = NGAP_Cause_PR_protocol;
@@ -274,6 +286,18 @@ void ngap_handle_ng_setup_request(amf_gnb_t *gnb, ogs_ngap_message_t *message)
&BroadcastPLMNItem->pLMNIdentity; &BroadcastPLMNItem->pLMNIdentity;
ogs_assert(pLMNIdentity); ogs_assert(pLMNIdentity);
if (pLMNIdentity->size != sizeof(ogs_plmn_id_t)) {
ogs_error("Invalid PLMNIdentity size = %d (expected %d)",
(int)pLMNIdentity->size,
(int)sizeof(ogs_plmn_id_t));
group = NGAP_Cause_PR_protocol;
cause = NGAP_CauseProtocol_semantic_error;
r = ngap_send_ng_setup_failure(gnb, group, cause);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
return;
}
memcpy(&gnb->supported_ta_list[i].bplmn_list[j].plmn_id, memcpy(&gnb->supported_ta_list[i].bplmn_list[j].plmn_id,
pLMNIdentity->buf, sizeof(ogs_plmn_id_t)); pLMNIdentity->buf, sizeof(ogs_plmn_id_t));
ogs_debug(" PLMN_ID[MCC:%d MNC:%d]", ogs_debug(" PLMN_ID[MCC:%d MNC:%d]",

View File

@@ -2622,6 +2622,31 @@ static ogs_pkbuf_t *testngap_build_handover_request_ack_transfer(
#define TEST_NGAP_MAX_MESSAGE 64 #define TEST_NGAP_MAX_MESSAGE 64
ogs_pkbuf_t *test_ngap_build_malformed_ng_setup_request(int i)
{
ogs_pkbuf_t *pkbuf = NULL;
const char *payload[TEST_NGAP_MAX_MESSAGE] = {
"00150035"
"000004001b0008c0 02f8391000010200 5240090300667265 6535676300660010"
"00000000010002f8 3900001008010203 0015400140000000",
"",
};
uint16_t len[TEST_NGAP_MAX_MESSAGE] = {
60,
0,
};
char hexbuf[OGS_HUGE_LEN];
pkbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN);
ogs_assert(pkbuf);
ogs_pkbuf_put_data(pkbuf,
ogs_hex_from_string(payload[i], hexbuf, sizeof(hexbuf)), len[i]);
return pkbuf;
}
ogs_pkbuf_t *test_ngap_build_amf_configuration_ack(int i) ogs_pkbuf_t *test_ngap_build_amf_configuration_ack(int i)
{ {
ogs_pkbuf_t *pkbuf = NULL; ogs_pkbuf_t *pkbuf = NULL;

View File

@@ -79,6 +79,7 @@ ogs_pkbuf_t *testngap_build_handover_failure(test_ue_t *test_ue,
ogs_pkbuf_t *testngap_build_handover_cancel(test_ue_t *test_ue, ogs_pkbuf_t *testngap_build_handover_cancel(test_ue_t *test_ue,
NGAP_Cause_PR group, long cause); NGAP_Cause_PR group, long cause);
ogs_pkbuf_t *test_ngap_build_malformed_ng_setup_request(int i);
ogs_pkbuf_t *test_ngap_build_amf_configuration_ack(int i); ogs_pkbuf_t *test_ngap_build_amf_configuration_ack(int i);
ogs_pkbuf_t *test_ngap_build_malformed_initial_ue_message(int i); ogs_pkbuf_t *test_ngap_build_malformed_initial_ue_message(int i);

View File

@@ -1434,6 +1434,29 @@ static void test5_func(abts_case *tc, void *data)
testgnb_ngap_close(ngap); testgnb_ngap_close(ngap);
} }
static void test6_issues4087_func(abts_case *tc, void *data)
{
int rv;
ogs_socknode_t *ngap;
ogs_pkbuf_t *sendbuf;
ogs_pkbuf_t *recvbuf;
ogs_ngap_message_t message;
ngap = testngap_client(1, AF_INET);
ABTS_PTR_NOTNULL(tc, ngap);
sendbuf = test_ngap_build_malformed_ng_setup_request(0);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
recvbuf = testgnb_ngap_read(ngap);
ABTS_PTR_NOTNULL(tc, recvbuf);
ogs_pkbuf_free(recvbuf);
testgnb_ngap_close(ngap);
}
abts_suite *test_crash(abts_suite *suite) abts_suite *test_crash(abts_suite *suite)
{ {
suite = ADD_SUITE(suite) suite = ADD_SUITE(suite)
@@ -1443,6 +1466,7 @@ abts_suite *test_crash(abts_suite *suite)
abts_run_test(suite, test3_func, NULL); abts_run_test(suite, test3_func, NULL);
abts_run_test(suite, test4_issues2842_func, NULL); abts_run_test(suite, test4_issues2842_func, NULL);
abts_run_test(suite, test5_func, NULL); abts_run_test(suite, test5_func, NULL);
abts_run_test(suite, test6_issues4087_func, NULL);
return suite; return suite;
} }