[PFCP] Validate F-TEID parameters to prevent UPF/SGWU crash (#3747)

This commit introduces robust validation for the F-TEID information element
in the PFCP message handling. Previously, malformed F-TEID values (such as
a zero length, zero TEID, or a TEID exceeding the pool size) could lead
to an assertion failure and crash the UPF.

The changes ensure that:
- The F-TEID length is greater than zero, confirming the IE is present.
- The TEID is a non-zero value, as a valid TEID must be positive.
- The TEID does not exceed the allowed pool size (max_ue * 4 * 16).

If any of these conditions are not met, an error is logged with the F-TEID
length and TEID value, and the function returns an error code
(OGS_PFCP_CAUSE_MANDATORY_IE_INCORRECT), preventing further processing
of the malformed message.
This commit is contained in:
Sukchan Lee
2025-03-07 10:12:40 +09:00
parent 4012f572ed
commit cb2359dca0
4 changed files with 33 additions and 8 deletions

View File

@@ -1356,14 +1356,30 @@ ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_or_add(
return pdr;
}
void ogs_pfcp_pdr_swap_teid(ogs_pfcp_pdr_t *pdr)
int ogs_pfcp_pdr_swap_teid(ogs_pfcp_pdr_t *pdr)
{
int i = 0;
ogs_assert(pdr);
ogs_assert(!pdr->f_teid.ch);
ogs_assert(pdr->f_teid.teid > 0 &&
pdr->f_teid.teid <= ogs_pfcp_pdr_teid_pool.size);
/*
* Issues #3747, #3574
*
* This code validates the F-TEID (Fully encapsulated TEID) information
* element within a PDR structure before further processing the PFCP
* message. The validation ensures that the F-TEID is present and
* within acceptable limits defined by the system.
*/
if (pdr->f_teid_len > 0 &&
pdr->f_teid.teid > 0 &&
pdr->f_teid.teid <= ogs_pfcp_pdr_teid_pool.size) {
/* PASS OK */
} else {
ogs_error("F-TEID LEN[%d] TEID[0x%x]",
pdr->f_teid_len, pdr->f_teid.teid);
return OGS_PFCP_CAUSE_MANDATORY_IE_INCORRECT;
}
/* Find out the Array Index for the restored TEID. */
i = pdr_random_to_index[pdr->f_teid.teid];
@@ -1379,6 +1395,8 @@ void ogs_pfcp_pdr_swap_teid(ogs_pfcp_pdr_t *pdr)
ogs_pfcp_pdr_teid_pool.array[i] = *(pdr->teid_node);
*(pdr->teid_node) = pdr->f_teid.teid;
}
return OGS_PFCP_CAUSE_REQUEST_ACCEPTED;
}
void ogs_pfcp_object_teid_hash_set(

View File

@@ -436,7 +436,7 @@ ogs_pfcp_pdr_t *ogs_pfcp_pdr_find(
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_or_add(
ogs_pfcp_sess_t *sess, ogs_pfcp_pdr_id_t id);
void ogs_pfcp_pdr_swap_teid(ogs_pfcp_pdr_t *pdr);
int ogs_pfcp_pdr_swap_teid(ogs_pfcp_pdr_t *pdr);
void ogs_pfcp_object_teid_hash_set(
ogs_pfcp_object_type_e type, ogs_pfcp_pdr_t *pdr,

View File

@@ -105,8 +105,11 @@ void sgwu_sxa_handle_session_establishment_request(
* a new TEID for the first time, so performing a swap is not appropriate
* in this case.
*/
if (pdr->f_teid.ch == false && pdr->f_teid_len)
ogs_pfcp_pdr_swap_teid(pdr);
if (pdr->f_teid.ch == false) {
cause_value = ogs_pfcp_pdr_swap_teid(pdr);
if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
goto cleanup;
}
}
restoration_indication = true;
}
@@ -116,6 +119,7 @@ void sgwu_sxa_handle_session_establishment_request(
if (OGS_ERROR == ogs_pfcp_setup_far_gtpu_node(far)) {
ogs_fatal("CHECK CONFIGURATION: sgwu.gtpu");
ogs_fatal("ogs_pfcp_setup_far_gtpu_node() failed");
cause_value = OGS_PFCP_CAUSE_SYSTEM_FAILURE;
goto cleanup;
}
if (far->gnode)

View File

@@ -162,8 +162,11 @@ void upf_n4_handle_session_establishment_request(
* a new TEID for the first time, so performing a swap is not appropriate
* in this case.
*/
if (pdr->f_teid.ch == false && pdr->f_teid_len)
ogs_pfcp_pdr_swap_teid(pdr);
if (pdr->f_teid.ch == false) {
cause_value = ogs_pfcp_pdr_swap_teid(pdr);
if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
goto cleanup;
}
}
restoration_indication = true;
}