amf: validate AMF-UE-NGAP-ID range to prevent crash from crafted NGAP messages

AMF crashes when receiving crafted NGAP messages with an oversized
AMF-UE-NGAP-ID (e.g., 0xc0ffffffff). The value exceeds the 3GPP spec
maximum (2^40-1) and causes ngap_send_error_indication() to fail,
triggering ogs_assert().

Added MAX_AMF_UE_NGAP_ID (0xffffffffffULL) range check after
asn_INTEGER2uint64() in all NGAP handlers.

Issues: #4371, #4375, #4376, #4377, #4378, #4379
This commit is contained in:
Sukchan Lee 2026-04-06 16:16:17 +09:00
parent 634326fb2b
commit 02b7575a91
2 changed files with 182 additions and 0 deletions

View file

@ -178,6 +178,7 @@ struct ran_ue_s {
/* UE identity */
#define INVALID_UE_NGAP_ID 0xffffffffffffffffULL /* Initial value of ran_ue_ngap_id */
uint64_t ran_ue_ngap_id; /* RAN-UE-NGAP-ID received from RAN */
#define MAX_AMF_UE_NGAP_ID 0xffffffffffULL
uint64_t amf_ue_ngap_id; /* AMF-UE-NGAP-ID received from AMF */
uint16_t gnb_ostream_id; /* SCTP output stream id for eNB */

View file

@ -709,6 +709,16 @@ void ngap_handle_uplink_nas_transport(
return;
}
if (amf_ue_ngap_id > MAX_AMF_UE_NGAP_ID) {
ogs_error("Overflow AMF_UE_NGAP_ID(2^40-1, 0xffffffffff) [0x%llx]",
(long long)amf_ue_ngap_id);
r = ngap_send_error_indication(gnb, (uint64_t *)RAN_UE_NGAP_ID, NULL,
NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
return;
}
ran_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id);
if (!ran_ue) {
ogs_error("No RAN UE Context : AMF_UE_NGAP_ID[%lld]",
@ -872,6 +882,16 @@ void ngap_handle_ue_radio_capability_info_indication(
return;
}
if (amf_ue_ngap_id > MAX_AMF_UE_NGAP_ID) {
ogs_error("Overflow AMF_UE_NGAP_ID(2^40-1, 0xffffffffff) [0x%llx]",
(long long)amf_ue_ngap_id);
r = ngap_send_error_indication(gnb, (uint64_t *)RAN_UE_NGAP_ID, NULL,
NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
return;
}
ran_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id);
if (!ran_ue) {
ogs_error("No RAN UE Context : AMF_UE_NGAP_ID[%lld]",
@ -977,6 +997,16 @@ void ngap_handle_initial_context_setup_response(
return;
}
if (amf_ue_ngap_id > MAX_AMF_UE_NGAP_ID) {
ogs_error("Overflow AMF_UE_NGAP_ID(2^40-1, 0xffffffffff) [0x%llx]",
(long long)amf_ue_ngap_id);
r = ngap_send_error_indication(gnb, (uint64_t *)RAN_UE_NGAP_ID, NULL,
NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
return;
}
ran_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id);
if (!ran_ue) {
ogs_error("No RAN UE Context : AMF_UE_NGAP_ID[%lld]",
@ -1256,6 +1286,16 @@ void ngap_handle_initial_context_setup_failure(
return;
}
if (amf_ue_ngap_id > MAX_AMF_UE_NGAP_ID) {
ogs_error("Overflow AMF_UE_NGAP_ID(2^40-1, 0xffffffffff) [0x%llx]",
(long long)amf_ue_ngap_id);
r = ngap_send_error_indication(gnb, (uint64_t *)RAN_UE_NGAP_ID, NULL,
NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
return;
}
ran_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id);
if (!ran_ue) {
ogs_error("No RAN UE Context : AMF_UE_NGAP_ID[%lld]",
@ -1384,6 +1424,11 @@ void ngap_handle_ue_context_modification_response(
ogs_warn("Invalid AMF_UE_NGAP_ID");
}
if (amf_ue_ngap_id > MAX_AMF_UE_NGAP_ID) {
ogs_warn("Overflow AMF_UE_NGAP_ID(2^40-1, 0xffffffffff) "
"[0x%llx]", (long long)amf_ue_ngap_id);
}
ran_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id);
if (!ran_ue)
ogs_warn("No RAN UE Context : AMF_UE_NGAP_ID[%lld]",
@ -1451,6 +1496,11 @@ void ngap_handle_ue_context_modification_failure(
ogs_warn("Invalid AMF_UE_NGAP_ID");
}
if (amf_ue_ngap_id > MAX_AMF_UE_NGAP_ID) {
ogs_warn("Overflow AMF_UE_NGAP_ID(2^40-1, 0xffffffffff) "
"[0x%llx]", (long long)amf_ue_ngap_id);
}
ran_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id);
if (!ran_ue)
ogs_warn("No RAN UE Context : AMF_UE_NGAP_ID[%lld]",
@ -1552,6 +1602,16 @@ void ngap_handle_ue_context_release_request(
return;
}
if (amf_ue_ngap_id > MAX_AMF_UE_NGAP_ID) {
ogs_error("Overflow AMF_UE_NGAP_ID(2^40-1, 0xffffffffff) [0x%llx]",
(long long)amf_ue_ngap_id);
r = ngap_send_error_indication(gnb, (uint64_t *)RAN_UE_NGAP_ID, NULL,
NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
return;
}
ran_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id);
if (!ran_ue) {
ogs_warn("No RAN UE Context : AMF_UE_NGAP_ID[%lld]",
@ -1729,6 +1789,16 @@ void ngap_handle_ue_context_release_complete(
return;
}
if (amf_ue_ngap_id > MAX_AMF_UE_NGAP_ID) {
ogs_error("Overflow AMF_UE_NGAP_ID(2^40-1, 0xffffffffff) [0x%llx]",
(long long)amf_ue_ngap_id);
r = ngap_send_error_indication(gnb, (uint64_t *)RAN_UE_NGAP_ID, NULL,
NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
return;
}
ran_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id);
if (!ran_ue) {
ogs_error("No RAN UE Context : AMF_UE_NGAP_ID[%lld]",
@ -1956,6 +2026,16 @@ void ngap_handle_pdu_session_resource_setup_response(
return;
}
if (amf_ue_ngap_id > MAX_AMF_UE_NGAP_ID) {
ogs_error("Overflow AMF_UE_NGAP_ID(2^40-1, 0xffffffffff) [0x%llx]",
(long long)amf_ue_ngap_id);
r = ngap_send_error_indication(gnb, (uint64_t *)RAN_UE_NGAP_ID, NULL,
NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
return;
}
ran_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id);
if (!ran_ue) {
ogs_error("No RAN UE Context : AMF_UE_NGAP_ID[%lld]",
@ -2278,6 +2358,16 @@ void ngap_handle_pdu_session_resource_modify_response(
return;
}
if (amf_ue_ngap_id > MAX_AMF_UE_NGAP_ID) {
ogs_error("Overflow AMF_UE_NGAP_ID(2^40-1, 0xffffffffff) [0x%llx]",
(long long)amf_ue_ngap_id);
r = ngap_send_error_indication(gnb, (uint64_t *)RAN_UE_NGAP_ID, NULL,
NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
return;
}
ran_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id);
if (!ran_ue) {
ogs_error("No RAN UE Context : AMF_UE_NGAP_ID[%lld]",
@ -2465,6 +2555,16 @@ void ngap_handle_pdu_session_resource_release_response(
return;
}
if (amf_ue_ngap_id > MAX_AMF_UE_NGAP_ID) {
ogs_error("Overflow AMF_UE_NGAP_ID(2^40-1, 0xffffffffff) [0x%llx]",
(long long)amf_ue_ngap_id);
r = ngap_send_error_indication(gnb, (uint64_t *)RAN_UE_NGAP_ID, NULL,
NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
return;
}
ran_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id);
if (!ran_ue) {
ogs_error("No RAN UE Context : AMF_UE_NGAP_ID[%lld]",
@ -2817,6 +2917,16 @@ void ngap_handle_path_switch_request(
return;
}
if (amf_ue_ngap_id > MAX_AMF_UE_NGAP_ID) {
ogs_error("Overflow AMF_UE_NGAP_ID(2^40-1, 0xffffffffff) [0x%llx]",
(long long)amf_ue_ngap_id);
r = ngap_send_error_indication(gnb, (uint64_t *)RAN_UE_NGAP_ID, NULL,
NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
return;
}
ran_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id);
if (!ran_ue) {
ogs_error("No RAN UE Context : AMF_UE_NGAP_ID[%lld]",
@ -3194,6 +3304,16 @@ void ngap_handle_handover_required(
return;
}
if (amf_ue_ngap_id > MAX_AMF_UE_NGAP_ID) {
ogs_error("Overflow AMF_UE_NGAP_ID(2^40-1, 0xffffffffff) [0x%llx]",
(long long)amf_ue_ngap_id);
r = ngap_send_error_indication(gnb, (uint64_t *)RAN_UE_NGAP_ID, NULL,
NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
return;
}
source_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id);
if (!source_ue) {
ogs_error("No RAN UE Context : AMF_UE_NGAP_ID[%lld]",
@ -3575,6 +3695,16 @@ void ngap_handle_handover_request_ack(
return;
}
if (amf_ue_ngap_id > MAX_AMF_UE_NGAP_ID) {
ogs_error("Overflow AMF_UE_NGAP_ID(2^40-1, 0xffffffffff) [0x%llx]",
(long long)amf_ue_ngap_id);
r = ngap_send_error_indication(gnb, (uint64_t *)RAN_UE_NGAP_ID, NULL,
NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
return;
}
target_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id);
if (!target_ue) {
ogs_error("No RAN UE Context : AMF_UE_NGAP_ID[%lld]",
@ -3793,6 +3923,16 @@ void ngap_handle_handover_failure(
return;
}
if (amf_ue_ngap_id > MAX_AMF_UE_NGAP_ID) {
ogs_error("Overflow AMF_UE_NGAP_ID(2^40-1, 0xffffffffff) [0x%llx]",
(long long)amf_ue_ngap_id);
r = ngap_send_error_indication(gnb, NULL, NULL,
NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
return;
}
target_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id);
if (!target_ue) {
ogs_error("No RAN UE Context : AMF_UE_NGAP_ID[%lld]",
@ -3918,6 +4058,16 @@ void ngap_handle_handover_cancel(
return;
}
if (amf_ue_ngap_id > MAX_AMF_UE_NGAP_ID) {
ogs_error("Overflow AMF_UE_NGAP_ID(2^40-1, 0xffffffffff) [0x%llx]",
(long long)amf_ue_ngap_id);
r = ngap_send_error_indication(gnb, (uint64_t *)RAN_UE_NGAP_ID, NULL,
NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
return;
}
source_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id);
if (!source_ue) {
ogs_error("No RAN UE Context : AMF_UE_NGAP_ID[%lld]",
@ -4070,6 +4220,16 @@ void ngap_handle_uplink_ran_status_transfer(
return;
}
if (amf_ue_ngap_id > MAX_AMF_UE_NGAP_ID) {
ogs_error("Overflow AMF_UE_NGAP_ID(2^40-1, 0xffffffffff) [0x%llx]",
(long long)amf_ue_ngap_id);
r = ngap_send_error_indication(gnb, (uint64_t *)RAN_UE_NGAP_ID, NULL,
NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
return;
}
source_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id);
if (!source_ue) {
ogs_error("No RAN UE Context : AMF_UE_NGAP_ID[%lld]",
@ -4193,6 +4353,16 @@ void ngap_handle_handover_notification(
return;
}
if (amf_ue_ngap_id > MAX_AMF_UE_NGAP_ID) {
ogs_error("Overflow AMF_UE_NGAP_ID(2^40-1, 0xffffffffff) [0x%llx]",
(long long)amf_ue_ngap_id);
r = ngap_send_error_indication(gnb, (uint64_t *)RAN_UE_NGAP_ID, NULL,
NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
return;
}
target_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id);
if (!target_ue) {
ogs_error("No RAN UE Context : AMF_UE_NGAP_ID[%lld]",
@ -4739,6 +4909,12 @@ void ngap_handle_ng_reset(
continue;
}
if (amf_ue_ngap_id > MAX_AMF_UE_NGAP_ID) {
ogs_error("Overflow AMF_UE_NGAP_ID(2^40-1, 0xffffffffff) "
"[0x%llx]", (long long)amf_ue_ngap_id);
continue;
}
ran_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id);
if (!ran_ue) {
@ -4875,6 +5051,11 @@ void ngap_handle_error_indication(amf_gnb_t *gnb, ogs_ngap_message_t *message)
ogs_warn("Invalid AMF_UE_NGAP_ID");
}
if (amf_ue_ngap_id > MAX_AMF_UE_NGAP_ID) {
ogs_warn("Overflow AMF_UE_NGAP_ID(2^40-1, 0xffffffffff) "
"[0x%llx]", (long long)amf_ue_ngap_id);
}
ran_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id);
if (!ran_ue)
ogs_warn("No RAN UE Context : AMF_UE_NGAP_ID[%lld]",