Store PCRF Session-Id copies directly as hash values and remove duplicate
MME DNS key buffers. Replace cache values in place and simplify cleanup.
Avoid temporary SBI header copies and use ogs_hash_get_or_set() for PFCP
Error Indication F-TEIDs while preserving the first-FAR-wins policy.
Zero complete UPF and SGW-U F-SEID lookup keys to prevent padding-related
lookup misses, and remove unused CP SEID-only session hashes.
Add SBI header and PFCP ownership regression coverage.
Replace chained entries with a contiguous slot array, allocated on first
insertion and grown at 90% load. Use SipHash-2-4 with a process-wide
random secret and retain the 24-byte inline key storage.
Use backward-shift deletion and reverse iteration from an empty boundary
to support deleting the current entry during traversal. Copy incoming
keys before resizing or moving slots to handle table-owned key aliases.
Remove the custom hash API and document key-pointer invalidation.
Add regression tests for growth, randomized mutations and iteration.
Copy keys on insertion and release them on removal, clear and destroy.
Store keys up to 23 bytes inline and allocate longer keys separately.
Keep duplicate-key behavior and value ownership unchanged.
Update SBI and metrics callers to stop allocating and freeing hash keys.
Remove the redundant set_rekey API and use set for RAN node ID indexes.
A Session Establishment Request can reuse an existing session for the
same CP F-SEID. If the request is rejected, the cleanup removes the
session's PFCP rules but leaves any existing URR accounting timers
active. Their callbacks can then access URRs that have already been
returned to the pool.
Expose upf_sess_urr_acc_remove_all() and call it before
ogs_pfcp_sess_clear() in the establishment failure path so the timers
and accounting are cleared before the rules are removed.
The N32-c sender selects the peer whose negotiation state is updated.
A trusted client could supply another peer's sender name and overwrite
that peer's state without its certificate covering the claimed identity.
When client verification is enabled, match the sender against the
verified TLS client certificate before looking up or creating a peer.
Return HTTP 403 on failure before dispatching to the peer FSM.
Add an SBI backend hook to obtain the verified client certificate.
Use OpenSSL hostname matching with DNS SAN priority and CN fallback,
and reject empty names and leading-dot suffix patterns.
Queued timer events and NRF subscription responses can outlive the NF
instance or subscription they reference. Handling them through raw
pointers may access a removed object or a new object reusing its pool
slot.
Give NF instances and subscriptions allocation IDs and pass them through
timer and NRF subscription client data. Resolve the ID when handling
each event, discard events for removed objects, and restore the live NF
pointer before dispatching its FSM.
Centralize NRF subscription response handling in the SBI library and
update all NF consumers and tests/af.
Sending from an nghttp2 receive callback can reenter nghttp2 and remove
the session while nghttp2_session_mem_recv() is still using it.
Defer sends until receiving returns and handle send failures there.
Preserve queued error responses for rejected requests, ignore remaining
input, and retain error-level diagnostics.
Returning the entire body can exceed nghttp2's allowed length and cause
response transmission to fail.
Limit each DATA chunk to the allowed length, track the offset in the
stream, and set EOF only for the final chunk.
Flow control can defer DATA until after server_send_response() frees the
response, leaving the data provider with a dangling pointer.
Transfer the content buffer to the stream and free it in stream_remove().
Reject duplicate responses, including responses without a body.
PDN contexts reference entries in the UE subscription array. Replacing
that array on IDR or ULA can invalidate APN names or make an existing
PDN use another APN's configuration.
Give each PDN its own copy of the EPC configuration and APN name.
Use mme_sess_set_session() for ESM and Gn assignments, releasing the
previous copy on replacement and the final copy when removing the PDN.
Keep the subscription ownership transfer introduced by d86e013f,
but remove the pointer-rebinding loop during UE migration. Retained
PDNs now carry their configurations independently of the UE array.
For Gn imports, fill a missing session type from the PDP context,
while preserving an existing valid subscription type. A later ULA
no longer populates the PDN configuration through a shared entry.
Clear subscription entries after removal and null APN names freed
when rejecting an invalid PDN type.
Add focused regression tests for IDR updates and removal, empty and
invalid profiles, ESM Information interleaving, ownership at all ESM
selection sites, and Gn session type handling.
Holding expiry or peer teardown can reclaim an Update Bearer transaction
while it is still linked to its MME bearer, leaving a stale reference to
a recycled pool slot.
Add an optional delete_cb invoked before transaction resources are
released. The MME callback uses the bearer ID stored in peer_data and
unlinks the node only if the bearer exists and the node is still present.
This handles prior unlinking and bearer removal without double removal.
Add a regression through the Update Bearer handler, holding timer expiry,
and paging continuation. Verify that no stale transaction remains and no
NAS modification or peer timer is started after expiry.
Cx getters release cx_lock before their callers consume the returned
strings. Concurrent UAR or MAR/SAR handling can free and replace the
visited-network identifier or S-CSCF name during that interval.
Copy both strings under cx_lock and free the returned copies on all
normal and error paths in UAR, LIR and SAR. Preserve NULL results for
identities without assigned values.
Keep immutable IMSI and user-name identifiers borrowed until context
teardown. Document the ownership, locking and teardown requirements.
On the final T3450 expiry during TAU, retain the UE context and
pending GUTI, transition to the registered state, and release S1
through the existing teardown path. If S1 is already gone, start
the mobile reachable timer directly. Keep Attach handling unchanged.
Store the received TAU identity separately in old_guti, including
its Gn consumers, so it cannot overwrite the pending GUTI. Offer
the pending GUTI again on the next TAU and wait for TAU Complete
instead of asserting.
Avoid immediate S1 release while GUTI confirmation is pending.
Combined TAU after security mode now leaves S1 release to the eNB,
matching the existing GUTI-only TAU Complete behavior.
Issues: #4883
When Registration Complete is not received, the exception path releases
PDU sessions and removes the AMF UE context without deleting its UDM SDM
subscription.
Clear T3550 and transition to registered, following TS 24.501 clauses
5.5.1.2.8(c) and 5.5.1.3.8(c). Reuse the normal SMF deactivation and
NG_REMOVE_AND_UNLINK sequence, preserving the UE and session contexts
for subsequent recovery or implicit deregistration. Start the mobile
reachable timer directly if the RAN context is already gone.
Issues: #4883
Set the core log level to OGS_LOG_FATAL during invalid-input checks
in conv_test1(), then restore the previous level. This suppresses
expected errors while preserving fatal diagnostics.
`tests/unit/pfcp-rule-test.c` names `struct ip` and `struct ip6_hdr`, which come
from <netinet/ip.h> and <netinet/ip6.h>. Take the same guarded includes
lib/pfcp/rule-match.c uses.
`ogs_pfcp_pdr_rule_find_by_packet()` compares `addr_len` bytes of the rule's
address, where `addr_len` is the *packet's* length. The rule's own family flags
(`ipv4_src`, `ipv4_dst`, `ipv6_src`, `ipv6_dst`) were never consulted, so the
memcmp compared only the first four bytes of an IPv6 address against an IPv4
packet, and the first four bytes of an IPv4 address against an IPv6 packet.
The SMF installs `permit out 58 from ff02::2/128 to assigned` for every session,
so an IPv4 packet whose source begins ff 02 00 00 — 255.2.0.0 — matched that RS
rule and was forwarded to the CP function's TEID instead of the N6 interface,
dropping out of the default flow's usage statistics.
Skip a rule whose address family differs from the packet's. Rules that name no
address (both flags zero) still match either family.
A failed Create transaction can reach the Diameter termination path
introduced by PR #4875. If no Gy peer is available, the existing
error handling sends a Delete response for that Create request.
Replace the separate Create/Delete error helpers with one helper
that selects the response type from the GTP version and original
request type, then calls ogs_gtp_send_error_message().
Use this helper consistently for Create/Delete errors in gsm-sm.c,
including Diameter termination and PFCP error paths.
Related PR: #4875
If PFCP Session Est Req on a 4G session times out (after 3 retrans), the
xact was being dropped without emitting any kind of event to the fsm.
As a result, the Session Creation at the UE (S%/S(C, GTPv2C) was left
dangling with no negative answer and the Gx and Gy sessions were left
established "forever".
The code path missing and being fixed by this patch is never triggered
in practice because currently the timers are the SMF are wrongly
configured: The GTPv2C t3_holding_duration timer is always configured
with the same value as the PFCP t1_holding_duration, and since the
GTPv2C is always armed beforehand, it also triggers beforehand.
As a result, the gtp_xact is being freed (also wrongly without sending
any response to the user) before and it is no longer available during
lookup from pfcp_xact->assoc_xact_id.
So in summary, aside from this patch, 2 more things need fixing in
current code base:
* In open5gs-smfd, GTPv2C (S5/s8/s2b) timeout should be bigger than PFCP
ones, since the later are sub-procedures of the former ones.
* Upon gtp_xact timeout, the entire session should be released (Gx, Gy) and
Create Session response cause=error sent to the UE.
This patch should be merged anyway, for where the GTPv2C vs PFCP timers
are fixed, since in that case (pfcp timeout < gtp2 timeout) we reject
the session earlier.
Fix the negative left shift reported by sbi_request_fuzz in
ogs_ascii_to_hex(). Mask converted digits to a nibble and pass
unsigned char values to ctype functions.
Log missing buffers, invalid lengths and non-hex characters in the
checked decoder. Delegate the string wrapper to it without duplicate
logs or an additional header dependency.
Require exactly six hex digits for AMF IDs and propagate conversion
failures through GUAMI discovery, NF profiles and AMF/UDM/SMF/PCF
handlers, with contextual error logs.
Validate UDM registration GUAMI before replacing the stored callback
URI. Include an INVALID_MANDATORY_INFORMATION N1 reject when SMF
rejects an invalid GUAMI, matching the existing No Guami path.
The specs clearly state SEID must be zero in this case:
"""
3GPP TS 29.244 7.2.2.4.2 Conditions for Sending SEID=0 in PFCP Header
If a peer's SEID is not available, the SEID field shall still be present in the header and its value shall be set to "0" in the
following messages:
- PFCP Session Establishment Request message on Sxa/Sxb/Sxc/N4;
"""
Before this patch, open5gs-smfd (and probably also open5gs-swgc though I
didn't check) were sending SEID!=0 (the previous existing SEID) during
PFCP session restoration after Recovery Timestamp increase quicked in.
This is wrong imho, because at that time the UPF is believed to be
disassociated and hence PFCP Association Setup procedure is run before
attempting PFCP session restoring. Which means, in practice, after a
PFCP Association Setup the previous sessions (SEID) lose any kind of
meaning, and hence they are all considered as not available.
Inform the OCS that "a service termination has happened, e.g. PDP
context, IP CAN bearer termination or service data flow termination.",
as per 3GPP TS 32.299 7.2.175.
PR #4863 adds Delete Bearer Request handling to release EPC sessions
when their UPF becomes unavailable, addressing the stale-session
problem reported in issue #4860.
However, reselect_upf() iterates over all sessions associated with the
failed UPF, including sessions that have not completed establishment.
For example, a Create Session Request rejected because UE IP allocation
fails can leave a session in the initial state with pfcp_node set but
an empty bearer list. A subsequent heartbeat timeout then reaches the
new ogs_assert(linked_bearer), causing the SMF to abort.
Restrict the EPC release handling to smf_gsm_state_operational before
looking up the default bearer. This excludes failed initial sessions
and avoids sending Delete Bearer Request for sessions still being
established or already being released.
The operational state is also the state that handles Delete Bearer
Response and continues the session release procedure.
Related PR: https://github.com/open5gs/open5gs/pull/4863
Related issue: https://github.com/open5gs/open5gs/issues/4860
A GTP-U packet ending right after a non-zero Next Extension Header
Type was read one byte past its end. Such packets were rejected
anyway, so only the over-read is removed.
Found by gtpu_header_fuzz.
Nothing records whether a UE's handovers work. The AMF sees every step and
knows the SUPI throughout, so it is the one place that can say both what
happened and who it happened to - the gNB has the outcome but no notion of
subscriber identity, and correlating the two would mean joining on a
RAN_UE_NGAP_ID that is reused as soon as a UE re-attaches.
Three counters, incremented only where the AMF is certain:
attempted HandoverRequired accepted for this UE
completed HandoverNotification arrived
rejected the target refused, or the source cancelled
A handover that is commanded and then never resolves is deliberately not
counted. The AMF has no guard timer for one - there is no T304 equivalent -
so the only later event is the UE re-attaching, which is indistinguishable
from an ordinary power cycle: the same HOLDING_NG_CONTEXT path serves both,
and exists for the power-cycle case. Inferring a failure there would mean
carrying a pending flag that must be cleared on every resolution and aged
out when a UE simply vanishes, and getting that wrong reports failures that
never happened. attempted less completed less rejected gives the same number
without the risk of attributing it to the wrong UE.
Reported in /5gc/amf/ue-info beside the identity already there, so a caller
can show per-subscriber handover health without a second source.
The counters are cleared on the way out of the de-registered state. The UE
context outlives a de-registration and is found again by 5G-S-TMSI, so
without that a UE would carry its previous registration's handovers into
the next one.
Tested-by: Pau Espin Pedrol <pespin@sysmocom.de>
Suppress expected diagnostics around individual test calls instead of
muting entire suites. Preserve FATAL messages and debug/trace output,
and restore the original log level before continuing.
Initialize unit-test log domains before applying command-line options
and remove redundant overrides that reset the configured log levels.
Replace natoi() and atoi() with a shared checked port parser.
Reject empty, non-numeric, and out-of-range ports before accumulation,
while preserving port 0 and leading zeros.
Issues: #4867
hss_cx_download_user_data() registers one Public Identity per MSISDN as
sip:<msisdn>@<visited-network> and tel:<msisdn>. TS 23.003 13.4 requires the canonical form of
a Tel URI to be "tel:+<CC><NDC><SN>", and RFC 3966 3 says a tel URI without the "+" is a local
number that needs a phone-context, so an I-CSCF asking for the canonical form -- which is what
the Cx interface is specified to carry -- does not match the identity the HSS stored.
impu_find_by_id() matches a Public Identity as a whole string, so the LIR for tel:+<msisdn>
finds no IMPU, hss_cx_get_server_name() returns NULL, and the HSS answers
DIAMETER_SUCCESS_SERVER_NAME_NOT_STORED (2004) with no Server-Name. The subscriber then sees
480 Temporarily Unavailable. The bytes in msisdn[].bcd come from ogs_buffer_to_bcd(), so they
are digits only and the "+" is never already there.
The volte client sent the same identity it expects the HSS to have registered, which is why the
test passed with the non-canonical form. Both move together, so the test now pins the form:
test_cx_lia_cb asserts Result-Code DIAMETER_SUCCESS with no Experimental-Result-Code, which the
HSS only produces when the identity matches.
Reported in #4841.
In ngap_handle_handover_required_transfer() the per-PDU-session flag
sess->handover.data_forwarding_not_possible is only ever set to true
(when the source gNB's HandoverRequiredTransfer omits the
directForwardingPathAvailability IE) and is never cleared. For a
PDU session that survives multiple N2 handovers this means the flag
latches at true after any single handover where the source didn't
advertise direct forwarding, and every subsequent handover emits
"Data Forwarding Not Possible" in the target gNB's
PDUSessionResourceSetupRequestTransfer regardless of what the source
advertised.
Observable symptom: HandoverRequired from the source carries
Direct Forwarding Path Availability = direct path available for a
PDU session, but the subsequent HandoverRequest to the target gNB
still contains:
Item N: id-DataForwardingNotPossible (127)
criticality: reject
value: data-forwarding-not-possible (0)
Effect: target gNB cannot accept forwarded DL bytes from the source
during the cutover and the in-flight window is dropped on every N2
handover after the first that didn't advertise direct forwarding.
Fix: derive the flag from the current source's IE on every HO prep
so it tracks the state being signalled now, not the high-water-mark
of previous handovers. When directForwardingPathAvailability is
present the flag is cleared; when absent it is set, matching the
prior behaviour for the first-handover case.
No new state machine paths, no new helpers; existing call sites in
ngap-build.c (which condition the IE emission on the flag) are
unchanged.
Tested-by: Pau Espin Pedrol <pespin@sysmocom.de>
The parser recorded the peer-supplied lengths while clamping the copy, so the builder read past ms_network_capability[] and imeisv[]. Size the MS Network Capability buffer to the 8 octets it is documented to hold.
sess_5gc_timeout() aborts the whole SMF (ogs_assert on a NULL stream)
when a PFCP Session Deletion Request times out and the associated SBI
stream has already been released (e.g. the AMF gave up, or the UE
context was cleaned up during churn). The modification branch a few
lines above already guards with `if (stream)`; apply the same handling
to the deletion branch: report 504 only when the stream is still alive,
otherwise log and continue with the existing SMF_EVT_N4_TIMER session
cleanup.
Without this the SMF process dies on a recoverable protocol timeout, and
the restart loses all in-memory UE address allocations (duplicate UE IPs
and broken downlink for half of the sessions). Observed 4-6 restarts in
one afternoon under session churn; zero restarts with this change across
a full-stack reset + 600-UE attach/detach churn + mass UE kills.
Fixes#4833
Correct the UPLINK GENERIC NAS TRANSPORT message type from 101 (0x65)
to 105 (0x69) in the NAS generator and regenerate the EPS NAS files.
Remove the obsolete cache entry for message type 101.
Ignore a PFCP REMOVE response whose bearer has already been removed by
an earlier REMOVE, instead of asserting. This happens e.g. when Create
Bearer and Delete Bearer both fail for the same bearer.
Pass the session ID to the timeout callback of the Modify Bearer PFCP
transaction, and mark it session-level so that the response handler
does not treat the ID as a bearer ID.
Not addressed: the Delete Bearer Request sent before Create Bearer
completes still carries EBI 0, and a late Delete Bearer Response for
a removed bearer still releases the whole session.
Issues: #4850
Retained PDN sessions reference subscription entries owned by the old
MME UE context. Removing that context frees APN data still in use.
Transfer subscription ownership to the new UE context and rebind
retained PDN references before removing the old context.
Use sample.yaml for EIR integration tests and share equipment fixtures
across integration suites. Enable EIR in SEPP examples and configure
gNB tests to use the serving EIR and NRF.
Remove the misleading warning on successful EIR lookups and log
generic equipment fallback at info level.# Please enter the commit message for your changes. Lines starting
Issues: #4577
Use eir.yaml as the single default configuration and select tests through
ABTS arguments, following the handover runner. Remove mode/policy
environment variables, eir-allow.yaml, and duplicate integration runs.
Move direct SBI endpoint parsing and readiness checks into service-test.
Always provision GUTI equipment fixtures and run EIR rejection cases.
Add eir-fsm to the eir suite and extend AMF/MME state-machine coverage for
policy outcomes and deferred session cleanup. Cover EIR-disabled and
allow-policy paths in FSM tests instead of separate integration runs.
An unprotected Registration Request using a registered UE's GUTI could
release its existing PDU sessions before authentication.
Defer session release until authentication, Security Mode Control and
the optional EIR check complete. Wait for all release responses before
continuing UDM registration, and prevent stale responses from resuming
a cancelled procedure.
Restore the previous NAS security context on authentication or SMC
failure, and ignore unverified Deregistration Requests during these
procedures.
Add unit and EIR integration regressions for session preservation and
replacement with EIR enabled or disabled and one or two PDU sessions.
Complete the SMF/BSF SBI configuration and make EIR fixtures safe to rerun.
An unverified Attach using a registered UE's GUTI could delete its
existing PDN sessions before authentication.
Keep the sessions through AKA, Security Mode Control and the optional
S13 EIR check. Delete them before ULR, and resume Attach only after
the last Delete Session Response.
Restore the saved NAS security context on authentication or SMC failure,
and discard unverified Detach requests during AKA and SMC. On deletion
timeout, cancel Attach continuation and retain the existing
UE_CONTEXT_REMOVE cleanup path.
Add EPC integration tests under tests/eir with S13 enabled and disabled,
covering one and two PDNs. Add focused unit coverage for restoration,
deletion ordering, cancellation and late responses.
A non-hex character after '%' made ogs_from_hex() return a negative
value, which was then shifted left (UBSan, OSS-Fuzz sbi_request_fuzz).
Decode the escape only when both characters are hex digits. Otherwise
the '%' is dropped, as a truncated escape at the end already was.
Malformed IMEISV, IMSI, SGsAP and PCO fields could trigger
out-of-bounds accesses or assertions on peer-controlled input.
- Require a 9-octet, even-parity IMEISV before writing its 16 digits
and terminator. Leave the output unchanged on failure and have
MME/AMF skip storing rejected identities. Preserve the existing
filler and digit acceptance policy.
- Check the AMF IMEISV length before reading its identity type,
including when the received IE has zero length.
- Validate the SGWC IMSI before UE lookup, which asserts on an
empty hash key, and reject nonpositive lengths in UE creation.
- Replace SGsAP DOWNLINK-UNITDATA assertions on received IMSI and
NAS container fields with error logging and early returns.
- Check the original GTP PCO length against the NAS destination
size before narrowing or copying. Omit an oversized optional
PCO instead of failing the builder, since callers assert on
message-build failure.
UEContextReleaseComplete and SGsAP-Paging-Request are sent over different
SCTP associations, so sending them in sequence does not guarantee that
the MME processes the release before the paging request.
If SGs paging is handled first, the UE can still be ECM-CONNECTED. The
MME then follows the connected-mode handling path instead of sending the
S1AP Paging expected by these tests, causing them to block until the
Meson timeout expires.
Add a short delay after UEContextReleaseComplete in the MT idle, MT SMS,
and crash CSFB tests to allow the asynchronous S1 release processing to
complete before starting the SGs paging sequence.
Return INT64_MAX directly when clamping SBI bitrates, avoiding an
intermediate double conversion that rounds the value to 2^63.
Cast Diameter test host identities to uint8_t * when assigning AVP
octet-string data to resolve pointer-sign warnings.
Log skipped hash removal at warning level when the entry belongs to
another context, since this can occur during context replacement.
A gNB/eNB can register the same node ID on a new SCTP association before
the old association's shutdown is processed. Removing the old context
can then delete the replacement's ID mapping. This caused the macOS N2
handover test to hang: the AMF could not find the target gNB despite its
successful NG Setup, while the test waited for a Handover Request.
Owner-checked removal alone is insufficient. ogs_hash_set() replaces
only the value of an existing entry, retaining the key pointer into
the old context. Subsequent ID reassignment or pool reuse can therefore
break lookups even when the replacement's mapping is not deleted.
Add ogs_hash_set_rekey() to remove and reinsert an entry with the
supplied key pointer, leaving ordinary ogs_hash_set() semantics intact.
Use it for gNB-ID and eNB-ID registration, and use the existing
ogs_hash_unset_if_owner() when removing contexts or unindexing their
previous IDs before reassignment.
Document why both operations are needed and the caller's responsibility
for key lifetime and access serialization. Keep the existing ID
replacement policy and association lifetime unchanged.
Add core and AMF/MME regression tests covering key replacement,
displaced-owner cleanup, old key storage changes, ID reassignment,
repeated registration and ID 0.
- macOS: install MongoDB 8.0 (mongodb/brew) and wait until ready,
add loopback aliases used by tests, use brew --prefix paths,
run the full test suite
- Use meson test -t 3 (timeout multiplier) on macOS and Ubuntu
- usrsctp: set infolen before usrsctp_recvv() so that PPID is
returned; sctp-test now checks PPID with usrsctp as well
A PDU session resource setup response can be followed immediately by
a UE deregistration request. The AMF sends a /modify request carrying
PDU_RES_SETUP_RSP, then a /release request for the same session,
without waiting for the /modify response.
The apparent ordering reversal does not require /release to arrive
before /modify. It can occur inside the SMF event queue:
1. The SMF handles /modify first. Its N2 SM information is copied into
a separate SMF_EVT_NGAP_MESSAGE event and appended to the queue.
The HTTP response is deferred until that event is processed.
2. If /release is already queued, it is processed before the newly
appended NGAP event. The session enters wait_pfcp_deletion and
starts PFCP session deletion.
3. The queued PDU_RES_SETUP_RSP event is then dispatched to
wait_pfcp_deletion instead of the operational state.
Thus, the HTTP requests can be handled in arrival order while the
actual setup-response processing is overtaken by session release.
Previously, wait_pfcp_deletion did not handle SMF_EVT_NGAP_MESSAGE.
The setup response was therefore discarded without replying to the
original /modify request, leaving an outstanding SBI transaction in
the AMF and causing resource-leak warnings at shutdown.
Return 204 No Content for PDU_RES_SETUP_RSP in this state, matching
the existing behavior in wait_5gc_n1_n2_release. Acknowledge the
obsolete setup report without activating the session or changing
the ongoing PFCP deletion procedure.
- Reject absolute URIs without a path to prevent the NULL dereference
found by CIFuzz, and add regression coverage.
- Reset reserved EIR fixtures and subscribers before each test case
to recover from interrupted runs, and stop setup on database errors.
- Add regression coverage for stale EIR fixture recovery.
- Wait for pending AMF responses and preserve NGAP IDs in deregistration
and GUTI tests.
- Log events for finalized NF instance FSMs as warnings.
- Enable SCTP PPID checks for usrsctp.
- Parenthesize concatenated JSON literals to fix Clang warnings.
Make intentional string literal concatenation explicit in the SBI
message tests to avoid -Wstring-concatenation.
Wait for the Configuration Update Command and the old connection's
PDU Session Resource Setup Request before starting mobility registration.
Preserve the old and new NGAP IDs for context release and setup.
This stabilizes test sequencing; the AMF event-queue race remains.
smf_qos_flow_binding() checked pf_to_add_list before rebuilding it,
so the GBR decision used the packet filters of the previous binding.
A re-sent rule without changes triggered QOS_MODIFY, and a rule that
added packet filters could be sent without the GBR QoS.
Move the ARP/MBR/GBR comparison after the rebuild. The comparison
itself is unchanged.
This does not address the other points raised in #4526.
Issues: #4526
TS 24.008 10.5.6.5 places the downlink extended octets before the
uplink ones, but the struct declared them uplink-first. As a result,
a QoS Profile IE of length 15 or 19 read 1-2 bytes past the IE, and
lengths 17/21 swapped the uplink and downlink extended rates on both
decode and encode.
Issues: #4183
ogs_gtp2_parse_uli() read the flags octet without checking
octet->len, causing a 1-byte over-read on a zero-length ULI IE.
Check the length before reading the flags and return 0.
SGW-C and SMF callers now treat a 0 return as an invalid ULI.
Also remove the ogs_assert() on ULI presence in the SMF
E-UTRAN Create Session Request path, so a missing ULI is
rejected with Mandatory IE missing instead of aborting.
A ULI with only the flags octet (no location fields) is
still accepted as before.
Issues: #4812
Check the combined public key, ciphertext, and MAC tag length for the
selected protection profile before allocation and copying, preventing
out-of-bounds reads when extracting the MAC tag.
Use size_t for the scheme-output length to avoid integer truncation.
Reject empty boundary strings before initializing the multipart parser
to prevent out-of-bounds writes to its lookbehind buffer.
Free the allocated boundary and return a parse error.
Share the AMF/MME action type and parser in lib/app, and length-aware
BCD validation in lib/proto. Validate S13 User-Name before conversion
to reject embedded NUL bytes while preserving existing length rules.
Add unit tests for policy parsing and bounded digit validation.
Related PR: #4802#4795#4708
Skip emergency registration while preserving checks for other registrations
that complete SMC. Share PEI validation and apply missing_pei_action to
unusable identities.
Add unit tests for check eligibility and exercise both allow and reject
policies in the AMF and MME integration tests.
Related PR: #4802#4795#4708
Run the S13 attach cases in the eir suite on the app harness, so one
open5gs-eird serves N5g-eir to the AMF and S13 to the MME out of the
same eir collection.
Fold the EPC side of s13.yaml into eir.yaml and drop s13.yaml. The
attach cases use SVN 09 of the test IMEI to stay clear of the SVN 00-07
used by registration-test.c.
Related PR: #4802#4795#4708
Extend transform.py to handle all-reference oneOf schemas with distinct
JSON types and preserve nullable alternatives in the union template.
Regenerate affected models and adapt AMF/AUSF 5G-AKA handlers to the
Av5gAka union member. Add transform and JSON roundtrip regression tests.
Related PR: #4807
Move missing-IMEISV policy handling out of the Diameter sender and
require an active attach with a matching serving S1 context before
processing an ECA.
Remove unreachable branches, simplify unit test setup, extend guard
coverage, and tidy license headers, formatting, and documentation.
Related PR: #4802
- Fix duplicate eir_thread in tests/app/app-init.c after the upstream merge
- Remove the IMEISV cache and the attach pre-check; check after Security
Mode Complete as the AMF does, without forcing re-authentication on the
valid-security-context path
- Ignore stale ECA responses, so a delayed answer cannot trigger ULR or
Attach Reject after the procedure has been cancelled or replaced
- Make User-Name optional in the ECR
- Keep S13 disabled by default in eir.yaml.in
- Ship eir.conf and the EIR TLS key/certificate in the Debian package
Deleting the default QoS flow can remove its PDRs before the UPF rejects
removal of the DL FAR shared with CP2UP, leaving the user plane broken
without a NAS response to the UE.
Check the session's default QoS flow in the existing rule deletion
branch, before removing packet filters. Return OGS_ERROR so the caller
uses the existing PDU Session Modification Reject path.
Use the stored flow rather than the UE-provided DQR bit. Dedicated QoS
flow deletion remains unchanged.
Issues #4808
The CP2UP QER association was disabled together with UP2CP QFI matching,
causing IPv6 Router Advertisements to be forwarded over N3 without a
PDU Session Container.
Restore the association with the default QoS flow's QER so the UPF adds
a DL PDU Session Container with the configured QFI. Keep UP2CP QFI
matching disabled and preserve EPC forwarding, where no 5GS QFI is
assigned.
Update the RA receive tests to require a DL PDU Session Container and
a QFI belonging to an established QoS flow in the matching 5GC session.
This makes the existing SLAAC tests fail when PSC/QFI is missing.
Add header and RA length checks without requiring PSC/QFI for EPC.
Issues #4804
Process all AppSession media components before emitting each updated PCC
rule and QoS decision once. Preserve flow presence across components and
emit the final rule state. Use the create-time ID format for rules added
by updates, and check capacity before allocating a new PCC rule slot.
Validate PCC identifiers in SM policy create responses and update
notifications before changing state. Reject missing or inconsistent IDs,
duplicate map keys including NULL-valued removals, and decisions exceeding
the existing PCC rule capacity.
Return HTTP 400 for invalid notifications without replacing the current
policy or invoking QoS-flow binding. Fail invalid create responses before
updating policy-association or session state.
Keep existing per-media flow replacement and QoS processing unchanged.
Issues #4796
Handle Session Report Request failures without aborting the UPF or SGW-U.
Replace fatal assertions in Error Indication, downlink data and usage
report paths with error logging, preserving existing packet ownership
and caller control flow.
Delete newly allocated local transactions if report construction or
TX update fails. Leave commit failure cleanup to the transaction layer.
Issues #4792
Return OGS_ERROR when remote transaction creation fails in PFCP and
GTPv1/v2 receive paths, allowing callers to discard the received message
without aborting on transaction or timer pool exhaustion.
Link transactions before allocating timers in PFCP remote and GTP
local/remote constructors. This ensures failure cleanup unlinks only the
partially initialized transaction and preserves the peer's existing list.
Issues #4791
tests/s13 attaches a UE through the MME against open5gs-eird over S13
and checks what follows Security Mode Complete: ESM Information Request
when the device is admitted, Attach Reject #6 when it is not. Seven
cases cover the three statuses, an unknown device, and the per-subscriber
overrides of the eir collection. The EPC test harness starts the EIR
when an eir section is present, and the test UE now records the Attach
Reject cause.
ogs_sbi_context_validation() required an SBI server and an NRF or SCP
for every NF but the SMF, which may run in 4G only. An EIR that only
serves S13 is in the same situation. Exempt it, but only when no SBI
server is declared: an EIR that announces a server without an NRF or SCP
is still a configuration error.
open5gs-eird answers ME-Identity-Check-Request from the MME out of the
same eir collection that serves the AMF, so one record admits or blocks
a device on both cores. The Terminal-Information IMEI (14 digits) and
Software-Version (2 digits) are recomposed into the stored PEI form
"imeisv-<16 digits>"; an IMEI without Software-Version is looked up as
"imei-<15 digits>" with the Luhn check digit computed.
A known device is answered with Equipment-Status, an unknown one with
DIAMETER_ERROR_EQUIPMENT_UNKNOWN (5422), a database failure with
DIAMETER_UNABLE_TO_COMPLY. The mongoc client is shared between the SBI
thread and the freeDiameter threads under a mutex.
S13 is enabled by eir.freeDiameter, either a configuration file or the
inline identity/realm/listen_on mapping accepted by the HSS.
Query an EIR over S13 (TS 29.272) after Security Mode Complete on an
initial attach, before the S6a ULR. The decision table mirrors the AMF's
N5g-eir handling: WHITELISTED and GREYLISTED are admitted, BLACKLISTED is
rejected with #6 Illegal ME, DIAMETER_ERROR_EQUIPMENT_UNKNOWN follows
unknown_action (#7), a missing IMEISV follows missing_pei_action (#7) and
any other failure follows failure_action (#17). Verdicts are cached per
IMEISV with an LRU and a configurable TTL, so the attach fast path with a
valid security context can apply a fresh verdict without an SMC.
An invalid policy value is a configuration error, as in the AMF.
Update dict.c
Update meson.build
Reuse existing header keys and free replaced values to prevent leaks
on duplicate names. Copy the new value before freeing the old one to
support aliased inputs.
Limit decoded request headers to 64 KiB, including per-field overhead,
duplicate names and empty values. Check lengths before allocation and
advertise the limit through SETTINGS_MAX_HEADER_LIST_SIZE.
Reset oversized streams with ENHANCE_YOUR_CALM without sending from
the receive callback, avoiding reentrant nghttp2 calls.
Issues: #4788
Query an EIR over S13 (TS 29.272) after Security Mode Complete on an
initial attach, before the S6a ULR. The decision table mirrors the AMF's
N5g-eir handling: WHITELISTED and GREYLISTED are admitted, BLACKLISTED is
rejected with #6 Illegal ME, DIAMETER_ERROR_EQUIPMENT_UNKNOWN follows
unknown_action (#7), a missing IMEISV follows missing_pei_action (#7) and
any other failure follows failure_action (#17). Verdicts are cached per
IMEISV with an LRU and a configurable TTL, so the attach fast path with a
valid security context can apply a fresh verdict without an SMC.
An invalid policy value is a configuration error, as in the AMF.
Check 1 + *ptr before reading ptr[1] so the length-prefix byte is
covered. Matches ogs_gtp1_parse_pdp_context(); reached from the Gn
SGSN Context Response handler.
smf_pco_build() read the PAP/CHAP/IPCP payload without checking the
container length, and walked IPCP options up to the IPCP packet length
even when it exceeded the container.
Skip containers too short to read and IPCP packets whose length is
below 4 or beyond the container. H-SMF returns PduSessionCreateError
instead of asserting when the EPCO cannot be built, and does not start
QoS flow binding on that error.
A non-contiguous mask in a UE packet filter makes
ogs_ipfw_encode_flow_description() return NULL, and the caller
asserted it, aborting the SMF. Reject the request instead, on both
the 5GS PDU session modification and the EPC Bearer Resource Command
paths.
The #4672 guard in gsm_handle_pdu_session_modification_request()
already logged this as invalid UE input but still called
ogs_assert_if_reached(), so a UE could abort the SMF.
Deleting the QoS rule and modifying the QoS flow description for the
same QoS flow in one request sets both REMOVE and QOS_MODIFY
(pfcp_flags 0x8080). The #4672 fix only skips the flow-description
delete operation, so a modify or create still sets QOS_MODIFY. Reject
the request through the existing cleanup path instead.
A UE could abort the SMF by exhausting the packet filter pool, since
smf_pf_add() returns NULL on exhaustion but its callers asserted on it.
- 5GS: gsm_handle_pdu_session_modification_qos_rules() returns an
error, so the modification is rejected and the session is cleared.
Reachable with 'modify existing QoS rule and add packet filters'.
- EPC: smf_s5c_handle_bearer_resource_command() sends a Bearer
Resource Failure Indication. Reachable with 'add packet filters',
since an identifier that matches no existing filter always
allocates a new one.
smf_pco_build() overflowed two stack arrays from a single request.
smf.ids[] (32 entries) had no bound check at all. A DNS/DNS6 server
address request yields two response containers, so 17 request containers
overflow it even though ogs_pco_parse() caps the request at 32.
pco_ipcp[] (4 entries) was guarded with <=, off by one. A fifth IPCP
container writes pco_ipcp[4] and a sixth aborts the process.
Route every smf.ids[] append through smf_pco_id_add() and drop what does
not fit; IPCP and P-CSCF check the return value so that num_of_ipcp and
p_cscf_index do not advance on a dropped append. Enforce the IPCP count
bound and ignore the extra containers.
Limitation: the num_of_option guards use the same <= comparison, and the
PAP/CHAP/IPCP payload length checks are still missing. Both are separate
issues.
Reject an empty servingNetworkName in both AUSF and UDM handlers
before it reaches the KDF functions. This prevents a zero-length
KDF parameter from triggering an assertion and terminating the UDM.
Late H-SMF responses can arrive after session release has advanced,
causing unexpected-state assertions or leaving AMF requests unfinished.
Store the AMF release stream before sending the H-SMF update and consume
it when PFCP deletion completes. Handle delayed release, activation and
deactivation responses in the release states without restarting the
session procedure.
Refresh the AMF transaction count after UE context adoption, immediately
before releasing sessions. This prevents inherited SBI transactions from
being mistaken for newly issued release requests and blocking
authentication.
8-byte TBCD input without the 0xF filler needs 17 bytes, but the
IMSI/MSISDN BCD buffers are 16.
Take the output size and return NULL when the digits do not fit,
without writing anything. Callers reject the message or keep the
stored identity instead of storing a truncated one. SGWC now rejects
an IMSI longer than OGS_MAX_IMSI_LEN, as SMF already does.
MSISDN and IMEI(SV) are still truncated to their maximum length
before decoding, as before.
Reject RAT Type 0 in GTPv1 Create PDP Context and GTPv2 Create Session
requests before passing the value to smf_sess_add_by_apn().
This prevents invalid network input from reaching
ogs_assert(sess->gtp_rat_type) and terminating the SMF process.
Keep the existing assertion as an internal invariant.
AF resPrio/preemptCap/preemptVuln in MediaComponent now update the
ARP of the PCC rule and the SMF modifies the QoS flow when only the
ARP has changed.
- resPrio is mapped through the new pcf.reservation_priorities config
(no standard mapping); an unmapped resPrio leaves the priority level
unchanged and is logged.
- preemptCap/preemptVuln are applied directly.
- An update whose media component carries only ARP keeps the bitrates
negotiated so far. This is decided by field presence on the parsed
MediaComponentRm, so an unmapped resPrio or "0 bps" is handled.
Related PR: #4793
Validate the Framed-IPv6-Prefix AVP length before interpreting its
OctetString value as ogs_paa_t.
Reject malformed values with DIAMETER_INVALID_AVP_VALUE so a short AVP
cannot drive an out-of-bounds read through paa->addr6.
Validate the Session-AMBR length before accessing the fixed
downlink and uplink value fields.
Reject truncated Session-AMBR IEs and perform byte-order conversion
on the copied structure instead of reading through the packet buffer.
Update the NAS generator source so regenerated code keeps the fix.
Encode Framed-Route and Framed-IPv6-Route values as
"<prefix> <gateway> <metric>" at Gx and PFCP boundaries while keeping
route prefixes in session data.
Add shared build/parse helpers and accept legacy bare prefixes on
receipt. Validate IPv4 addresses before applying class A/B/C default
prefix lengths, using ogs_inet_pton() and be32toh() from lib/core.
Leave IPv6 addresses without a prefix length unchanged.
Reject empty prefixes and embedded NULs, then use ogs_strndup() for
bounded copying without requiring NUL-terminated input.
Send framed routes in CCA-Initial only and convert both EPC and 5GC
PDR paths. Use ERROR-level logs for rejected routes and document
subscriber-data delivery and wire-format compatibility.
Add regression tests for format conversion, classful defaults,
invalid inputs and non-NUL-terminated buffers.
Upgrade UPFs before SMFs and PCRFs: older UPFs cannot parse the new
wire-format strings.
Related PR: #4757
Include the string declarations used by the harness and suppress
expected core error logs from rejected fuzz inputs.
Clarify the flow-description path and input-length comment.
Related PR: #4752
Fix undefined behavior caused by shifting a negative value while
building IPv4 prefix masks.
Reject port numbers with leading zeros to prevent the decimal
validator and the base-detecting ipfw parser from interpreting the
same input differently.
Related PR: #4752
Pass short GTPv1 inputs to ogs_gtp1_parse_msg() so the fuzzer also
exercises header-length validation. Rename the GTPv2 message variable
to distinguish it from the GTPv1 counterpart.
The fuzzer exposed undefined behavior in 32-bit TLV decoding when the
first octet has its high bit set. It was promoted to int before being
shifted by 24, which can overflow a signed int.
Cast the first octet to uint32_t before shifting in both decoding paths
and add regression coverage for high-bit values.
Related PR: #4751
smf_pfcp_sessions_active is incremented only in smf_sess_add_by_psi(),
which serves the 5GC paths (smf_sess_add_by_sm_context() and
smf_sess_add_by_pdu_session()). EPC sessions are created through
smf_sess_add_by_apn(), used by smf_sess_add_by_gtp1_message() and
smf_sess_add_by_gtp2_message(), and that path never incremented it.
smf_sess_remove() decrements the gauge for every session regardless of
how it was created, so on an EPC deployment each teardown drives the
value one step further below zero, and it only resets when the SMF
restarts. The neighbouring GTP1/GTP2 gauges are paired correctly and
are unaffected.
Increment the gauge in smf_sess_add_by_apn() as well, mirroring the
placement in smf_sess_add_by_psi().
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Diameter Initial answers arriving after the Create Session transaction
expired no longer assert. The session is abandoned: only Diameter
sessions confirmed by an Initial answer are terminated, then the local
session is released. Rejected Create Session requests are released the
same way instead of staying in wait_epc_auth_initial.
Also store the Diameter session state before publishing the answer
event, always deliver S6b STA (Result-Code logged only), and drop
queued Diameter events for already removed sessions.
Not covered: an answer that never arrives still leaves the session
waiting (no CCR timeout).
Related PR: #4742
Without ISTM, the first Usage Report could use an uninitialized
time_start as its duration baseline and report the time since the
epoch. This also affects termination when no earlier usage report was
sent. Positive configured time triggers could then fire spuriously.
Start measurement and its timers before accounting the first packet,
and report zero Duration until measurement starts. Omit Time of
First/Last Packet when no packet was observed. Keep Start/End Time in
an empty termination report as a zero-length interval at report time.
Use monotonic timestamps for elapsed duration while retaining realtime
Start/End Time. Replace the write-only last-report realtime snapshot
with its monotonic counterpart. Keep the rollback guard because
ogs_get_monotonic_time() can fall back to gettimeofday().
Keep first-packet measurement and recurring timer-expiry logs at DEBUG
to avoid synchronous log output on normal accounting paths at INFO.
Identify the URR and interval in timer-start diagnostics, including
restarts, and retain warnings and errors for abnormal conditions.
Cancel accounting timers and clear accumulated state immediately after
an applied Remove URR, before freed rule storage can be reused. Retain
this cleanup if a later IE rejects the request, and preserve accounting
when the Remove itself is rejected. Check cleanup IDs in one helper.
Unreported usage accumulated before removal is discarded. The Session
Modification Response still carries no final Usage Report for removed
URRs; implementing that reporting remains a separate change.
Related PR: #4714
Co-authored-by: Erol Yağız Aydın <ygzaydns@gmail.com>
Replace duplicated atoll() parsing with shared helpers that reject
missing, malformed, negative and overflowing values, duplicate value
keys, and duplicate timer keys within the same time mapping.
Keep NAS timer values in seconds and convert local timer intervals
to microseconds after validating the poll/epoll timeout limit.
Preserve existing zero handling and NAS encoding validation.
Allow configuring T3513, T3522, T3550, T3555, T3560 and T3570 through
amf.time.<timer>.value. Document their ranges and existing defaults
without changing default intervals or retransmission counts.
Include configuration paths and filenames in validation errors.
Recognize T3396 in the common configuration parser to avoid spurious
unknown-key warnings.
Related PR: #4709
* Move UPF loop variable declarations outside for statements.
* Support older MongoDB C drivers in EIR tests.
* Remove an unused cleanup label and fix a misspelled default label.
* Save the H-SMF modification stream ID before sending or queuing N1N2
to handle NAS completion arriving before the AMF response.
* Clear the stream ID even if the stream has expired, and prevent
late AMF responses from restoring a consumed ID.
Related PR : #4708
Handle EIR checks within the AMF security mode state, preserve failure
policies, and clean up pending transactions when leaving the state.
Prepare missing database constraints at EIR startup while preserving
existing settings. Log setup failures and continue with runtime validation.
Centralize numeric identity validation and improve failure diagnostics.
Move EIR tests into a dedicated suite with its own configuration, covering
database queries, HTTP/2 responses, and registration outcomes.
Update configuration defaults, packaging, and documentation.
PR: #4708
Return NGAP PathSwitchRequestFailure with the received UE identifiers
and per-session causes when the UE context is missing, the source gNB
has been removed, or the security context is invalid.
Send NGAP and S1AP failure responses to the requesting target RAN on
a valid UE-associated SCTP stream. Handle stream wrap, reduced limits,
and associations without an available UE stream.
Correct the MME security-context failure path to respond to the target
eNB instead of the source eNB.
Issues: #4769
The AMF may retain ran_ue while waiting for SMF deactivation after
removing its gNB. A PathSwitchRequest received in this window reaches
ran_ue_switch_to_gnb() and aborts on the missing source gNB.
Reject the request before changing UE state and leave the pending
deactivation procedure to complete the existing context cleanup.
Add the corresponding source eNB check to the MME PathSwitchRequest
handler and assert the source eNB in enb_ue_switch_to_enb(). The MME
currently removes enb_ue with its eNB, so this is a defensive check.
Normal Xn/X2 handover remains supported: the checks require the source
RAN node to exist and allow the request to come from the target node.
Issues: #4769
transform.py flattens a oneOf mixing an inline array and $ref items
into an object with one property per alternative, and that object was
the wire format: SmSubsData went out as
{"SessionManagementSubscriptionDataList":[...]} instead of the array.
Keep the object as the C-side container. When the alternatives differ
by JSON type and are an array of models, a model or a char *,
transform.py adds x-open5gs-union: true and model-body.mustache
generates convertToJSON/parseFromJSON that put the one member set on
the wire as the JSON value itself and pick the member by JSON type.
Structs, headers and the model set are unchanged; the bodies of
SmSubsData, ImmediateReport and SteeringContainer are regenerated.
Alternatives sharing a JSON type (HssAuthenticationVectors) or using
enum, map or nullable schemas keep the wrapper object; transform.py
reports them as warnings.
Issues: #4771
The registered-state heartbeat asserted that ogs_nnrf_nfm_send_nf_update()
returned true. A full SBI request pool makes the update fail to build,
which aborted the NF. Use ogs_expect, as the register path in this file
already does.
The heartbeat timer is rearmed just above, so the update retries on the
next interval; the NF stops updating only until the pool drains.
Issues #4776
on_header_value() asserted when a part repeated Content-Type or
Content-Id. A peer can send such a body, so treat it as a multipart
parse error and answer 400 instead of aborting.
The parser still runs to the end of the body after the error, as
in the existing parse_error handling; no unit test covers this
path since sbi-message-test uses its own stub callbacks.
Issues #4775
Replace session-wide cleanup with ID-based removal of newly created
rules. Keep applied updates, removals and existing BAR replacements.
Clear request-local FAR flags so rejected requests cannot leave an
End Marker pending for the next request.
Reject duplicate Create IDs and removal of referenced rules. Keep GTP-U
hash entries owned by live rules and reject cross-session local TEID
collisions. Synchronize PDR/FAR tunnel updates when they are applied.
Start new UPF URR timers after acceptance and update the QoS-flow gauge
from the surviving QER count on modification. Add rule lifecycle logs
and regression tests.
Issues: #4766 and #4767
Reject a Session Establishment that reuses a CP F-SEID owned by another
PFCP node before rebinding pfcp_node, and reject a UE IPv4/IPv6 address
held by a session of another PFCP node with Cause 64. A session of the
same node may still take over an address, e.g. one left by an orphaned
session.
Clear UE IP hash entries with ogs_hash_unset_if_owner() so that removing
or re-addressing one session cannot drop another session's mapping.
Only UPF is affected; SGWU has no UE IP hash. Orphaned UPF sessions left
when the SMF removes a session without PFCP Session Deletion, and session
contexts left after a failed Establishment, are pre-existing and are not
addressed here.
Issues #4762
The indirect tunnel is removed handover.duration after N2 handover
completion. If the next handover started before that delayed REMOVE was
answered, a second REMOVE|CREATE was sent for the same tunnel. The late
response of the delayed REMOVE then deleted the new tunnel from the
session, because smf_sess_delete_indirect_data_forwarding() deletes
whichever tunnel the session holds, and the handover failed on the
Created PDR. With enough QoS flows for PDR IDs to be reused, the delayed
REMOVE could also reach the UPF after the new tunnel had taken over its
PDR IDs.
Remember the delayed REMOVE transaction and, when the next handover
finds the old tunnel, turn that transaction into the REMOVE|CREATE
replacement instead of sending a second one: add the CREATE flag,
attach the new stream, and send it now if it is still waiting for the
timer. The existing REMOVE|CREATE handling does the rest. If the
transaction is gone (e.g. PFCP timeout), a new REMOVE|CREATE is sent as
before. The remembered ID is claimed once before the lookup and cleared
when the transaction is answered or timed out, so it never refers to a
transaction that no longer exists.
In the HR roaming V-SMF, the AMF stream for a UE-requested modification
was stored on the 204 to HsmfUpdateData, and the H-SMF stream for a
UE-requested release was stored on the 200 to N1N2MessageTransfer.
VsmfUpdateData can overtake that 204, and the AMF's N2/N1-RELEASED
updates can overtake that 200, so the reply on the stored stream was
skipped and the procedure stalled.
Store both streams when the request is sent and leave the response
handlers as no-ops.
Session-level PFCP messages were dispatched by SEID alone, so a
request for a SEID from a PFCP node other than the one the session
belongs to was applied. Such a request is now handled as Session
context not found (Cause 65).
- UPF/SGWU: Session Modification/Deletion Request
- SMF/SGWC: Session Report Request
Issues #4761
GTP-U peers added to gtpu_peer_list were only freed at process exit,
so every distinct peer address ever seen held one gtp_node pool entry
(global.max.gtp_peer, default 64). Renumbering eNB GTP-U addresses, or
gNB changes across handovers, eventually exhausted the pool and new
sessions failed with "CHECK CONFIGURATION: sgwu.gtpu".
Count the FARs/PDRs referencing each peer and remove the node when the
last reference goes away. A FAR/PDR moving to another address releases
the old peer; a same-address update leaves the count unchanged.
A FAR whose Outer Header Creation is removed still holds its peer until
the FAR itself is removed.
Issues: #4764
A rejected PFCP Session Report Request was incorrectly treated as a
request to release the session. In the 5GC path, the PFCP event had no
deletion trigger, causing an assertion failure during session deletion.
Separate PFCP error handling from the session release decision.
Malformed reports now receive an appropriate error response without
releasing the session. Gy Final-Unit-Indication and the absence of a
Gy peer still trigger a locally initiated session release.
Return Mandatory IE missing or Conditional IE missing with the
corresponding Offending IE for missing Report Type, PDR ID, or
Downlink Data Report IEs. Also log the actual PDR ID when lookup fails.
Issues #4744
When a UE shows up on a new NG connection while the AMF still holds the
old one, HOLDING_NG_CONTEXT() detaches the old ran_ue and removes it
later, either on UEContextReleaseComplete or when t_ng_holding expires.
The gNB never sends UEContextReleaseRequest for that context, so the
Update SM Context (upCnxState=DEACTIVATED) that normally precedes an AN
release is never sent. A session the UE keeps but does not re-activate
on the new connection stays ACTIVATED in the SMF and the UPF, pointing
at a GTP-U endpoint that no longer exists: downlink packets are
forwarded into a black hole instead of being buffered, and no downlink
data notification is raised, so the UE is never paged.
The UE does not have to be misbehaving to get there. A Registration
Request that carries PDU Session Status but no Uplink Data Status is
ordinary, and gmm_handle_registration_update() acts only on the sessions
listed in Uplink Data Status, so the rest are left as they are.
Note the sessions whose AN resources were established on the NG context
being put on hold - psimask.activated is exactly that set, and
amf_ue_note_stale_user_plane() writes it down - and deactivate whatever
is still noted when that context is removed. Deciding at hold time
rather than at release time keeps the outcome independent of whether
the gNB answers UEContextReleaseCommand before or after the UE asks for
the user plane again.
The note says the SMF may still believe the user plane is on that
context. While that context lives, the note is dropped only where the
SMF has said otherwise: on the success of a procedure that itself moves
the user plane - an activation, a deactivation, a completed handover -
and update_sm_context_supersedes_stale_user_plane() is that list, after
its N1/N2 content has been handled, since an HTTP success alone is not
the procedure succeeding. A MODIFIED or an N1-only exchange proves
nothing about the DL endpoint and leaves the note alone, and so does
dispatching: OGS_OK from
amf_sess_sbi_discover_and_send() means the transaction started, not
that the SMF took it. When the held context is removed the note is
consumed with it, whichever way the decision goes, so the pool id of a
freed context is never kept, and amf_ue_remove() severs the reverse
reference a held context keeps for the same reason.
That leaves the window where a procedure is in flight but not yet
answered, and which NG context it was issued on decides. A transaction
on some other context is a newer procedure that owns where the user
plane ends up; racing it with DEACTIVATED could tear down the user plane
it is setting up, so the sweep steps aside and the responsibility moves
to that procedure. A transaction on the context being removed is the
opposite - a late ACTIVATED for a GTP-U endpoint that is gone - and must
not stop the cleanup. amf_sbi_xact_ctx_t already records which RAN-UE a
transaction was issued on. For the same reason an answer for the noted
context does not clear the note, and a timed-out cleanup is not reported
to the NG context the UE is using now: the UE is not waiting on it.
The deactivation itself is normally sent on behalf of that current NG
context rather than the one being removed, since
amf_sess_sbi_discover_and_send() records the RAN-UE in sess->ran_ue_id
and the Namf callbacks reach the UE through it. If no serving NG context
remains either, the cleanup stays best-effort. Its response is handled
ahead of the generic N1/N2 and error parsing, which would answer an
unexpected or malformed response with an Error Indication towards that
same live connection.
NGAP_UE_CTX_REL_NG_CONTEXT_REMOVE is not the only way a held context is
destroyed. amf_sbi_send_deactivate_all_ue_in_gnb(), the partial NG Reset
and ngap_handle_error_indication() all find no AMF-UE context on a held
entry, since holding invalidates amf_ue_id, and remove it directly. All
four call the deactivation immediately before ran_ue_remove(), so that
the cleanup and the removal are visible together at the call site and
ran_ue_remove() stays a plain destructor. Only the two places that hold
an NG context leave a holder behind, so a context that was never held
passes through untouched, as do the handover release actions.
The hold has to be noted in two places, and one of them was an inlined
copy of HOLDING_NG_CONTEXT(). The copy exists because the macro takes a
single AMF-UE context and uses it for two roles: the context whose NG
connection is being held, and the context that records the hold. Those
are the same everywhere except in amf_ue_release_old_context(), where
the NG context and the sessions still belong to old_amf_ue while the
hold has to be recorded in amf_ue, since old_amf_ue is removed as soon
as its sessions have been moved across.
Rather than note it twice, split the two roles into parameters as
HOLDING_NG_CONTEXT_FOR() and keep HOLDING_NG_CONTEXT() as the ordinary
spelling on top of it, so the copy goes away. The existing callers are
unchanged, and both spellings stay macros so that the logs and
assertions keep reporting the file and line that triggered them.
mme_ue_set_imsi() carried the same copy of HOLDING_S1_CONTEXT(), for the
same reason and with the same two roles, so it gets the same treatment
as HOLDING_S1_CONTEXT_FOR(). Nothing about the stale user plane is
carried over: Release Access Bearers is per-UE rather than per-session
in EPC, and the exposure there is smaller, so only the duplication is
addressed.
Each half of both macros names the UE after the context it is about: the
one released on the way in is the holder's, the one put on hold is the
serving context's.
Folding the copies in changes their log lines. Both reported an existing
or already-removed holding context through ogs_error() where the macros
use ogs_warn(); in the AMF "RAN-NG Context has already been removed" now
reads "NG Context has already been removed" and the lines that named the
UE by the caller's display name now follow the rule above; in the MME the
macro's "Holding S1 Context" line now appears alongside the caller's
"Holding old S1 context". The old-context callers then clear the RAN-UE
reference themselves - CM_IDLE() and ECM_IDLE() must see the context as
released, and nothing associates a new one with the old UE context -
while the macros leave the field alone for the ordinary callers, which
associate a new context right after.
tests/slice/holding-test.c covers both halves of the AMF fix: a
Registration without Uplink Data Status, where downlink traffic has to
raise a notification afterwards, and one with it, where the user plane
must survive the removal of the held context.
Deactivating it exposed that a Home Routed Roaming session never
started a network triggered Service Request afterwards, which also
holds for an ordinary idle transition. Everything for that request
already exists on the home side - the V-SMF delegates the deactivation
over HsmfUpdateData with upCnxState, the H-UPF buffers and reports to
the H-SMF, the report handler builds the N1N2 message transfer, and the
AMF to send it to was passed in PduSessionCreateData.amfNfId - but two
steps were missing in between.
smf_nsmf_handle_update_data_in_hsmf() copied the received upCnxState
into sess->nsmf_param for the PFCP modification and never into
sess->up_cnx_state, which is what
smf_5gc_n4_handle_session_report_request() switches on, so the H-SMF
still believed the user plane was up and dropped the report. Record it
in the session as well, as smf_nsmf_handle_update_sm_context() does in
the V-SMF, once the requested combination has been accepted, so that an
HsmfUpdateData rejected as Bad Request leaves the session untouched,
and log every recording. This also keeps the H-SMF in step when the UE
comes back, since the activation is delegated with upCnxState the same
way, so the log line appears on the home side for every session
activation and shows at a glance that this change is in.
And the N1N2 message transfer itself never left the home PLMN: the
discovery option named the AMF NF instance but not where to look for
it, so the discovery stayed in the home PLMN, found no AMF and the
transfer failed with 504. Name the serving PLMN as the target and the
home PLMN as the requester, the same way the AMF names the home PLMN
when it discovers the AUSF or the UDM of a roaming UE.
tests/slice/holding-test.c passes in the roaming configuration with
the buffering, the report and the N1N2 message transfer all on the
home side, crossing to the serving AMF through the SEPP.
Issues #4741
During handover the target ran_ue/enb_ue is linked to the same
amf_ue/mme_ue before the UE has moved, and after HandoverCancel it is
only unlinked and removed once the RAN node answers
UEContextReleaseCommand with UEContextReleaseComplete. A RAN node that
withholds the Release Complete therefore keeps an addressable context
that still resolves to the UE.
The setup response handlers only verified the message identifiers, the
sending RAN node's ownership of the context, and the existence of the
PDU session or bearer. They did not verify that the context is the one
currently serving the UE. A RAN node could therefore send an
unrequested PDUSessionResourceSetupResponse or E-RABSetupResponse over
such a context, and the AMF/MME would forward the supplied transport
layer address and TEID, redirecting the downlink of a session that is
still served by another RAN node.
Add RAN_UE_IS_SERVING()/ENB_UE_IS_SERVING(), which require that the
context is both the serving association and not already being released,
and apply them in InitialContextSetupResponse and in
PDUSessionResourceSetupResponse/E-RABSetupResponse. Rejected responses
are answered with an Error Indication and produce no SBI, PFCP, or S11
side effect.
Also set initial_context_setup_response_received after validation
instead of before, so a rejected response leaves no state behind.
This is not a general request-correlation mechanism. A RAN node that
has been selected as a handover target retains other ways to influence
the user plane, and HandoverNotify is deliberately left alone since
rejecting it would change the outcome of a HandoverCancel/HandoverNotify
race.
Each Error Indication for a bearer started a new deactivation procedure.
When multiple Delete Bearer transactions timed out, they sent overlapping
PFCP removal requests. The first response removed the bearer, and a later
response hit ogs_assert(bearer).
Track an Error Indication deactivation on the bearer and ignore duplicate
reports while it is in progress. Clear the mark when the PFCP procedure is
rejected or times out so that a later report can retry.
Read modify_flags before resolving session-level modifications, tolerate
a missing GTP transaction during local EPC session deletion, and release
the whole PDN connection when a Delete Bearer request for the default
bearer times out. This prevents a live EPC session from being left without
a default bearer.
Issues: #4753
Add strict hex decoding helpers that reject invalid lengths, non-hex
characters, and NULL inputs without modifying the output buffer.
Validate RAND, HXRES*, AUTN, and KSEAF before using them. Decode the
initial authentication vectors into temporary buffers before updating
the UE context, and validate KSEAF before storing a successful
authentication result.
Add core conversion tests for malformed, non-ASCII, and NULL inputs,
and verify that the output remains unchanged on failure.
Issues #4734
The synch-failure path (Authentication Failure cause #21) already caps
repeats per authentication procedure via auth_synch_fail_count, sending
AUTHENTICATION REJECT once the limit is reached. The ngKSI-already-in-use
path (cause #71) had no equivalent bound: it re-invoked AUSF on every
occurrence and returned without ever reaching the reject path, so a UE
that keeps answering each Authentication Request with cause #71 would
loop without limit, holding its context and repeating AUSF/UDM
round-trips.
Add auth_ngksi_fail_count and mirror the existing synch-failure guard:
count cause #71 failures and send AUTHENTICATION REJECT once the limit is
reached. The counter is reset at authentication-procedure entry
(OGS_FSM_ENTRY_SIG) alongside auth_synch_fail_count, so a legitimate
cause #71 in a later procedure starts from zero.
Re-running 5G AKA on cause #71 is permitted by TS 24.501, so the previous
behavior was standards-compliant; this change only makes the two
authentication-failure paths consistent and bounds a signalling loop
against a misbehaving UE. It is a robustness change, not a security fix,
and does not by itself constitute a DoS defense (other control-plane
paths such as re-registration are equally unbounded and belong to
edge rate limiting).
The NGAP and S1AP handover handlers resolve the UE context with a
global lookup by AMF_UE_NGAP_ID / MME_UE_S1AP_ID and then use it
without checking that the sending RAN node is the one that owns it.
A gNB or eNB can therefore drive handover signalling for a UE context
belonging to a different RAN node - cancelling it, failing it,
forwarding status transfer to its peer, or completing a handover
notification for it.
In ngap_handle_handover_request_ack(), target_ue is looked up by the
AMF_UE_NGAP_ID carried in the message and target_ue->ran_ue_ngap_id is
overwritten with the RAN_UE_NGAP_ID from the message before the later
checks (source_ue, amf_ue, PDUSessionList) can reject it, corrupting
the RAN UE NGAP ID mapping of another gNB's UE context even though the
request itself is eventually rejected.
Add the ownership check already used by
ngap_find_ran_ue_by_message_ue_ids() and
s1ap_find_enb_ue_by_message_ue_ids() right after the lookup in:
- ngap_handle_handover_required()
- ngap_handle_handover_request_ack()
- ngap_handle_handover_failure()
- ngap_handle_handover_cancel()
- ngap_handle_uplink_ran_status_transfer()
- ngap_handle_handover_notification()
- s1ap_handle_handover_required()
- s1ap_handle_handover_request_ack()
- s1ap_handle_handover_failure()
- s1ap_handle_handover_cancel()
- s1ap_handle_enb_status_transfer()
- s1ap_handle_handover_notification()
In ngap_handle_handover_request_ack(), also move the assignment of
target_ue->ran_ue_ngap_id after the Source-UE and AMF-UE lookups so
that the Target-UE context is not left with a new RAN UE NGAP ID when
the handler bails out. The two Error Indications on that path now
report the RAN_UE_NGAP_ID received in the message, since the one in
the context is not assigned yet at that point. The second
!RAN_UE_NGAP_ID check is removed as the IE is already validated at the
top of the handler. The S1AP side needs no such reordering:
s1ap_handle_handover_request_ack() already assigns
target_ue->enb_ue_s1ap_id after the Source-UE and MME-UE contexts have
been resolved.
The S1AP Error Indication reports both UE S1AP IDs received in the
message, as s1ap_find_enb_ue_by_message_ue_ids() does. HandoverFailure
carries no ENB_UE_S1AP_ID IE, so only the MME UE S1AP ID is reported
there.
ngap_handle_path_switch_request() and s1ap_handle_path_switch_request()
are intentionally left alone: in Xn/X2 based handover the
PathSwitchRequest is sent by the target node while the UE context is
still owned by the source node, so the sender is not expected to be the
owner there.
Run CIFuzz on pushes to the main branch so that GitHub Code
Scanning has a current default-branch analysis.
Also update the SARIF upload action from CodeQL Action v3 to v4.
emm_handle_authentication_response() used the length supplied in the
NAS Authentication Response as the comparison length for memcmp().
A UE could therefore submit a truncated RES and have only that prefix
compared with the expected XRES.
Reject zero-length responses and responses whose length differs from
mme_ue->xres_len, then compare the complete expected response.
Even if an attacker guesses a truncated RES prefix accepted by the
vulnerable comparison, the attacker cannot complete the Attach
procedure because the subsequent NAS Security Mode exchange requires
integrity keys derived from KASME.
TS 23.502 4.3.2.2.1 returns the created SM context to the AMF at
step 5, before the PDU Session Establishment Accept is delivered by
N1N2MessageTransfer at step 11.
If the RAN-UE context disappears while CreateSMContext is in flight,
the AMF removes its local session. The later N1N2 transfer is then
rejected, but the SMF only logs the error and retains the session. This
leaves the UE IP address, PFCP session, PCF policy and UDM association
without a release procedure.
For non-home-routed sessions, trigger a locally initiated release when
the AMF returns a response other than 200 OK or 202 Accepted. Keep the
session on 202 because the AMF may still be attempting to reach the UE,
and preserve the existing home-routed roaming behavior because the peer
SMF must also be released.
After PFCP deletion, run SBI cleanup with
SMF_UECM_STATE_DEREG_BY_N1N2. This releases the PCF and UDM resources,
sends SMContextStatusNotify to the AMF and finally removes the SMF
session.
Remove newly allocated contexts when request validation fails.
In the AMF, a PDU Session Establishment Request creates an amf_sess
context before validating the requested DNN and S-NSSAI. If validation
fails, remove the session only when it was created while handling the
current request. Leave pre-existing session contexts untouched.
In the MME, a Create Bearer Request allocates a bearer before parsing
the Bearer Level QoS IE. If parsing fails, send a Create Bearer
Response with cause "Mandatory IE incorrect" and remove the newly
allocated bearer.
This prevents rejected requests from retaining AMF session-pool
entries or MME EPS bearer identities until the UE context is released.
The S6a, Cx and SWx authentication handlers accessed RAND and AUTS at
fixed offsets without validating the containing AVP value and length.
A malformed Re-Synchronization-Info or SIP-Authorization AVP could
therefore cause out-of-bounds reads and expose adjacent heap contents
through error logging.
Validate the AVP value and require the exact RAND plus AUTS length
before processing re-synchronization data.
ogs_gtp1_gsn_addr_to_ip() returns OGS_ERROR when an SGSN Address IE
does not contain a valid IPv4 or IPv6 address. The MME asserted that
the conversion succeeded, allowing a malformed SGSN Context Request
to abort the process.
Validate both the primary and alternative control-plane addresses
and return Mandatory IE incorrect when either address is invalid.
Convert the addresses into local variables before updating the UE
context to prevent an invalid request from partially modifying the
stored Gn TEID and addresses.
Validate the remaining block size before reading TLV headers or
advancing over their values.
Reject truncated headers, values extending beyond the input block,
and zero-length embedded blocks before any out-of-bounds access.
Apply the same validation to descriptor-based and fixed-length TLV
parsing.
Also avoid passing an uninitialized stack buffer to the logger when
hexdumping a zero-length input.
Add tests for truncated headers, trailing octets, over-long values,
fixed-length TV elements, and descriptor-based parsing.
ogs_pfcp_parse_volume_measurement() and
ogs_pfcp_parse_dropped_dl_traffic_threshold() copied 8-octet fields
selected by the flags octet without checking the declared IE length. A
short IE with every flag set read up to 48 and 16 octets past the end
of the IE. The flags octet itself was also read unchecked, which
dereferenced NULL for an absent IE, since the SMF usage report handlers
call ogs_pfcp_parse_volume_measurement() without testing
volume_measurement.presence.
ogs_pfcp_parse_volume() validated each volume field but not the flags
octet, and ogs_pfcp_parse_sdf_filter() validated the Flow Description
length field without validating that many octets actually follow it.
Validate the remaining reads against octet->len and return 0 on a short
IE, as ogs_pfcp_parse_volume() already did for its volume fields. The
callers compare the decoded length against the IE length, so a
truncated IE is now rejected instead of parsed from adjacent memory.
An Attach or Registration Request can arrive on an S1/NG connection
already associated with another subscriber. The request was dispatched
through that association without checking its mobile identity.
The subsequent identity update could relabel the associated UE context
and migrate another subscriber's sessions into it. This either aborted
the MME/AMF when the target already owned sessions or silently assigned
the existing sessions to the wrong subscriber.
Re-resolve the identity before dispatch. If it differs from a registered
context or a context with sessions, release the access connection and
drop the request so the UE can retry on a newly resolved context.
Keep the existing migration behaviour for unfinished procedures without
sessions, and add regression tests for the affected MME and AMF paths.
Issues: #4739
SMF session contexts kept Gx, Gy and S6b Session-Id pointers as aliases
of strings owned by the corresponding freeDiameter session state.
Those strings are released by state_cleanup(), while the SMF session
context can remain alive longer. This leaves sess->gx_sid, gy_sid or
s6b_sid dangling and allows later Diameter requests to read freed
memory. Recovery paths could also free the aliased pointer from the SMF
side even though the allocation was owned by the Diameter session
state.
Give each SMF Session-Id its own copy and release it from
smf_sess_remove(), so the SMF context and freeDiameter session state
have independent lifetimes.
PCRF had a similar ownership problem in its IP-to-Gx-Session-Id hash.
The hash stored pointers to both the address and Session-Id owned by the
Gx session state. Releasing or updating that state could therefore leave
dangling hash entries or modify a hash key in place.
Make each PCRF hash entry own copies of both its key and Session-Id.
Return a copy from IP lookups so callers can safely use the Session-Id
after releasing the hash lock, remove old entries before overwriting a
stored address, and release remaining entries during PCRF shutdown.
A production smf-ims also aborted while processing a
Credit-Control-Answer when fd_msg_sess_get() rejected its Session-Id:
[diam] ERROR: [fd_sess_new@sessions.c](mailto:fd_sess_new@sessions.c):405:
Invalid parameter '(fd_os_is_valid_os0(opt, optlen))', 22
[diam] ERROR: [fd_msg_sess_get@messages.c](mailto:fd_msg_sess_get@messages.c):1522:
Invalid argument
[smf] FATAL: smf_gx_cca_cb:
Assertion `ret == 0' failed.
A received Diameter answer must not be able to terminate the whole SMF
because its Session-Id cannot be resolved. Replace the
fd_msg_sess_get() assertions in the Gx, Gy and S6b answer callbacks
with error handling that logs and discards the affected answer.
The Session-Id lifetime issues were found while investigating the
production failure, but without the corresponding CCR/CCA packet capture
they are not claimed to be the proven source of the malformed
Session-Id seen in that incident.
Issues: #4737
Validate the Local F-TEID IE length before storing it in the PDR
in Created PDR and Update PDR handlers.
Also bound the copy length in the Create PDR and Created PDR
builders to the size of ogs_pfcp_f_teid_t.
This prevents out-of-bounds reads and writes when a malformed PFCP
message provides an oversized F-TEID IE length.
A timer expiry event may already be queued when its associated UE or
bearer context is removed. Deleting the timer does not retract an event
that has already been pushed to the MME event queue.
When the stale event is later dispatched, the context lookup returns
NULL and the existing assertion aborts the entire MME process.
Replace the assertions in the EMM, ESM and Gn timer handlers with
runtime guards that log and discard stale events. Also guard the
dependent SGW-UE lookup in the Gn timer path for consistency with the
S11 timer handler.
This prevents an already-removed context from causing an MME process
abort.
Validate the peer-provided 'Length of QoS rule' before using it as
the parsing bound for the packet filter list.
Previously, ogs_nas_parse_qos_rules() only rejected a zero rule
length. A rule could declare a length larger than the remaining
Requested QoS rules IE, causing
parse_qos_rules_packet_filter_list() to read beyond the received
message buffer.
The packet filter parser's internal bounds checks did not prevent
this because they were performed against the inflated rule length
provided by the peer. Reject any rule whose declared length exceeds
the remaining buffer before entering the parser.
Also fix ogs_nas_build_qos_rules() to use the operation code of the
rule currently being encoded. The function copied rule[i] into the
local target structure but several branches continued to inspect
rule[0].code. As a result, the first rule's operation code could
incorrectly determine the wire layout of subsequent rules in a
multi-rule IE.
Use target.code consistently so each QoS rule is encoded according
to its own operation code.
This prevents an out-of-bounds read reachable through a crafted PDU
Session Modification Request and fixes malformed encoding of mixed
operation-code QoS rules.
Add unit tests for valid and invalid Flow-Description strings handled by
ogs_ipfw_compile_rule().
Cover malformed grammar, protocol truncation, invalid prefixes, port
ranges, unsupported port lists, mixed address families, and the
protocol 41 paths that previously reached errx() and terminated the
process.
Also verify that valid IPv4, IPv6, numeric-protocol, port-range, and
"assigned" destination rules continue to compile and encode correctly.
Issues: #4711
Validate Flow-Description strings before passing them to the bundled
ipfw parser.
The parser accepts syntax that ogs_ipfw_rule_t cannot represent and may
silently truncate or discard parts of malformed rules. Some invalid
inputs can also reach errx() paths in the vendored parser and terminate
the process.
Validate the supported IPFilterRule subset, including:
- action and direction
- protocol names and numbers
- IPv4 and IPv6 addresses and prefixes
- source and destination address-family consistency
- port numbers and ranges
- unsupported trailing tokens and port lists
- unsupported source-side "assigned"
Protocol 41 with an IPv4 literal is rejected because the bundled parser
uses protocol 41 as an address-family selector and passes the literal to
the IPv6 address parser. Although an IPv4 outer address is valid for
IPv6 encapsulation, this combination is not currently supported by the
bundled parser and can terminate the process.
Propagate compile_rule() failures to the caller and only swap uplink
rules after successful compilation.
The Flow-Description form reported in #4711 now fails cleanly with a
diagnostic and is not installed. This does not add support for
"assigned" in the source position.
The parser already uses static storage and is not reentrant, and its
current callers run serially in the event loop, so the parse-error flag
does not introduce an additional concurrency limitation.
Reported-in: #4711
Validate the Outer Header Creation IE before copying it into the
internal FAR structure.
Only the supported GTP-U/IPv4, GTP-U/IPv6, and dual-stack variants are
accepted. Reject unsupported Description combinations and verify that
the IE contains the TEID and all addresses required by its flags.
Previously, a truncated GTP-U/IPv6 IE could be partially copied into a
zero-initialized structure. This produced an unspecified IPv6 address
and could leave an incompletely initialized GTP-U node, eventually
triggering an Unknown family assertion on a subsequent request.
Return INVALID_LENGTH for truncated IEs and SERVICE_NOT_SUPPORTED for
unsupported Outer Header Creation variants.
Issues: #4699
Use the local bearer context to determine whether a Delete Bearer
Response should remove a dedicated bearer or delete the entire PDN
session.
An MME may return a failure response without Linked EPS Bearer ID or
Bearer Contexts. In that case, relying on the response IEs causes SGW-C
to remove only the default bearer and leave an empty session in the UE
session list.
The stale session later triggers an assertion failure while handling a
Release Access Bearers Request.
Apply the same default-bearer check to both the normal response path
and the path where the associated S5-C transaction has already expired.
Issues: #4727 and #4667
On a CPU-constrained SGWU host, single-packet read per poll callback caps DL
throughput because the SGWU worker thread spends a non-trivial share of its
time in in epoll syscall and wakeups rather than GTP-U + PDR-walk processing.
Under DL load the worker pegs near 100% CPU while the co-resident gNB
user-plane has headroom but is starved for data.
Draining up to N packets per callback amortises the dispatch and
PDR-walk overhead and keeps the kernel rx queue from saturating
between wakeups. UPF_SK_DRAIN_BUDGET=32 is a balance between batch efficiency
and tail latency at ~1500 B packets / line rate.
The PDR/FAR list walk is hot in cache across the batch, so per-packet processing
cost drops modestly even on the same single core.
This change effectively allows pushing forward existing open5gs-sgwud
throughput on high load, while as a tradeof may increase CPU use when in
lower loads, due to extra read() calls returning EAGAIN (and extra pkbuf
allocation being freed immediately in _gtpv1_u_recv_cb()) when
< UPF_SK_DRAIN_BUDGETS are waiting to be read in the socket.
This is a simple optimization tailored for open5gs-sgwud, which doesn't
require a big refactoring nor architectural change, that has significant benefits
on single radio plus integrated core products, which may not need a much
more complex SGWU implementation.
On a CPU-constrained UPF host, single-packet read per poll callback caps DL
throughput because the UPF worker thread spends a non-trivial share of its
time in in epoll syscall and wakeups rather than GTP-U + PDR-walk processing.
Under DL load the worker pegs near 100% CPU while the co-resident gNB
user-plane has headroom but is starved for data.
Draining up to N packets per callback amortises the dispatch and
PDR-walk overhead and keeps the kernel rx queue from saturating
between wakeups. UPF_SK_DRAIN_BUDGET=32 is a balance between batch efficiency
and tail latency at ~1500 B packets / line rate.
The PDR/FAR list walk is hot in cache across the batch, so per-packet processing
cost drops modestly even on the same single core.
This change effectively allows pushing forward existing open5gs-upfd
throughput on high load, while as a tradeof may increase CPU use when in
lower loads, due to extra read() calls returning EAGAIN (and extra pkbuf
allocation being freed immediately in _gtpv1_u_recv_cb()) when
< UPF_SK_DRAIN_BUDGETS are waiting to be read in the socket.
This is a simple optimization tailored for open5gs-upfd, which doesn't
require a big refactoring nor architectural change, that has significant benefits
on single radio plus integrated core products, which may not need a much
more complex UPF implementation.
SBI responses are dispatched to the GMM state the UE is in when the
response arrives, not to the state that sent the request.
While the AMF is waiting for a UEContextTransfer or a
RegistrationStatusUpdate response from the old AMF, the UE can start
a new registration procedure. The FSM then moves to
gmm_state_authentication() and on to gmm_state_initial_context_setup(),
and neither state had a namf-comm case. The late response therefore
reached the service level default and terminated the AMF through
ogs_assert_if_reached().
Ignore UEContextTransfer and RegistrationStatusUpdate responses in
these two states, since they belong to the superseded registration
procedure. Assertions for unexpected services and resources are kept
as they are.
Issues: #4691
Reject integrity-protected uplink NAS messages that reuse an already
accepted NAS COUNT.
Calculate the estimated uplink COUNT without updating the UE context,
and commit it only after successful MAC verification. Track whether an
uplink COUNT has already been accepted so that the first COUNT value of
zero remains valid.
Reset the tracking state only when a new security context is created,
and preserve it in the UE context memento.
Apply the same handling to AMF, MME, and the EPS Service Request path.
Issues: #4690
The MME may not send a Delete Indirect Data Forwarding Tunnel
Request after handover. In this case, every subsequent Create
Indirect Data Forwarding Tunnel Request allocated another DL/UL
PDR and FAR pair for the same bearer.
Repeated handovers could therefore exhaust the per-session PDR
pool and cause SGW-C to abort when creating another bearer.
Re-use an existing indirect forwarding tunnel and preserve its
PDR. Once the tunnel has been installed in SGW-U, send an Update
FAR with the new remote TEID and address instead of creating
another PDR/FAR pair.
Use a common buffer index for Create FAR and Update FAR because
both builders share the same static FAR buffer.
Issues: #4719
Newer gcc 16.1.1 doesn't like it and warns about it:
../src/sgwu/sxa-build.c: In function ‘sgwu_sxa_build_session_modification_response’:
../src/sgwu/sxa-build.c:98:16: warning: variable ‘j’ set but not used [-Wunused-but-set-variable=]
98 | int i = 0, j = 0;
|
When the eNB reported a dedicated bearer in the
E-RABFailedToSetupListBearerSURes, s1ap_handle_e_rab_setup_response()
only logged "Not implemented : remove dedicated bearer" and kept the
bearer context.
That bearer was created by mme_s11_handle_create_bearer_request(), so it
already held an EPS Bearer Identity taken from the UE bitmap (EBI 5-15).
Leaving it behind leaked that identity for good, and the SGW was never
told that the bearer had not been established because no Create Bearer
Response was sent at all.
In a VoLTE deployment where the radio side rejects the dedicated bearer,
every call attempt consumed one more EBI. After eleven bearers the
bitmap was full and the next Create Bearer Request took the MME down:
[mme] WARNING: Cause[Group:1 Cause:25]
[mme] ERROR: Not implemented : remove dedicated bearer
...
[mme] ERROR: No available EBI (range 5-15)
[mme] FATAL: mme_s11_handle_create_bearer_request:
Assertion `bearer' failed.
Reject the pending Create Bearer Request with "No resources available"
and remove the bearer, mirroring the cleanup that a default bearer
already gets in the same loop.
The transaction id is checked before answering because
mme_gtp_send_create_bearer_response() asserts on it, and a dedicated
bearer can exist without one: mme_s11_handle_create_bearer_request()
returns early when ogs_gtp2_parse_bearer_qos() fails, before
bearer->create.xact_id is assigned. That path leaks the bearer as well
and is left for a separate change.
When the MME does not answer a relayed (PGW-initiated) Delete Bearer
Request, bearer_timeout() removed the bearer with a PFCP Session
Modification (MODIFY_REMOVE), regardless of whether the request carried
a Linked EPS Bearer ID.
For a default bearer this left an sgwc_sess_t with an empty bearer_list
in sgwc_ue->sess_list, and the next procedure walking that list aborted
the whole SGW-C:
[sgwc] FATAL: sgwc_s11_handle_release_access_bearers_request:
Assertion `ogs_list_count(&sess->bearer_list)' failed.
Split the timeout path the same way that
sgwc_s11_handle_delete_bearer_response() already does: delete the PFCP
session for a Linked EPS Bearer ID, remove only the bearer for an EPS
Bearer ID.
The three loops over sgwc_ue->sess_list keep asserting on an empty
bearer_list, so any other path leaving a PDN connection without bearers
still fails immediately. They now log the IMSI, session id and APN
first - the assert alone did not identify the PDN connection.
A production SMF crashed twice with the same assertion:
```
FATAL: smf_gx_cca_cb: Assertion `(void *)sess_data == data' failed.
(../src/smf/gx-path.c:792)
```
In both logs, the FATAL message appears before the "No Session Data"
message from the preceding source line. This cannot happen within a
single callback invocation and strongly indicates that multiple
callbacks were executing concurrently.
fd_sess_state_retrieve() temporarily removes the state from the
Diameter session until it is stored back. If a request path runs while
an answer callback is holding the state, it sees no state and may
incorrectly treat the existing Diameter session as a new one.
This creates a second state for the same Session-Id. The state stored
in the Diameter session can then differ from the pointer registered as
the callback data, causing a later answer to trigger the assertion.
Prevent the duplicate state and handle an existing mismatch safely:
* In the Gx, Gy and S6b request paths, do not create a new state when
the SMF session already has a Diameter Session-Id but no state can
be retrieved. Discard the request instead of leaving two states for
the same Session-Id.
* In the Gx/Gy CCA and S6b AAA/STA callbacks, restore the current state
and discard the stale answer when the state pointer does not match,
instead of aborting the process.
Also fix related defects found during the investigation:
* Replace the raw smf_sess_t pointer stored in S6b state with its pool
ID and resolve it using smf_sess_find_by_id(). This prevents an
answer arriving after session removal from accessing freed memory.
If the session no longer exists, release the stale Diameter state
instead of storing it back.
* Set sess_data->ts before sending S6b AAR and STR messages. Previously,
response time could be calculated from uninitialised memory.
* Avoid dereferencing a NULL sess_data in smf_s6b_aaa_cb() cleanup.
* Free the S6b STR request when no session state is found.
* Count "No Session Data" and unexpected new-session callback paths as
errors instead of successful answers.
This patch prevents duplicate state creation and hardens the answer
callbacks against stale state. It does not serialize Diameter session
state access; doing so would require a larger change such as
per-request callback contexts or explicit state-access serialization.
Return NGAP PathSwitchRequestFailure with the received UE identifiers
and per-session causes when the UE context is missing, the source gNB
has been removed, or the security context is invalid.
Send NGAP and S1AP failure responses to the requesting target RAN on
a valid UE-associated SCTP stream. Handle stream wrap, reduced limits,
and associations without an available UE stream.
Correct the MME security-context failure path to respond to the target
eNB instead of the source eNB.
Issues: #4769
The AMF may retain ran_ue while waiting for SMF deactivation after
removing its gNB. A PathSwitchRequest received in this window reaches
ran_ue_switch_to_gnb() and aborts on the missing source gNB.
Reject the request before changing UE state and leave the pending
deactivation procedure to complete the existing context cleanup.
Add the corresponding source eNB check to the MME PathSwitchRequest
handler and assert the source eNB in enb_ue_switch_to_enb(). The MME
currently removes enb_ue with its eNB, so this is a defensive check.
Normal Xn/X2 handover remains supported: the checks require the source
RAN node to exist and allow the request to come from the target node.
Issues: #4769
transform.py flattens a oneOf mixing an inline array and $ref items
into an object with one property per alternative, and that object was
the wire format: SmSubsData went out as
{"SessionManagementSubscriptionDataList":[...]} instead of the array.
Keep the object as the C-side container. When the alternatives differ
by JSON type and are an array of models, a model or a char *,
transform.py adds x-open5gs-union: true and model-body.mustache
generates convertToJSON/parseFromJSON that put the one member set on
the wire as the JSON value itself and pick the member by JSON type.
Structs, headers and the model set are unchanged; the bodies of
SmSubsData, ImmediateReport and SteeringContainer are regenerated.
Alternatives sharing a JSON type (HssAuthenticationVectors) or using
enum, map or nullable schemas keep the wrapper object; transform.py
reports them as warnings.
Issues: #4771
The registered-state heartbeat asserted that ogs_nnrf_nfm_send_nf_update()
returned true. A full SBI request pool makes the update fail to build,
which aborted the NF. Use ogs_expect, as the register path in this file
already does.
The heartbeat timer is rearmed just above, so the update retries on the
next interval; the NF stops updating only until the pool drains.
Issues #4776
on_header_value() asserted when a part repeated Content-Type or
Content-Id. A peer can send such a body, so treat it as a multipart
parse error and answer 400 instead of aborting.
The parser still runs to the end of the body after the error, as
in the existing parse_error handling; no unit test covers this
path since sbi-message-test uses its own stub callbacks.
Issues #4775
Replace session-wide cleanup with ID-based removal of newly created
rules. Keep applied updates, removals and existing BAR replacements.
Clear request-local FAR flags so rejected requests cannot leave an
End Marker pending for the next request.
Reject duplicate Create IDs and removal of referenced rules. Keep GTP-U
hash entries owned by live rules and reject cross-session local TEID
collisions. Synchronize PDR/FAR tunnel updates when they are applied.
Start new UPF URR timers after acceptance and update the QoS-flow gauge
from the surviving QER count on modification. Add rule lifecycle logs
and regression tests.
Issues: #4766 and #4767
Reject a Session Establishment that reuses a CP F-SEID owned by another
PFCP node before rebinding pfcp_node, and reject a UE IPv4/IPv6 address
held by a session of another PFCP node with Cause 64. A session of the
same node may still take over an address, e.g. one left by an orphaned
session.
Clear UE IP hash entries with ogs_hash_unset_if_owner() so that removing
or re-addressing one session cannot drop another session's mapping.
Only UPF is affected; SGWU has no UE IP hash. Orphaned UPF sessions left
when the SMF removes a session without PFCP Session Deletion, and session
contexts left after a failed Establishment, are pre-existing and are not
addressed here.
Issues #4762
The indirect tunnel is removed handover.duration after N2 handover
completion. If the next handover started before that delayed REMOVE was
answered, a second REMOVE|CREATE was sent for the same tunnel. The late
response of the delayed REMOVE then deleted the new tunnel from the
session, because smf_sess_delete_indirect_data_forwarding() deletes
whichever tunnel the session holds, and the handover failed on the
Created PDR. With enough QoS flows for PDR IDs to be reused, the delayed
REMOVE could also reach the UPF after the new tunnel had taken over its
PDR IDs.
Remember the delayed REMOVE transaction and, when the next handover
finds the old tunnel, turn that transaction into the REMOVE|CREATE
replacement instead of sending a second one: add the CREATE flag,
attach the new stream, and send it now if it is still waiting for the
timer. The existing REMOVE|CREATE handling does the rest. If the
transaction is gone (e.g. PFCP timeout), a new REMOVE|CREATE is sent as
before. The remembered ID is claimed once before the lookup and cleared
when the transaction is answered or timed out, so it never refers to a
transaction that no longer exists.
In the HR roaming V-SMF, the AMF stream for a UE-requested modification
was stored on the 204 to HsmfUpdateData, and the H-SMF stream for a
UE-requested release was stored on the 200 to N1N2MessageTransfer.
VsmfUpdateData can overtake that 204, and the AMF's N2/N1-RELEASED
updates can overtake that 200, so the reply on the stored stream was
skipped and the procedure stalled.
Store both streams when the request is sent and leave the response
handlers as no-ops.
Session-level PFCP messages were dispatched by SEID alone, so a
request for a SEID from a PFCP node other than the one the session
belongs to was applied. Such a request is now handled as Session
context not found (Cause 65).
- UPF/SGWU: Session Modification/Deletion Request
- SMF/SGWC: Session Report Request
Issues #4761
GTP-U peers added to gtpu_peer_list were only freed at process exit,
so every distinct peer address ever seen held one gtp_node pool entry
(global.max.gtp_peer, default 64). Renumbering eNB GTP-U addresses, or
gNB changes across handovers, eventually exhausted the pool and new
sessions failed with "CHECK CONFIGURATION: sgwu.gtpu".
Count the FARs/PDRs referencing each peer and remove the node when the
last reference goes away. A FAR/PDR moving to another address releases
the old peer; a same-address update leaves the count unchanged.
A FAR whose Outer Header Creation is removed still holds its peer until
the FAR itself is removed.
Issues: #4764
A rejected PFCP Session Report Request was incorrectly treated as a
request to release the session. In the 5GC path, the PFCP event had no
deletion trigger, causing an assertion failure during session deletion.
Separate PFCP error handling from the session release decision.
Malformed reports now receive an appropriate error response without
releasing the session. Gy Final-Unit-Indication and the absence of a
Gy peer still trigger a locally initiated session release.
Return Mandatory IE missing or Conditional IE missing with the
corresponding Offending IE for missing Report Type, PDR ID, or
Downlink Data Report IEs. Also log the actual PDR ID when lookup fails.
Issues #4744
When a UE shows up on a new NG connection while the AMF still holds the
old one, HOLDING_NG_CONTEXT() detaches the old ran_ue and removes it
later, either on UEContextReleaseComplete or when t_ng_holding expires.
The gNB never sends UEContextReleaseRequest for that context, so the
Update SM Context (upCnxState=DEACTIVATED) that normally precedes an AN
release is never sent. A session the UE keeps but does not re-activate
on the new connection stays ACTIVATED in the SMF and the UPF, pointing
at a GTP-U endpoint that no longer exists: downlink packets are
forwarded into a black hole instead of being buffered, and no downlink
data notification is raised, so the UE is never paged.
The UE does not have to be misbehaving to get there. A Registration
Request that carries PDU Session Status but no Uplink Data Status is
ordinary, and gmm_handle_registration_update() acts only on the sessions
listed in Uplink Data Status, so the rest are left as they are.
Note the sessions whose AN resources were established on the NG context
being put on hold - psimask.activated is exactly that set, and
amf_ue_note_stale_user_plane() writes it down - and deactivate whatever
is still noted when that context is removed. Deciding at hold time
rather than at release time keeps the outcome independent of whether
the gNB answers UEContextReleaseCommand before or after the UE asks for
the user plane again.
The note says the SMF may still believe the user plane is on that
context. While that context lives, the note is dropped only where the
SMF has said otherwise: on the success of a procedure that itself moves
the user plane - an activation, a deactivation, a completed handover -
and update_sm_context_supersedes_stale_user_plane() is that list, after
its N1/N2 content has been handled, since an HTTP success alone is not
the procedure succeeding. A MODIFIED or an N1-only exchange proves
nothing about the DL endpoint and leaves the note alone, and so does
dispatching: OGS_OK from
amf_sess_sbi_discover_and_send() means the transaction started, not
that the SMF took it. When the held context is removed the note is
consumed with it, whichever way the decision goes, so the pool id of a
freed context is never kept, and amf_ue_remove() severs the reverse
reference a held context keeps for the same reason.
That leaves the window where a procedure is in flight but not yet
answered, and which NG context it was issued on decides. A transaction
on some other context is a newer procedure that owns where the user
plane ends up; racing it with DEACTIVATED could tear down the user plane
it is setting up, so the sweep steps aside and the responsibility moves
to that procedure. A transaction on the context being removed is the
opposite - a late ACTIVATED for a GTP-U endpoint that is gone - and must
not stop the cleanup. amf_sbi_xact_ctx_t already records which RAN-UE a
transaction was issued on. For the same reason an answer for the noted
context does not clear the note, and a timed-out cleanup is not reported
to the NG context the UE is using now: the UE is not waiting on it.
The deactivation itself is normally sent on behalf of that current NG
context rather than the one being removed, since
amf_sess_sbi_discover_and_send() records the RAN-UE in sess->ran_ue_id
and the Namf callbacks reach the UE through it. If no serving NG context
remains either, the cleanup stays best-effort. Its response is handled
ahead of the generic N1/N2 and error parsing, which would answer an
unexpected or malformed response with an Error Indication towards that
same live connection.
NGAP_UE_CTX_REL_NG_CONTEXT_REMOVE is not the only way a held context is
destroyed. amf_sbi_send_deactivate_all_ue_in_gnb(), the partial NG Reset
and ngap_handle_error_indication() all find no AMF-UE context on a held
entry, since holding invalidates amf_ue_id, and remove it directly. All
four call the deactivation immediately before ran_ue_remove(), so that
the cleanup and the removal are visible together at the call site and
ran_ue_remove() stays a plain destructor. Only the two places that hold
an NG context leave a holder behind, so a context that was never held
passes through untouched, as do the handover release actions.
The hold has to be noted in two places, and one of them was an inlined
copy of HOLDING_NG_CONTEXT(). The copy exists because the macro takes a
single AMF-UE context and uses it for two roles: the context whose NG
connection is being held, and the context that records the hold. Those
are the same everywhere except in amf_ue_release_old_context(), where
the NG context and the sessions still belong to old_amf_ue while the
hold has to be recorded in amf_ue, since old_amf_ue is removed as soon
as its sessions have been moved across.
Rather than note it twice, split the two roles into parameters as
HOLDING_NG_CONTEXT_FOR() and keep HOLDING_NG_CONTEXT() as the ordinary
spelling on top of it, so the copy goes away. The existing callers are
unchanged, and both spellings stay macros so that the logs and
assertions keep reporting the file and line that triggered them.
mme_ue_set_imsi() carried the same copy of HOLDING_S1_CONTEXT(), for the
same reason and with the same two roles, so it gets the same treatment
as HOLDING_S1_CONTEXT_FOR(). Nothing about the stale user plane is
carried over: Release Access Bearers is per-UE rather than per-session
in EPC, and the exposure there is smaller, so only the duplication is
addressed.
Each half of both macros names the UE after the context it is about: the
one released on the way in is the holder's, the one put on hold is the
serving context's.
Folding the copies in changes their log lines. Both reported an existing
or already-removed holding context through ogs_error() where the macros
use ogs_warn(); in the AMF "RAN-NG Context has already been removed" now
reads "NG Context has already been removed" and the lines that named the
UE by the caller's display name now follow the rule above; in the MME the
macro's "Holding S1 Context" line now appears alongside the caller's
"Holding old S1 context". The old-context callers then clear the RAN-UE
reference themselves - CM_IDLE() and ECM_IDLE() must see the context as
released, and nothing associates a new one with the old UE context -
while the macros leave the field alone for the ordinary callers, which
associate a new context right after.
tests/slice/holding-test.c covers both halves of the AMF fix: a
Registration without Uplink Data Status, where downlink traffic has to
raise a notification afterwards, and one with it, where the user plane
must survive the removal of the held context.
Deactivating it exposed that a Home Routed Roaming session never
started a network triggered Service Request afterwards, which also
holds for an ordinary idle transition. Everything for that request
already exists on the home side - the V-SMF delegates the deactivation
over HsmfUpdateData with upCnxState, the H-UPF buffers and reports to
the H-SMF, the report handler builds the N1N2 message transfer, and the
AMF to send it to was passed in PduSessionCreateData.amfNfId - but two
steps were missing in between.
smf_nsmf_handle_update_data_in_hsmf() copied the received upCnxState
into sess->nsmf_param for the PFCP modification and never into
sess->up_cnx_state, which is what
smf_5gc_n4_handle_session_report_request() switches on, so the H-SMF
still believed the user plane was up and dropped the report. Record it
in the session as well, as smf_nsmf_handle_update_sm_context() does in
the V-SMF, once the requested combination has been accepted, so that an
HsmfUpdateData rejected as Bad Request leaves the session untouched,
and log every recording. This also keeps the H-SMF in step when the UE
comes back, since the activation is delegated with upCnxState the same
way, so the log line appears on the home side for every session
activation and shows at a glance that this change is in.
And the N1N2 message transfer itself never left the home PLMN: the
discovery option named the AMF NF instance but not where to look for
it, so the discovery stayed in the home PLMN, found no AMF and the
transfer failed with 504. Name the serving PLMN as the target and the
home PLMN as the requester, the same way the AMF names the home PLMN
when it discovers the AUSF or the UDM of a roaming UE.
tests/slice/holding-test.c passes in the roaming configuration with
the buffering, the report and the N1N2 message transfer all on the
home side, crossing to the serving AMF through the SEPP.
Issues #4741
During handover the target ran_ue/enb_ue is linked to the same
amf_ue/mme_ue before the UE has moved, and after HandoverCancel it is
only unlinked and removed once the RAN node answers
UEContextReleaseCommand with UEContextReleaseComplete. A RAN node that
withholds the Release Complete therefore keeps an addressable context
that still resolves to the UE.
The setup response handlers only verified the message identifiers, the
sending RAN node's ownership of the context, and the existence of the
PDU session or bearer. They did not verify that the context is the one
currently serving the UE. A RAN node could therefore send an
unrequested PDUSessionResourceSetupResponse or E-RABSetupResponse over
such a context, and the AMF/MME would forward the supplied transport
layer address and TEID, redirecting the downlink of a session that is
still served by another RAN node.
Add RAN_UE_IS_SERVING()/ENB_UE_IS_SERVING(), which require that the
context is both the serving association and not already being released,
and apply them in InitialContextSetupResponse and in
PDUSessionResourceSetupResponse/E-RABSetupResponse. Rejected responses
are answered with an Error Indication and produce no SBI, PFCP, or S11
side effect.
Also set initial_context_setup_response_received after validation
instead of before, so a rejected response leaves no state behind.
This is not a general request-correlation mechanism. A RAN node that
has been selected as a handover target retains other ways to influence
the user plane, and HandoverNotify is deliberately left alone since
rejecting it would change the outcome of a HandoverCancel/HandoverNotify
race.
Each Error Indication for a bearer started a new deactivation procedure.
When multiple Delete Bearer transactions timed out, they sent overlapping
PFCP removal requests. The first response removed the bearer, and a later
response hit ogs_assert(bearer).
Track an Error Indication deactivation on the bearer and ignore duplicate
reports while it is in progress. Clear the mark when the PFCP procedure is
rejected or times out so that a later report can retry.
Read modify_flags before resolving session-level modifications, tolerate
a missing GTP transaction during local EPC session deletion, and release
the whole PDN connection when a Delete Bearer request for the default
bearer times out. This prevents a live EPC session from being left without
a default bearer.
Issues: #4753
Add strict hex decoding helpers that reject invalid lengths, non-hex
characters, and NULL inputs without modifying the output buffer.
Validate RAND, HXRES*, AUTN, and KSEAF before using them. Decode the
initial authentication vectors into temporary buffers before updating
the UE context, and validate KSEAF before storing a successful
authentication result.
Add core conversion tests for malformed, non-ASCII, and NULL inputs,
and verify that the output remains unchanged on failure.
Issues #4734
The synch-failure path (Authentication Failure cause #21) already caps
repeats per authentication procedure via auth_synch_fail_count, sending
AUTHENTICATION REJECT once the limit is reached. The ngKSI-already-in-use
path (cause #71) had no equivalent bound: it re-invoked AUSF on every
occurrence and returned without ever reaching the reject path, so a UE
that keeps answering each Authentication Request with cause #71 would
loop without limit, holding its context and repeating AUSF/UDM
round-trips.
Add auth_ngksi_fail_count and mirror the existing synch-failure guard:
count cause #71 failures and send AUTHENTICATION REJECT once the limit is
reached. The counter is reset at authentication-procedure entry
(OGS_FSM_ENTRY_SIG) alongside auth_synch_fail_count, so a legitimate
cause #71 in a later procedure starts from zero.
Re-running 5G AKA on cause #71 is permitted by TS 24.501, so the previous
behavior was standards-compliant; this change only makes the two
authentication-failure paths consistent and bounds a signalling loop
against a misbehaving UE. It is a robustness change, not a security fix,
and does not by itself constitute a DoS defense (other control-plane
paths such as re-registration are equally unbounded and belong to
edge rate limiting).
The NGAP and S1AP handover handlers resolve the UE context with a
global lookup by AMF_UE_NGAP_ID / MME_UE_S1AP_ID and then use it
without checking that the sending RAN node is the one that owns it.
A gNB or eNB can therefore drive handover signalling for a UE context
belonging to a different RAN node - cancelling it, failing it,
forwarding status transfer to its peer, or completing a handover
notification for it.
In ngap_handle_handover_request_ack(), target_ue is looked up by the
AMF_UE_NGAP_ID carried in the message and target_ue->ran_ue_ngap_id is
overwritten with the RAN_UE_NGAP_ID from the message before the later
checks (source_ue, amf_ue, PDUSessionList) can reject it, corrupting
the RAN UE NGAP ID mapping of another gNB's UE context even though the
request itself is eventually rejected.
Add the ownership check already used by
ngap_find_ran_ue_by_message_ue_ids() and
s1ap_find_enb_ue_by_message_ue_ids() right after the lookup in:
- ngap_handle_handover_required()
- ngap_handle_handover_request_ack()
- ngap_handle_handover_failure()
- ngap_handle_handover_cancel()
- ngap_handle_uplink_ran_status_transfer()
- ngap_handle_handover_notification()
- s1ap_handle_handover_required()
- s1ap_handle_handover_request_ack()
- s1ap_handle_handover_failure()
- s1ap_handle_handover_cancel()
- s1ap_handle_enb_status_transfer()
- s1ap_handle_handover_notification()
In ngap_handle_handover_request_ack(), also move the assignment of
target_ue->ran_ue_ngap_id after the Source-UE and AMF-UE lookups so
that the Target-UE context is not left with a new RAN UE NGAP ID when
the handler bails out. The two Error Indications on that path now
report the RAN_UE_NGAP_ID received in the message, since the one in
the context is not assigned yet at that point. The second
!RAN_UE_NGAP_ID check is removed as the IE is already validated at the
top of the handler. The S1AP side needs no such reordering:
s1ap_handle_handover_request_ack() already assigns
target_ue->enb_ue_s1ap_id after the Source-UE and MME-UE contexts have
been resolved.
The S1AP Error Indication reports both UE S1AP IDs received in the
message, as s1ap_find_enb_ue_by_message_ue_ids() does. HandoverFailure
carries no ENB_UE_S1AP_ID IE, so only the MME UE S1AP ID is reported
there.
ngap_handle_path_switch_request() and s1ap_handle_path_switch_request()
are intentionally left alone: in Xn/X2 based handover the
PathSwitchRequest is sent by the target node while the UE context is
still owned by the source node, so the sender is not expected to be the
owner there.
Run CIFuzz on pushes to the main branch so that GitHub Code
Scanning has a current default-branch analysis.
Also update the SARIF upload action from CodeQL Action v3 to v4.
emm_handle_authentication_response() used the length supplied in the
NAS Authentication Response as the comparison length for memcmp().
A UE could therefore submit a truncated RES and have only that prefix
compared with the expected XRES.
Reject zero-length responses and responses whose length differs from
mme_ue->xres_len, then compare the complete expected response.
Even if an attacker guesses a truncated RES prefix accepted by the
vulnerable comparison, the attacker cannot complete the Attach
procedure because the subsequent NAS Security Mode exchange requires
integrity keys derived from KASME.
TS 23.502 4.3.2.2.1 returns the created SM context to the AMF at
step 5, before the PDU Session Establishment Accept is delivered by
N1N2MessageTransfer at step 11.
If the RAN-UE context disappears while CreateSMContext is in flight,
the AMF removes its local session. The later N1N2 transfer is then
rejected, but the SMF only logs the error and retains the session. This
leaves the UE IP address, PFCP session, PCF policy and UDM association
without a release procedure.
For non-home-routed sessions, trigger a locally initiated release when
the AMF returns a response other than 200 OK or 202 Accepted. Keep the
session on 202 because the AMF may still be attempting to reach the UE,
and preserve the existing home-routed roaming behavior because the peer
SMF must also be released.
After PFCP deletion, run SBI cleanup with
SMF_UECM_STATE_DEREG_BY_N1N2. This releases the PCF and UDM resources,
sends SMContextStatusNotify to the AMF and finally removes the SMF
session.
Remove newly allocated contexts when request validation fails.
In the AMF, a PDU Session Establishment Request creates an amf_sess
context before validating the requested DNN and S-NSSAI. If validation
fails, remove the session only when it was created while handling the
current request. Leave pre-existing session contexts untouched.
In the MME, a Create Bearer Request allocates a bearer before parsing
the Bearer Level QoS IE. If parsing fails, send a Create Bearer
Response with cause "Mandatory IE incorrect" and remove the newly
allocated bearer.
This prevents rejected requests from retaining AMF session-pool
entries or MME EPS bearer identities until the UE context is released.
The S6a, Cx and SWx authentication handlers accessed RAND and AUTS at
fixed offsets without validating the containing AVP value and length.
A malformed Re-Synchronization-Info or SIP-Authorization AVP could
therefore cause out-of-bounds reads and expose adjacent heap contents
through error logging.
Validate the AVP value and require the exact RAND plus AUTS length
before processing re-synchronization data.
ogs_gtp1_gsn_addr_to_ip() returns OGS_ERROR when an SGSN Address IE
does not contain a valid IPv4 or IPv6 address. The MME asserted that
the conversion succeeded, allowing a malformed SGSN Context Request
to abort the process.
Validate both the primary and alternative control-plane addresses
and return Mandatory IE incorrect when either address is invalid.
Convert the addresses into local variables before updating the UE
context to prevent an invalid request from partially modifying the
stored Gn TEID and addresses.
Validate the remaining block size before reading TLV headers or
advancing over their values.
Reject truncated headers, values extending beyond the input block,
and zero-length embedded blocks before any out-of-bounds access.
Apply the same validation to descriptor-based and fixed-length TLV
parsing.
Also avoid passing an uninitialized stack buffer to the logger when
hexdumping a zero-length input.
Add tests for truncated headers, trailing octets, over-long values,
fixed-length TV elements, and descriptor-based parsing.
ogs_pfcp_parse_volume_measurement() and
ogs_pfcp_parse_dropped_dl_traffic_threshold() copied 8-octet fields
selected by the flags octet without checking the declared IE length. A
short IE with every flag set read up to 48 and 16 octets past the end
of the IE. The flags octet itself was also read unchecked, which
dereferenced NULL for an absent IE, since the SMF usage report handlers
call ogs_pfcp_parse_volume_measurement() without testing
volume_measurement.presence.
ogs_pfcp_parse_volume() validated each volume field but not the flags
octet, and ogs_pfcp_parse_sdf_filter() validated the Flow Description
length field without validating that many octets actually follow it.
Validate the remaining reads against octet->len and return 0 on a short
IE, as ogs_pfcp_parse_volume() already did for its volume fields. The
callers compare the decoded length against the IE length, so a
truncated IE is now rejected instead of parsed from adjacent memory.
An Attach or Registration Request can arrive on an S1/NG connection
already associated with another subscriber. The request was dispatched
through that association without checking its mobile identity.
The subsequent identity update could relabel the associated UE context
and migrate another subscriber's sessions into it. This either aborted
the MME/AMF when the target already owned sessions or silently assigned
the existing sessions to the wrong subscriber.
Re-resolve the identity before dispatch. If it differs from a registered
context or a context with sessions, release the access connection and
drop the request so the UE can retry on a newly resolved context.
Keep the existing migration behaviour for unfinished procedures without
sessions, and add regression tests for the affected MME and AMF paths.
Issues: #4739
SMF session contexts kept Gx, Gy and S6b Session-Id pointers as aliases
of strings owned by the corresponding freeDiameter session state.
Those strings are released by state_cleanup(), while the SMF session
context can remain alive longer. This leaves sess->gx_sid, gy_sid or
s6b_sid dangling and allows later Diameter requests to read freed
memory. Recovery paths could also free the aliased pointer from the SMF
side even though the allocation was owned by the Diameter session
state.
Give each SMF Session-Id its own copy and release it from
smf_sess_remove(), so the SMF context and freeDiameter session state
have independent lifetimes.
PCRF had a similar ownership problem in its IP-to-Gx-Session-Id hash.
The hash stored pointers to both the address and Session-Id owned by the
Gx session state. Releasing or updating that state could therefore leave
dangling hash entries or modify a hash key in place.
Make each PCRF hash entry own copies of both its key and Session-Id.
Return a copy from IP lookups so callers can safely use the Session-Id
after releasing the hash lock, remove old entries before overwriting a
stored address, and release remaining entries during PCRF shutdown.
A production smf-ims also aborted while processing a
Credit-Control-Answer when fd_msg_sess_get() rejected its Session-Id:
[diam] ERROR: [fd_sess_new@sessions.c](mailto:fd_sess_new@sessions.c):405:
Invalid parameter '(fd_os_is_valid_os0(opt, optlen))', 22
[diam] ERROR: [fd_msg_sess_get@messages.c](mailto:fd_msg_sess_get@messages.c):1522:
Invalid argument
[smf] FATAL: smf_gx_cca_cb:
Assertion `ret == 0' failed.
A received Diameter answer must not be able to terminate the whole SMF
because its Session-Id cannot be resolved. Replace the
fd_msg_sess_get() assertions in the Gx, Gy and S6b answer callbacks
with error handling that logs and discards the affected answer.
The Session-Id lifetime issues were found while investigating the
production failure, but without the corresponding CCR/CCA packet capture
they are not claimed to be the proven source of the malformed
Session-Id seen in that incident.
Issues: #4737
Validate the Local F-TEID IE length before storing it in the PDR
in Created PDR and Update PDR handlers.
Also bound the copy length in the Create PDR and Created PDR
builders to the size of ogs_pfcp_f_teid_t.
This prevents out-of-bounds reads and writes when a malformed PFCP
message provides an oversized F-TEID IE length.
A timer expiry event may already be queued when its associated UE or
bearer context is removed. Deleting the timer does not retract an event
that has already been pushed to the MME event queue.
When the stale event is later dispatched, the context lookup returns
NULL and the existing assertion aborts the entire MME process.
Replace the assertions in the EMM, ESM and Gn timer handlers with
runtime guards that log and discard stale events. Also guard the
dependent SGW-UE lookup in the Gn timer path for consistency with the
S11 timer handler.
This prevents an already-removed context from causing an MME process
abort.
Validate the peer-provided 'Length of QoS rule' before using it as
the parsing bound for the packet filter list.
Previously, ogs_nas_parse_qos_rules() only rejected a zero rule
length. A rule could declare a length larger than the remaining
Requested QoS rules IE, causing
parse_qos_rules_packet_filter_list() to read beyond the received
message buffer.
The packet filter parser's internal bounds checks did not prevent
this because they were performed against the inflated rule length
provided by the peer. Reject any rule whose declared length exceeds
the remaining buffer before entering the parser.
Also fix ogs_nas_build_qos_rules() to use the operation code of the
rule currently being encoded. The function copied rule[i] into the
local target structure but several branches continued to inspect
rule[0].code. As a result, the first rule's operation code could
incorrectly determine the wire layout of subsequent rules in a
multi-rule IE.
Use target.code consistently so each QoS rule is encoded according
to its own operation code.
This prevents an out-of-bounds read reachable through a crafted PDU
Session Modification Request and fixes malformed encoding of mixed
operation-code QoS rules.
Add unit tests for valid and invalid Flow-Description strings handled by
ogs_ipfw_compile_rule().
Cover malformed grammar, protocol truncation, invalid prefixes, port
ranges, unsupported port lists, mixed address families, and the
protocol 41 paths that previously reached errx() and terminated the
process.
Also verify that valid IPv4, IPv6, numeric-protocol, port-range, and
"assigned" destination rules continue to compile and encode correctly.
Issues: #4711
Validate Flow-Description strings before passing them to the bundled
ipfw parser.
The parser accepts syntax that ogs_ipfw_rule_t cannot represent and may
silently truncate or discard parts of malformed rules. Some invalid
inputs can also reach errx() paths in the vendored parser and terminate
the process.
Validate the supported IPFilterRule subset, including:
- action and direction
- protocol names and numbers
- IPv4 and IPv6 addresses and prefixes
- source and destination address-family consistency
- port numbers and ranges
- unsupported trailing tokens and port lists
- unsupported source-side "assigned"
Protocol 41 with an IPv4 literal is rejected because the bundled parser
uses protocol 41 as an address-family selector and passes the literal to
the IPv6 address parser. Although an IPv4 outer address is valid for
IPv6 encapsulation, this combination is not currently supported by the
bundled parser and can terminate the process.
Propagate compile_rule() failures to the caller and only swap uplink
rules after successful compilation.
The Flow-Description form reported in #4711 now fails cleanly with a
diagnostic and is not installed. This does not add support for
"assigned" in the source position.
The parser already uses static storage and is not reentrant, and its
current callers run serially in the event loop, so the parse-error flag
does not introduce an additional concurrency limitation.
Reported-in: #4711
Validate the Outer Header Creation IE before copying it into the
internal FAR structure.
Only the supported GTP-U/IPv4, GTP-U/IPv6, and dual-stack variants are
accepted. Reject unsupported Description combinations and verify that
the IE contains the TEID and all addresses required by its flags.
Previously, a truncated GTP-U/IPv6 IE could be partially copied into a
zero-initialized structure. This produced an unspecified IPv6 address
and could leave an incompletely initialized GTP-U node, eventually
triggering an Unknown family assertion on a subsequent request.
Return INVALID_LENGTH for truncated IEs and SERVICE_NOT_SUPPORTED for
unsupported Outer Header Creation variants.
Issues: #4699
Use the local bearer context to determine whether a Delete Bearer
Response should remove a dedicated bearer or delete the entire PDN
session.
An MME may return a failure response without Linked EPS Bearer ID or
Bearer Contexts. In that case, relying on the response IEs causes SGW-C
to remove only the default bearer and leave an empty session in the UE
session list.
The stale session later triggers an assertion failure while handling a
Release Access Bearers Request.
Apply the same default-bearer check to both the normal response path
and the path where the associated S5-C transaction has already expired.
Issues: #4727 and #4667
On a CPU-constrained SGWU host, single-packet read per poll callback caps DL
throughput because the SGWU worker thread spends a non-trivial share of its
time in in epoll syscall and wakeups rather than GTP-U + PDR-walk processing.
Under DL load the worker pegs near 100% CPU while the co-resident gNB
user-plane has headroom but is starved for data.
Draining up to N packets per callback amortises the dispatch and
PDR-walk overhead and keeps the kernel rx queue from saturating
between wakeups. UPF_SK_DRAIN_BUDGET=32 is a balance between batch efficiency
and tail latency at ~1500 B packets / line rate.
The PDR/FAR list walk is hot in cache across the batch, so per-packet processing
cost drops modestly even on the same single core.
This change effectively allows pushing forward existing open5gs-sgwud
throughput on high load, while as a tradeof may increase CPU use when in
lower loads, due to extra read() calls returning EAGAIN (and extra pkbuf
allocation being freed immediately in _gtpv1_u_recv_cb()) when
< UPF_SK_DRAIN_BUDGETS are waiting to be read in the socket.
This is a simple optimization tailored for open5gs-sgwud, which doesn't
require a big refactoring nor architectural change, that has significant benefits
on single radio plus integrated core products, which may not need a much
more complex SGWU implementation.
On a CPU-constrained UPF host, single-packet read per poll callback caps DL
throughput because the UPF worker thread spends a non-trivial share of its
time in in epoll syscall and wakeups rather than GTP-U + PDR-walk processing.
Under DL load the worker pegs near 100% CPU while the co-resident gNB
user-plane has headroom but is starved for data.
Draining up to N packets per callback amortises the dispatch and
PDR-walk overhead and keeps the kernel rx queue from saturating
between wakeups. UPF_SK_DRAIN_BUDGET=32 is a balance between batch efficiency
and tail latency at ~1500 B packets / line rate.
The PDR/FAR list walk is hot in cache across the batch, so per-packet processing
cost drops modestly even on the same single core.
This change effectively allows pushing forward existing open5gs-upfd
throughput on high load, while as a tradeof may increase CPU use when in
lower loads, due to extra read() calls returning EAGAIN (and extra pkbuf
allocation being freed immediately in _gtpv1_u_recv_cb()) when
< UPF_SK_DRAIN_BUDGETS are waiting to be read in the socket.
This is a simple optimization tailored for open5gs-upfd, which doesn't
require a big refactoring nor architectural change, that has significant benefits
on single radio plus integrated core products, which may not need a much
more complex UPF implementation.
SBI responses are dispatched to the GMM state the UE is in when the
response arrives, not to the state that sent the request.
While the AMF is waiting for a UEContextTransfer or a
RegistrationStatusUpdate response from the old AMF, the UE can start
a new registration procedure. The FSM then moves to
gmm_state_authentication() and on to gmm_state_initial_context_setup(),
and neither state had a namf-comm case. The late response therefore
reached the service level default and terminated the AMF through
ogs_assert_if_reached().
Ignore UEContextTransfer and RegistrationStatusUpdate responses in
these two states, since they belong to the superseded registration
procedure. Assertions for unexpected services and resources are kept
as they are.
Issues: #4691
Reject integrity-protected uplink NAS messages that reuse an already
accepted NAS COUNT.
Calculate the estimated uplink COUNT without updating the UE context,
and commit it only after successful MAC verification. Track whether an
uplink COUNT has already been accepted so that the first COUNT value of
zero remains valid.
Reset the tracking state only when a new security context is created,
and preserve it in the UE context memento.
Apply the same handling to AMF, MME, and the EPS Service Request path.
Issues: #4690
The MME may not send a Delete Indirect Data Forwarding Tunnel
Request after handover. In this case, every subsequent Create
Indirect Data Forwarding Tunnel Request allocated another DL/UL
PDR and FAR pair for the same bearer.
Repeated handovers could therefore exhaust the per-session PDR
pool and cause SGW-C to abort when creating another bearer.
Re-use an existing indirect forwarding tunnel and preserve its
PDR. Once the tunnel has been installed in SGW-U, send an Update
FAR with the new remote TEID and address instead of creating
another PDR/FAR pair.
Use a common buffer index for Create FAR and Update FAR because
both builders share the same static FAR buffer.
Issues: #4719
Newer gcc 16.1.1 doesn't like it and warns about it:
../src/sgwu/sxa-build.c: In function ‘sgwu_sxa_build_session_modification_response’:
../src/sgwu/sxa-build.c:98:16: warning: variable ‘j’ set but not used [-Wunused-but-set-variable=]
98 | int i = 0, j = 0;
|
When the eNB reported a dedicated bearer in the
E-RABFailedToSetupListBearerSURes, s1ap_handle_e_rab_setup_response()
only logged "Not implemented : remove dedicated bearer" and kept the
bearer context.
That bearer was created by mme_s11_handle_create_bearer_request(), so it
already held an EPS Bearer Identity taken from the UE bitmap (EBI 5-15).
Leaving it behind leaked that identity for good, and the SGW was never
told that the bearer had not been established because no Create Bearer
Response was sent at all.
In a VoLTE deployment where the radio side rejects the dedicated bearer,
every call attempt consumed one more EBI. After eleven bearers the
bitmap was full and the next Create Bearer Request took the MME down:
[mme] WARNING: Cause[Group:1 Cause:25]
[mme] ERROR: Not implemented : remove dedicated bearer
...
[mme] ERROR: No available EBI (range 5-15)
[mme] FATAL: mme_s11_handle_create_bearer_request:
Assertion `bearer' failed.
Reject the pending Create Bearer Request with "No resources available"
and remove the bearer, mirroring the cleanup that a default bearer
already gets in the same loop.
The transaction id is checked before answering because
mme_gtp_send_create_bearer_response() asserts on it, and a dedicated
bearer can exist without one: mme_s11_handle_create_bearer_request()
returns early when ogs_gtp2_parse_bearer_qos() fails, before
bearer->create.xact_id is assigned. That path leaks the bearer as well
and is left for a separate change.
Restructure 03-5g-eir.md to match the rest of docs/_docs/guide/:
lead with what the feature is for and who needs it, walk through a
concrete quick-start (start the daemon, add a device, turn it on in
the AMF), explain the allow/reject policies in plain language with
a table, and move index/schema/precedence internals into a
"Technical reference" section at the end for readers who want them.
No behavioral or config changes.
Move open5gs-eir from a hard Depends to a Recommends in the open5gs
metapackage. The equipment identity check is disabled in the AMF by
default (amf.eir.enabled: false), so installing the EIR daemon isn't
required for a working core; users who want it can still get it by
default (Recommends is installed unless --no-install-recommends is
used) while it stays easy to opt out of.
open5gs-eird applies a $jsonSchema validator (collMod) to the eir
collection at startup, requiring pei/status and constraining status
to the known enum values, rejecting malformed documents at write
time in addition to the existing application-level checks.
Verified live against MongoDB 8.0: rejects a document missing pei,
rejects an unrecognized status value, accepts a well-formed record.
Move PEI/SUPI format validation (ogs_dbi_eir_pei_is_valid/
ogs_dbi_eir_supi_is_valid) from src/eir/n5geir-handler.c into
lib/dbi/eir.c, where it's directly unit-testable alongside the rest
of the DBI layer, and add coverage: valid/invalid IMEI/IMEISV/IMSI
formats, length boundaries, non-digit rejection, and a regression
test for the supi-missing-equals-supi-null generic record lookup.
Verified: `./build/tests/registration/registration -v eir` passes
(9/9) when run standalone; it previously stalled under `meson test`
in this sandbox due to port contention with other locally-running
NF processes, not a defect in the suite itself.
open5gs-eird now creates two unique partial indexes on the eir
collection at startup: eir_specific_unique (pei+supi, supi is a
string) and eir_generic_unique (pei only, supi missing or null),
so duplicate records are rejected by MongoDB instead of only being
caught if a lookup happens to encounter them.
MongoDB partial index filters don't support $exists: false, so the
generic-record convention switches from "supi field omitted" to
"supi missing or null", matched via supi: {$eq: null} in both the
index and the DBI lookup query. Documented in 03-5g-eir.md.
Check digit-only content and expected length for PEI (IMEI: 15
digits, IMEISV: 16 digits) and SUPI (IMSI: 6-15 digits) instead of
only checking the identity type prefix, rejecting malformed values
with 400 Bad Request before they ever reach the database lookup.
Only treat a 404 as unknown equipment when ProblemDetails.cause is
ERROR_EQUIPMENT_UNKNOWN; any other 404 now goes through
failure_action instead of being misread as an unknown-equipment
result. Malformed 200 responses already fell through to
failure_action via the existing default case.
Registration Requests without a PEI no longer silently bypass the
equipment identity check; they now follow the configurable
missing_pei_action policy (default allow), matching unknown_action
and failure_action semantics.
Reject invalid unknown_action/failure_action values at startup
instead of silently warning and falling back to allow, and add
missing_pei_action for explicit control over that policy too.
When the MME does not answer a relayed (PGW-initiated) Delete Bearer
Request, bearer_timeout() removed the bearer with a PFCP Session
Modification (MODIFY_REMOVE), regardless of whether the request carried
a Linked EPS Bearer ID.
For a default bearer this left an sgwc_sess_t with an empty bearer_list
in sgwc_ue->sess_list, and the next procedure walking that list aborted
the whole SGW-C:
[sgwc] FATAL: sgwc_s11_handle_release_access_bearers_request:
Assertion `ogs_list_count(&sess->bearer_list)' failed.
Split the timeout path the same way that
sgwc_s11_handle_delete_bearer_response() already does: delete the PFCP
session for a Linked EPS Bearer ID, remove only the bearer for an EPS
Bearer ID.
The three loops over sgwc_ue->sess_list keep asserting on an empty
bearer_list, so any other path leaving a PDN connection without bearers
still fails immediately. They now log the IMSI, session id and APN
first - the assert alone did not identify the PDN connection.
A production SMF crashed twice with the same assertion:
```
FATAL: smf_gx_cca_cb: Assertion `(void *)sess_data == data' failed.
(../src/smf/gx-path.c:792)
```
In both logs, the FATAL message appears before the "No Session Data"
message from the preceding source line. This cannot happen within a
single callback invocation and strongly indicates that multiple
callbacks were executing concurrently.
fd_sess_state_retrieve() temporarily removes the state from the
Diameter session until it is stored back. If a request path runs while
an answer callback is holding the state, it sees no state and may
incorrectly treat the existing Diameter session as a new one.
This creates a second state for the same Session-Id. The state stored
in the Diameter session can then differ from the pointer registered as
the callback data, causing a later answer to trigger the assertion.
Prevent the duplicate state and handle an existing mismatch safely:
* In the Gx, Gy and S6b request paths, do not create a new state when
the SMF session already has a Diameter Session-Id but no state can
be retrieved. Discard the request instead of leaving two states for
the same Session-Id.
* In the Gx/Gy CCA and S6b AAA/STA callbacks, restore the current state
and discard the stale answer when the state pointer does not match,
instead of aborting the process.
Also fix related defects found during the investigation:
* Replace the raw smf_sess_t pointer stored in S6b state with its pool
ID and resolve it using smf_sess_find_by_id(). This prevents an
answer arriving after session removal from accessing freed memory.
If the session no longer exists, release the stale Diameter state
instead of storing it back.
* Set sess_data->ts before sending S6b AAR and STR messages. Previously,
response time could be calculated from uninitialised memory.
* Avoid dereferencing a NULL sess_data in smf_s6b_aaa_cb() cleanup.
* Free the S6b STR request when no session state is found.
* Count "No Session Data" and unexpected new-session callback paths as
errors instead of successful answers.
This patch prevents duplicate state creation and hardens the answer
callbacks against stale state. It does not serialize Diameter session
state access; doing so would require a larger change such as
per-request callback contexts or explicit state-access serialization.
Cover starting open5gs-eird, the eir MongoDB collection schema and
lookup precedence with example records/indexes, the amf.eir config
knobs and their effect on registration, and current limitations
(no S13, CEIR, wildcard rules, or admin API).
Add unit coverage for the new OpenAPI models (equipment_status,
eir_response_data) and a registration-suite eir-test.c exercising
DBI precedence directly against a live MongoDB (exact SUPI+PEI,
PEI-only fallback, pair overriding generic in both directions,
GREYLISTED, unknown, invalid status, ambiguous duplicates), reusing
the existing test_db_insert_ue-style fixture pattern. Wire the new
"eir" NF into the multi-process 5GC test harness (no_eir/eir_count,
mirroring bsf/udr) so it starts alongside the rest of the stack.
Add amf.eir (enabled/unknown_action/failure_action), disabled by
default so existing deployments and behavior are unchanged. When
enabled, the check runs once per initial registration attempt right
after Security Mode Complete (once amf_ue->pei is known) and before
Registration Accept: WHITELISTED/GREYLISTED continue, BLACKLISTED
rejects with 5GMM cause #6 (Illegal ME), and 404/discovery-failure/
timeout/5xx/malformed-response outcomes follow the configured
unknown_action/failure_action (default allow). Duplicate/late-response
handling is the existing generic SBI xact machinery; discovery
failures are special-cased in nnrf-handler.c only for n5g_eir_eic so
they honor failure_action instead of always rejecting.
Add open5gs-eird, a producer-only NF modeled on src/udr: it registers
with the NRF as 5G_EIR, advertises n5g-eir-eic v1 with AMF as the
allowed consumer, and serves GET .../equipment-status by validating
PEI/SUPI and delegating the lookup to lib/dbi. Wire it into the
build, packaging (debian, systemd) and default/sample configs,
disabled from nothing since the daemon itself is inert until an AMF
is configured to call it.
Add ogs_dbi_eir_check_equipment(), backed by a new eir collection.
Lookup is exact SUPI+PEI first, falling back to a PEI-only (no supi
field) record, and treats an unrecognized status or an ambiguous
duplicate match as a database error rather than an implicit
whitelist. lib/dbi has no dependency on lib/sbi, so the record uses
its own ogs_dbi_eir_status_t rather than the OpenAPI enum.
Add EquipmentStatus/EirResponseData OpenAPI models, the
equipment-status resource name, and pei/supi query parameters so the
common SBI layer can build and parse N5g-eir_EquipmentIdentityCheck
(TS 29.511) requests and responses. NF type/service name resolution
for 5G_EIR/n5g-eir-eic already worked through the existing generic
prefix mapping.
ogs_pfcp_handle_update_urr() decoded the 3-octet Reporting Triggers IE in
reverse octet order (reptri_5 from the LSB, reptri_7 from the MSB), which is
inconsistent with ogs_pfcp_handle_create_urr() and ogs_pfcp_build_update_urr()
where reptri_5 is the MSB and reptri_7 the LSB. An Update URR carrying
Reporting Triggers therefore swapped octet 5 and octet 7, corrupting triggers
such as VOLTH when modifying an existing URR.
Align handle_update_urr with the create path and the encoder.
Snapshot the GUAMI presence flag before removing the SBI transaction and
pass the copied value to the old AMF discovery fallback helper.
This fixes use-after-free issues in both the NF discovery no-match path and
the failed AMF discovery path while preserving the transaction-before-context
cleanup ordering.
Related PR: #4698
Store the Origin-Host and Origin-Realm received in successful AIA and
ULA messages, and use the learned identity for subsequent S6a requests.
Update the learned identity only in the MME event thread to avoid
accessing UE-owned string pointers from freeDiameter callback threads.
Preserve existing hss_map routing behavior by using the learned
host/realm pair only when no hss_map entry is associated with the UE.
Forget the learned identity when:
* DIAMETER_UNABLE_TO_DELIVER or DIAMETER_REALM_NOT_SERVED is received
* DIAMETER_ERROR_USER_UNKNOWN is received
* an MME or SGSN update Cancel-Location-Request is received
* the UE context is removed
Do not invalidate the identity for other 3xxx result codes, such as
DIAMETER_TOO_BUSY, since they do not indicate that the learned identity
is invalid.
Document the learned HSS routing behavior and reference TS 29.272
clause 7.1.6.
Related PR: #4692
Follow up the DNS-based SGW/PGW selection introduced by #4693 and
harden several fallback, asynchronous completion, cache, resolver,
and compatibility paths found during review and testing.
A DNS failure must never prevent an attach when a statically
configured gateway remains available. Preserve the SGW serving the
UE when a DNS resolution is created and restore it whenever a later
DNS-based SGW selection cannot complete.
This is required because a previous Create Session Request attempt
may already have switched the UE to a DNS-discovered SGW. If that
request times out and the next DNS candidate cannot be resolved, simply
returning from apply_sgw() leaves the UE attached to the failed DNS SGW
and causes subsequent CSR attempts to continue using it instead of the
original fallback SGW.
Restore the pre-DNS SGW when:
* the SGW DNS leg ends in fallback after an earlier SGW switch
* mme_sgw_add() cannot create the selected SGW node
* ogs_gtp_connect() cannot connect the selected SGW
* the deferred Create Session Request cannot be built or committed
The fallback pointer records the SGW currently serving the UE when the
resolution is created rather than assuming it is always statically
configured. Successfully connected SGW nodes are retained for the
process lifetime, so the stored pointer remains valid.
The PGW path does not require the same state restoration. When PGW DNS
selection falls back, mme_dns_sess_pgw_addr() returns NULL and the S11
Create Session Request builder selects the statically configured PGW
again on each attempt.
Harden deferred CSR completion handling.
post_resolved() runs on the MME main thread, which is also responsible
for draining the application event queue. ogs_queue_push() can block
indefinitely when that queue is full, causing a self-deadlock because
the blocked producer is also the only consumer.
Use ogs_queue_trypush() instead. When it returns OGS_RETRY, return the
resolution to PENDING and restart its guard timer. The DNS legs are
already complete, so the guard callback simply attempts to post the
completed result again. Do not retry when the queue has been terminated
during shutdown.
Do not move a resolution to CONSUMED or increment csr_attempts until
the deferred CSR transaction has been successfully built and committed.
The GTP timeout retry path uses CONSUMED as its eligibility condition,
so marking an unsent request as consumed leaves meaningless retry state.
If local CSR creation fails, restore the pre-DNS SGW first and then
remove the resolution. This prevents a subsequent NAS retry from
capturing the failed DNS SGW as its new fallback and prevents a stale
CONSUMED resolution from incorrectly short-circuiting the new request
to SEND_NOW.
Document that OGS_OK from mme_gtp_send_create_session_request() may
mean that the request was deferred for DNS selection and does not
guarantee that a GTP transaction exists when the function returns.
Fix an MME event-loop hang caused by unusable SRV answers.
An SRV record whose target is "." indicates that the service is not
available. mme_dns_candidate_apply_srv() previously left the candidate
unchanged in this case. leg_advance() then repeatedly read the same
cached SRV answer without advancing the candidate cursor, hanging the
MME event loop.
Make mme_dns_candidate_apply_srv() return whether it found a usable
target. Skip the candidate when all SRV targets are empty or ".", while
leaving the candidate unchanged for callers that need to inspect the
failure.
Add unit and DNS integration coverage for this case. Extend the test DNS
server to encode "." as the DNS root label and verify that the MME skips
the unusable SRV candidate and falls back instead of hanging.
Bound the MME DNS cache to prevent expired entries from accumulating
indefinitely across many TAC and APN names.
When inserting a new key at capacity:
* remove expired entries
* if the cache remains full, evict entries closest to expiry
* do not make room when replacing an existing key, which would otherwise
evict an unrelated entry on every refresh at capacity
Disable the c-ares internal query cache when the installed c-ares
version provides ARES_OPT_QUERY_CACHE. c-ares 1.31 and later enable an
internal cache by default, which can continue answering a query after
the MME's own cache entry has expired and silently override the
operator-configured dns.cache_ttl. Set qcache_max_ttl to zero so the
MME cache remains authoritative.
Retain compatibility with both older distribution versions of c-ares
and newer releases that deprecate the legacy query and reply parsing
APIs. Define CARES_NO_DEPRECATED before including ares.h to suppress
the newer deprecation attributes without raising the minimum supported
c-ares version.
Validate configured resolver addresses before initializing c-ares.
Require each dns.server address to be a bare IPv4 or IPv6 literal.
Reject hostnames, malformed addresses, bracketed addresses, scope
suffixes, and IPv6 link-local addresses, which require interface scope
handling that is not supported by the MME configuration.
Format resolver entries as:
* IPv4: address:port
* IPv6: [address]:port
The brackets are required by the c-ares server CSV format. Without
them, a value such as 2001:db8::53:53 is accepted as a different valid
IPv6 address using the default DNS port, causing queries to be sent
silently to the wrong resolver.
Build and validate the server CSV before c-ares initialization so
configuration failures do not require partially initialized channel or
library cleanup. The fixed CSV buffer remains safe because inet_pton()
guarantees that accepted addresses fit the maximum IPv4 or IPv6 literal
length.
Explicitly initialize mme_sess_t::dns_id to OGS_INVALID_POOL_ID instead
of relying on the current value of the pool allocator's zero-filled
memory.
Update the sample configuration and documentation to describe the
current DNS-selection limitations:
* roaming PGW lookup currently builds the APN-FQDN from the serving PLMN
rather than deriving the home-PLMN APN-OI
* only A records are used for discovered gateways
* SRV weights are ignored
* non-terminal NAPTR records are not followed
* DNS-discovered SGW nodes are retained for the process lifetime
* resolver addresses must be bare IPv4 or IPv6 literals
* link-local IPv6 resolvers are not supported
Add the c-ares development dependency to Debian, Ubuntu, Fedora, Alpine,
CentOS, macOS, and FreeBSD build instructions and container images, and
add the c-ares MIT license notice.
Also link the DNS selection unit tests against libmme directly so they
exercise the same mme-dns-select implementation built for the MME.
New 'dns' test (suite epc, built only when c-ares is available) with
a minimal programmable stub DNS server (UDP, NAPTR/SRV/A) listening
on 127.0.0.200:10053:
1. attach with a working S-NAPTR chain: SGW via NAPTR(s)->SRV->A,
PGW via NAPTR(a)->A, both resolving to the gateways of
configs/dns.yaml.in - the attach succeeding proves the Create
Session Request followed the DNS-provided gateways;
2. NOERROR/0-answer responses: static fallback, attach succeeds;
3. unresponsive DNS: guard timer fires, static fallback, attach
succeeds.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Select the SGW by TAI-FQDN and the PGW by APN-FQDN using S-NAPTR
(NAPTR -> SRV -> A / NAPTR -> A) as described in 3GPP TS 29.303,
resolved asynchronously with c-ares integrated into the MME main
loop (sockets in ogs_pollset, timeouts via ogs_timer; no threads,
no blocking).
The feature is inert unless a new `mme.dns` section is configured:
without it (or without c-ares at build time) the static
gtpc.client.sgwc/smf selection is used unchanged.
Flow: mme_gtp_send_create_session_request() defers the CSR while
resolution is in flight; MME_EVENT_DNS_RESOLVED applies the result
(sgw_ue_switch_to_sgw() before any S11 TEID exists; PGW address
injected into the PGW S5/S8 F-TEID, after the HSS-provided
MIP6-Agent-Info but before the static PGW list) and sends the CSR.
On any DNS failure or guard-timer expiry the MME falls back to the
static configuration with a warning.
- Applies to initial attach and UE-requested PDN connectivity only;
TAU / Path-Switch keep the statically relocated SGW.
- Create Session reject or GTP timeout retries the next DNS
candidate (PGW / SGW cursor respectively, max 3 attempts).
- TTL-based cache (real TTL for A records, mme.dns.cache_ttl for
NAPTR/SRV, short negative caching).
- IPv4/A records only; AAAA is out of scope.
- New Prometheus counters: dns_query_total, dns_query_failed,
dns_cache_hit.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Record-processing logic for DNS-based SGW/PGW selection, independent
of any DNS library so it is unit-testable in isolation:
- APN-FQDN / TAI-FQDN builders (TS 23.003 19.4.2.2 / 19.4.2.3)
- S-NAPTR service-field matching (x-3gpp-sgw / x-3gpp-pgw with
x-s5-gtp / x-s8-gtp protocol tokens, case-insensitive, multi-token)
- s5 vs s8 decision from the IMSI vs the serving PLMN
- topon./topoff. canonical-name handling (TS 29.303 4.3.2), used for
candidate deduplication only (no topological matching)
- NAPTR filtering (terminal flags "a"/"s" only) with stable
(order, preference) sorting and SRV application by priority
(RFC 2782 weights are intentionally ignored)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Prepare for DNS-based (3GPP TS 29.303) SGW/PGW selection: probe for
libcares via pkg-config and define MME_HAVE_CARES when available.
Without c-ares the MME builds and behaves exactly as before.
Add libc-ares-dev to the CI dependency list so the feature is
compiled and tested by CI.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Validate the UE-requested PDN type against the subscription session
type before building a Create Session Request.
The explicit APN path previously performed this validation, but the
default APN path could reach the S11 builder without checking for a
compatible PDN type. If the requested and subscribed PDN types had no
common value, the builder triggered an assertion and terminated the
MME.
Move the PDN type negotiation into a common helper and use it for both
PDN Connectivity Request and ESM Information Response processing.
Reject incompatible requests with the appropriate ESM cause:
* IPv4 subscription with an incompatible request: IPv4 only allowed
* IPv6 subscription with an incompatible request: IPv6 only allowed
* Other incompatible combinations: service option not subscribed
Avoid clearing the EBI bitmap while bearer contexts are still
active during UE re-attachment.
Previously, CLEAR_EPS_BEARER_ID() reset the bitmap before the
existing bearer contexts were removed. This temporarily broke
the correspondence between the EBI bitmap and active bearers,
allowing duplicate EBI allocation windows and triggering
FREE-UNRESERVED reports from the EBI accounting checks.
Only clear the bitmap when no active sessions remain, allowing
existing bearer teardown to release EBIs through the normal
allocation/free path.
Also add EBI accounting instrumentation to trace allocation,
release, migration, and bitmap consistency for debugging.
Retrieve AM and SMF selection subscription data in a single Nudm_SDM
request using the dataset-names query parameter.
Parse combined Nudm_SDM responses as ProvisionedDataSets and process the
AM and SMF selection data sequentially while preserving the existing
UE context in SMF lookup.
Forward the requested serving PLMN from UDM to UDR, falling back to the
UE GUAMI PLMN when it is not provided.
Also limit the UDR UE-AMBR validation to requests that actually include
subscribedUeAmbr, and safely ignore delayed combined responses received
after the UE has moved to another GMM state.
Issues: #4683
Return 400 Bad Request for malformed SCP requests instead of falling
back to a generic 500 response. Distinguish missing and invalid
User-Agent headers, preserve the original header while parsing the NF
type, and validate mandatory discovery headers consistently.
Return 504 Gateway Timeout with TARGET_NF_NOT_REACHABLE when the target
NF cannot be reached, and NRF_NOT_REACHABLE when NRF discovery fails.
Avoid fallback 500 responses after a callback has already sent a
response by revalidating MHD sessions and HTTP/2 streams. Also fix
nnrf URI string leaks on error paths.
Issues #4681 and #4682
Validate that UE contexts referenced by partial NG RESET and S1 RESET
belong to the gNB or eNB that sent the request.
When both core-network and RAN UE identifiers are present, also verify
that they refer to the same UE association. This prevents a peer from
resetting a UE owned by another RAN node or supplying mismatched UE IDs.
Guard the deferred reset acknowledgement paths against a missing
acknowledgement buffer without aborting or interrupting the remaining
session cleanup.
Issues: #4680
Validate User-Name and Public-Identity before passing them to the HSS
context lookup functions.
A zero-length identity could otherwise be used as a hash key and trigger
an assertion in ogs_hash_get(), terminating the HSS.
Return DIAMETER_INVALID_AVP_VALUE for empty identities in UAR, MAR, SAR,
and LIR requests.
Issues #4675
Issues #4676
When processing a UE-requested PDU Session Modification Request, the
SMF treated every Requested QoS flow description as a QoS parameter
modification regardless of its operation code.
If the UE deletes a dedicated QoS flow by sending both:
- Delete existing QoS rule
- Delete existing QoS flow description
for the same QFI, the QoS rules handler sets OGS_PFCP_MODIFY_REMOVE,
but the QoS flow descriptions handler also set
OGS_PFCP_MODIFY_QOS_MODIFY. This produced an invalid
REMOVE|QOS_MODIFY combination and tripped the invariant in
gsm_handle_pdu_session_modification_request(), aborting smfd during
VoNR call teardown.
A "Delete existing QoS flow description" carries no QoS parameters, so
skip the QoS-parameter update path for that operation and let the QoS
rule deletion drive the actual PFCP removal.
Also update the test GSM message builder to encode QoS rule deletion
without packet filters, and add a VoNR regression test for the
UE-initiated dedicated QoS flow deletion case.
Issues #4672
Move the vendored cJSON copy out of the generated OpenAPI tree:
```
lib/sbi/openapi/external/cJSON.{c,h}
-> lib/third-party/cjson/cJSON.{c,h}
```
The copy under lib/sbi/openapi/external/ came from the OpenAPI generator
output, but cJSON is a third-party dependency rather than generated SBI
model code. Keep it in lib/third-party/cjson/ as the single canonical
vendored copy.
Update the current openapi-generator template sets accordingly so that
regenerated model code includes the relocated header directly:
```
```
This avoids any post-processing after regeneration and works regardless
of which generated source directory includes the header, since the path
no longer depends on "../" relative traversal.
Notes:
* The generator still emits an external/cJSON.{c,h} pair from
cJSON.{c,h}.mustache into its output directory. That generated copy is
no longer copied into the source tree.
* The older template sets (r16 5.2.0/6.4.0, r17 6.4.0/7.20.0) are left
untouched as a historical record of what generated past trees.
Validate Framed-IP-Address before using it as an IPv4 hash key in
Rx AAR handling. A malformed AVP shorter than 4 bytes could otherwise
lead to an out-of-bounds read.
Also validate Framed-IPv6-Prefix before casting it to ogs_paa_t in
Rx AAR and Gx CCR handling. This prevents dereferencing a short buffer
when checking the IPv6 prefix length.
Issues #4663 and #4664
UE-associated SCTP streams are allocated per RAN association.
During X2 or Xn handover, the UE context can retain a stream ID that
was valid for the source eNB or gNB but is outside the target RAN's
negotiated stream range. Sending Path Switch Request Acknowledge on
that stream then fails with EINVAL.
Rebind the stream using the target RAN allocator only when the
existing stream ID is out of range.
Issues: #4670
Avoid asserting when an S11 Delete Bearer Response arrives after its
associated S5-C transaction has already been removed.
There is no response left to relay to the PGW in this case, but the
SGW-C must still complete local cleanup. Delete the PFCP session for a
Linked EPS Bearer ID, or remove the affected PFCP bearer for an EPS
Bearer ID.
Keep the associated S5-C transaction assertion for the Bearer Resource
Command path, which requires transaction-specific data.
Issues: #4667
Do not send a GTP-U Error Indication when the received TEID is
owned by an existing PDR but the packet does not match its QFI or
SDF filter.
Such a packet is off-filter, not an unknown tunnel. Sending an Error
Indication can cause the peer to remove a live bearer, for example
after a stray uplink packet during X2 handover.
Keep the existing Error Indication behavior for TEIDs that are not
owned by any PDR.
Issues: #4665
On a GTP-U Error Indication for an EPC session, the SMF deleted the whole
PFCP session for any Error Indication and never notified the MME. A single
transient, handover-induced Error Indication on a dedicated (voice) bearer
therefore tore down the entire IMS PDN, and because no Delete Bearer
Request was sent to the MME, the MME and UE kept a stale IMS PDN
connection - the UE could not place a new VoLTE call until it re-attached.
SMF (src/smf/n4-handler.c, src/smf/pfcp-path.c):
Map the Error Indication FAR to its bearer and run a PGW-initiated bearer
deactivation instead of a blind session deletion, per 3GPP TS 23.007:
- dedicated bearer -> deactivate only that bearer (IMS PDN survives);
- default bearer -> deactivate the whole PDN connection.
smf_gtp2_send_delete_bearer_request() sets the Linked EBI (default) or the
EPS Bearer ID (dedicated), so the MME deactivates the EPS bearer toward the
UE and stays in sync. The PFCP session is deleted on the Delete Bearer
Response (wait_pfcp_deletion). The default-bearer case uses cause
"Reactivation requested" so the UE re-establishes the PDN.
MME (src/mme/mme-s11-handler.c, mme-path.c, mme-context.h, nas-path.c,
nas-path.h, esm-sm.c):
Map the GTPv2 Cause "Reactivation requested" (#8) on a default-bearer
Delete Bearer Request to NAS ESM cause #39 "reactivation requested"
(TS 29.274 Table C.3) so the UE re-establishes the IMS PDN. The mapping is
restricted to the default bearer (Linked EBI). Carry the ESM cause across
paging in mme_ue->paging.esm_cause so an ECM-IDLE UE also receives it after
paging; previously the post-paging path always used REGULAR_DEACTIVATION.
The TS 29.274 Table C.3 "re-attach required" mapping for the last PDN
connection is intentionally not implemented (Attach without PDN
connectivity and SCEF PDN connections are not supported here); the last
default bearer is deactivated with ESM cause #39 as well.
Issues: #4659
Remove local indirect forwarding tunnels after PFCP modification
synchronization even when the associated S11 transaction has expired.
Also release the PDR TEID node on per-session PDR ID allocation
failure and add diagnostics for PDR resource exhaustion.
Issues: #4653
OpenAPI_nf_profile_parseFromJSON() aborts via ogs_assert(data) in
listEntry_create() when an NFProfile carries a non-empty
nfSetRecoveryTimeList / serviceSetRecoveryTimeList. OSS-Fuzz:
listEntry_create: Assertion `data' failed (lib/sbi/openapi/src/list.c:10)
OpenAPI_list_add (list.c:116)
OpenAPI_nf_profile_parseFromJSON (nf_profile.c:3989)
Root cause is in the model-body.mustache map handler. The per-value
type dispatch only emits assignments to localMapKeyPair for
isString / isByteArray / isNumeric / isBoolean. For a map whose value
is a DateTime (map<string,DateTime>, e.g. NfSetRecoveryTimeList) or an
array (map<string,array<string>>, e.g. allowedOperationsPerNfType),
no branch fires, localMapKeyPair stays NULL, and the generated code
calls OpenAPI_list_add(list, NULL) -> listEntry_create(NULL) -> abort.
This is remotely triggerable: NFProfile is parsed from peer/NRF input.
Template fix (r19, openapitools 7.20.0):
- add isDate / isDateTime branches in both parseFromJSON and
convertToJSON map blocks (DateTime is carried as a JSON string,
handled like isString); convertToJSON previously also dropped the
value silently for these maps.
- guard OpenAPI_list_add with a NULL check so any remaining
unhandled value category (e.g. array-valued maps) fails the parse
gracefully instead of aborting the process.
Regenerated the two affected models (nf_profile, nf_service).
DateTime maps now round-trip correctly; the array-valued maps are
rejected instead of crashing pending full map<string,array> support.
Issues: #4649
ogs_fqdn_parse() returns -EINVAL on invalid FQDN encoding, but the DNN
and APN decoders stored the result directly into the uint8_t length
field. The negative value was truncated (-22 -> 234), so the
"if (length > 0)" guard passed and ogs_cpystrn() copied up to 101 bytes
from an uninitialized stack buffer that ogs_fqdn_parse() never wrote.
The guard was written when ogs_fqdn_parse() returned 0 on failure; the
later switch to -EINVAL broke it via the unsigned truncation.
Capture the return value in a signed int, take the error branch on
negative/zero, and assign to length only on success. Applied to both
ogs_nas_5gs_decode_dnn and ogs_nas_eps_decode_access_point_name via the
support/type-list.py templates; generated ies.c regenerated.
Found by OSS-Fuzz (nas_5gs_message_fuzz, MSan).
Issues: #4645
Accept NF status notifications only when they match a subscription
confirmed by the NRF. Reject notifications outside the confirmed
subscription state with 404 Not Found before updating or removing the
local NF cache.
Apply the same validation to both NF_REGISTERED and NF_DEREGISTERED
notifications.
Move the NF status subscription lookup from nf-sm.c to the SBI
context so it can be reused by notification handling.
Keep the existing lookup semantics for subscription creation, including
subscriptions that have been requested locally but are not yet confirmed
by the NRF.
Release RAN-UE and eNB-UE contexts when processing fails after a
new context has been allocated.
Malformed InitialUEMessage messages and failed handover target setup
could leave newly created contexts in their respective pools until the
peer association was closed. Repeated failures could therefore exhaust
the RAN/eNB UE context pool and prevent legitimate UE procedures.
Only contexts allocated for the current message are removed, preserving
pre-existing UE contexts on duplicate or malformed messages.
Validate that UE Context Release Request is received from the gNB/eNB
owning the resolved UE context and that the RAN-side UE ID matches.
Apply ownership validation to UE Context Release Complete as well, while
preserving its existing AMF/MME UE ID-based completion handling without
requiring a RAN-side UE ID consistency match.
Keep the procedure-specific lookup paths so unknown UE contexts retain
their existing warning-level handling and Error Indication behavior.
Cx User-Name may contain an IMSI-based IMPI in the form of <IMSI>@ims.mnc<MNC>.mcc<MCC>.3gppnetwork.org.
Do not parse digits from the realm portion when converting the
User-Name into a BCD subscriber identifier. Otherwise, digits in the
MNC, MCC, and domain name can cause a valid IMPI to be rejected as an
invalid or overlong IMSI.
Issues: #4633
Store the target RAN UE ID in the SBI transaction context when sending
an Update SM Context request. Use the saved ID when processing the SMF
response so that the target RAN context can still be released even if
the source RAN context has already been removed.
This also avoids an AMF assertion failure during the handover-cancel
response race.
Issues: #4631
This commit adds the network policy IE, part of ATTACH ACCEPT and
TAU ACCEPT messages. This prevents unsecured redirection to GERAN
or UTRAN, protecting the UEs from unsecured redirection attacks.
This IE is mandatory in Rel.19
This patch changes the default behavior!
In case you want to allow unsecured redirects, add the following:
```
global:
parameter:
allow_unsecured_redirection: true
```
to your mme.yaml
ogs_strtok_r() returns NULL when the flow description is empty or
contains only spaces. Check the first token before comparing it with
"permit" so that NULL is not passed to strcmp().
Invalid flow descriptions now return OGS_ERROR through the existing
error path instead of crashing the SMF or UPF process.
Issues: #4630
Handle failure to deactivate the old Non-3GPP session after a
Non-3GPP to 3GPP handover as a non-fatal error.
The Modify Bearer Response has already been sent at this point, so a
missing or already released WLAN session must not terminate the SMF.
Log the deactivation failure and continue instead of asserting.
Issues: #4636
In ngap_build_path_switch_ack(), the UESecurityCapabilities IE block passed
&PathSwitchRequestAcknowledge->protocolIEs to ASN_SEQUENCE_ADD(), while every
other IE block in the function correctly passes protocolIEs without the
address-of operator.
Since the asn1c v6->v7 migration, protocolIEs is a pointer returned by
ogs_asn_calloc_protocol_ies(), so the extra '&' passes a pointer-to-pointer.
asn_sequence_add() then casts it to _A_SEQUENCE_OF and reads/writes array,
count and size at that location, corrupting the protocolIEs pointer and
adjacent fields in the PDU. This leads to a heap/wild-pointer write and
crashes the AMF.
The block only runs when send_ue_security_capability_in_path_switch_ack is
set, i.e. on a UE security capability mismatch during PathSwitchRequest, so
the bug stayed hidden until exercised by the Xn handover path. When it
triggers, the AMF dies before sending PATH SWITCH REQUEST ACKNOWLEDGE,
causing a guard-timer timeout on the handover and NGAP socket failures on
subsequent procedures.
Drop the stray '&' so the IE is appended to the correct sequence, and add
the missing ogs_assert(ie) for consistency with the other IE blocks.
Upgrade to Release-19
Avoid ARG_MAX failures when linking generated ASN.1 and OpenAPI libraries
Update Debian package, documentation, and WebUI version metadata
MongoDB is required by database-backed components such as HSS/PCRF
and PCF/UDR, but it does not need to be installed locally when an
external MongoDB server is used.
Move the MongoDB package relationship from Depends to Recommends for
the affected Debian packages, so the default installation still pulls
MongoDB in while allowing users to opt out with --no-install-recommends.
Update the documentation to clarify which components use MongoDB and
explain that the MongoDB installation step can be skipped when using an
external database.
Regenerate GTPv1 and GTPv2 TLV message definitions from the latest
Release 19 3GPP specifications.
For GTPv1, update the generator and regenerate message definitions from
TS 29.060 V19.0.0. The generator now handles the unmodified Word document
without manual table-cell edits, including merged table cells and reference
values with suffixes such as 7.7.25A, 7.7.25B, and 7.7.45A.
For GTPv2, update the generator and regenerate message definitions from
TS 29.274 V19.6.0. This adds new Rel-19 IEs, updates changed message and
grouped IE definitions, and improves parsing of aliases such as APCO, LDN,
IP4CP, and PTI.
Also update the TLV regeneration documentation for GTPv1 and GTPv2.
Regenerate PFCP message definitions from 3GPP TS 29.244 V19.5.0.
This updates PFCP IE and grouped IE definitions for Rel-19, including
new N6 delay measurement, protocol description, RTP information,
header handling, MPQUIC, and other newly added information elements.
It also updates renamed IEs and fixes generator handling for duplicated
IE names and repeated IE types in the same message or grouped IE.
Remove obsolete User Plane IP Resource Information handling from PFCP
messages. Since this IE is no longer present in the generated PFCP
Association messages, remove the remote PFCP node GTP-U resource list
and related encode/decode helpers. Local configured GTP-U resource
handling is kept for CH F-TEID allocation.
Regenerate EPS and 5GS NAS message encoder/decoder files from
3GPP TS 24.301 and TS 24.501 Rel-19 specifications.
Update NAS message table indexes for the reduced Chapter 8/9 input
documents, refresh generated message support files, and add newly
introduced NAS IE type definitions.
Also make the NAS message generators produce valid C identifiers for
IE names containing special characters, and fix Python regex escape
warnings.
Validate NFProfile.heartBeatTimer before applying the received NFProfile
to the live NF instance.
A non-positive heartbeat interval could otherwise be stored in
nf_instance->time.heartbeat_interval and later passed to ogs_timer_start()
when the NF enters the registered state, triggering a timer assertion.
Reject non-positive values with HTTP 400.
Issues: #4616
Use the RANNodeName and ENBname pointers directly instead of taking their
addresses when handling NG setup and S1 setup requests.
This fixes incorrect pointer assignment introduced during merge resolution.
The /ue-info JSON dumper added in #4093 exposes cm_state but not
mm_state, so a UE that has explicitly detached (e.g. handset
flight-mode triggering a NAS Detach Request) is indistinguishable
from a UE that is merely ECM-IDLE while still EMM-REGISTERED. Both
render as cm_state: "idle" with no live S1AP IDs.
This is because the MME keeps the mme_ue_t context alive across
explicit detach -- emm_state_de_registered's entry handler clears
timers and S1 state but does not call mme_ue_remove(), so the UE
stays in mme_ue_list and the dumper iterates over it.
This patch adds an mm_state field to each item. The string mirrors
the name of the FSM state-handler function in emm-sm.c, so in-
progress NAS transitions are distinguishable from the steady-state
{de,}registered values:
emm_state_de_registered -> "deregistered"
emm_state_registered -> "registered"
emm_state_authentication -> "authentication"
emm_state_security_mode -> "security_mode"
emm_state_initial_context_setup -> "initial_context_setup"
emm_state_ue_context_will_remove -> "ue_context_will_remove"
emm_state_exception -> "exception"
(otherwise) -> "initial"
This lets external monitors filter out fully-detached UEs without
having to wait for the implicit detach timer (T3412 + T3423,
typically ~30+ minutes) before the entry disappears on its own, and
also lets them surface in-progress NAS transitions (e.g. an
authentication that's been stuck for a long time). This is the
LTE mirror of the equivalent AMF /ue-info field added in the prior
mm_state patch.
No state-machine changes; the new field is read-only from
mme_ue->sm via OGS_FSM_CHECK().
Signed-off-by: NM <npm-sdr@npm-net.com>
The /ue-info JSON dumper added in #4093 emits enb.enb_id only while the
UE is ECM-CONNECTED, because enb_id is resolved via the live enb_ue_t
which is freed at UE Context Release. An ECM-IDLE UE is therefore
indistinguishable from one that has never attached -- both render with
no enb_id field and no way for an external monitor to anchor the UE
against its last cell.
This is the 4G mirror of how the AMF /ue-info already exposes the
last-attached gNB even for CM-IDLE UEs: amf_ue_t->nr_cgi.cell_id is
preserved across UE Context Release on the long-lived amf_ue_t, and
the dumper emits location.nr_cgi.gnb_id from it. mme_ue_t had no
equivalent stored eNB-ID -- only ue->e_cgi (28-bit ECI), and decoding
the eNB-ID from the ECI requires knowing the per-eNB id-length which
the mme_ue_t doesn't carry.
This patch:
- Adds last_enb_id_presence / last_enb_id to mme_ue_t.
- Captures the eNB-ID in enb_ue_associate_mme_ue() whenever an
enb_ue_t is bound to the mme_ue_t. Skips silently if the eNB
hasn't completed S1 Setup with an enb_id IE; a later association
on a properly-set-up eNB overwrites.
- Falls back to last_enb_id (and ue->e_cgi.cell_id) in build_enb()
when enb_ue_find_by_id() returns NULL, and explicitly emits
status: "not-connected" so the consumer knows the values are
last-known rather than live.
External monitors can now keep an ECM-IDLE 4G UE anchored to its
last cell across app restarts without waiting for the next
re-attach.
No state-machine changes; the new fields are read-only side-effects
of the existing attach association path.
Signed-off-by: NM <npm-sdr@npm-net.com>
The S1SetupRequest eNBname IE (S1AP id_eNBname) carries an
optional human-readable identifier the eNB picks for itself, but
the IE is currently not captured anywhere in the MME data model
and is not exposed by the recently-added /enb-info JSON dumper
(#4093). This is the LTE mirror of the equivalent AMF /gnb-info
field added in the prior commit.
This patch:
- adds a 64-byte enb_name field to mme_enb_t (zero-init at struct
allocation; the field is populated only if the peer sends the
IE)
- captures the IE in s1ap_handle_s1_setup_request, truncating to
fit and NUL-terminating
- adds a "name" field to each item in the /enb-info JSON output,
alongside enb_id, so external monitors can display a friendly
identifier next to the SCTP peer address without re-parsing
S1AP messages out-of-band
The field is the empty string when the peer does not include the
IE.
No new IE handling beyond capture: cause-checks, supported-TA
processing, and S1 setup state machines are unchanged.
Signed-off-by: NM <npm-sdr@npm-net.com>
The /ue-info JSON dumper added in #4093 exposes cm_state but not
mm_state, so a UE that has explicitly deregistered (e.g. handset
flight-mode triggering a NAS Deregistration Request) is
indistinguishable from a UE that is merely CM-IDLE while still
MM-REGISTERED. Both render as cm_state: "idle" with
gnb.status: "not-connected".
This is because the AMF keeps the amf_ue_t context alive across
explicit deregistration -- gmm_state_de_registered's entry handler
clears timers and radio capability but does not call amf_ue_remove(),
so the UE stays in amf_ue_list and the dumper iterates over it.
This patch adds an mm_state field to each item. The string mirrors
the name of the FSM state-handler function in gmm-sm.c, so in-
progress NAS transitions are distinguishable from the steady-state
{de,}registered values:
gmm_state_de_registered -> "deregistered"
gmm_state_registered -> "registered"
gmm_state_authentication -> "authentication"
gmm_state_security_mode -> "security_mode"
gmm_state_initial_context_setup -> "initial_context_setup"
gmm_state_ue_context_will_remove -> "ue_context_will_remove"
gmm_state_exception -> "exception"
(otherwise) -> "initial"
This lets external monitors filter out fully-deregistered UEs
without having to wait for the implicit deregistration timer
(T3512 + Mobile Reachable + Implicit Dereg, ~9-15 minutes by
default) before the entry disappears on its own, and also lets
them surface in-progress NAS transitions (e.g. an authentication
that's been stuck for a long time).
No state-machine changes; the new field is read-only from
amf_ue->sm via OGS_FSM_CHECK().
Signed-off-by: NM <npm-sdr@npm-net.com>
The NGSetupRequest RANNodeName IE (NGAP id_RANNodeName) carries an
optional human-readable identifier the gNB picks for itself, but
the IE is currently not captured anywhere in the AMF data model
and is not exposed by the recently-added /gnb-info JSON dumper
(#4093).
This patch:
- adds a 64-byte ran_node_name field to amf_gnb_t (zero-init at
struct allocation; the field is populated only if the peer
sends the IE)
- captures the IE in ngap_handle_ng_setup_request, truncating to
fit and NUL-terminating
- adds a "name" field to each item in the /gnb-info JSON output,
alongside gnb_id, so external monitors can display a friendly
identifier next to the SCTP peer address without re-parsing
NGAP messages out-of-band
The field is the empty string when the peer does not include the
IE.
No new IE handling beyond capture: cause-checks, supported-TA
processing, and NG setup state machines are unchanged.
Signed-off-by: NM <npm-sdr@npm-net.com>
Remove a duplicated UESecurityCapabilities IE block accidentally left during
merge conflict resolution in ngap_build_path_switch_ack().
Also fix indentation for no_ims in the global configuration structure.
ogs_hash_clear() removed entries by calling ogs_hash_set() with a
NULL value. That path looks the entry up again, which requires hashing
and comparing the caller-owned key.
During context teardown, a hash table may still contain keys whose
backing storage has already been released. Rehashing those keys while
destroying the table can therefore trigger an ASan use-after-free in
hashfunc_default().
Clear the table by walking the bucket array directly and moving active
entries to the free list without dereferencing key contents.
Store the replacement plmnList in temporary storage while validating the
PATCH request. Commit it to the NF instance only after validation succeeds.
Previously, the NRF PATCH handler cleared and updated the live NF instance
before validation completed. If validation failed, the request returned
HTTP 400 but the existing PLMN state was already modified.
This change preserves the previous validation behavior while preventing
rejected PATCH requests from changing the stored NF profile.
Validate SBI timestamp strings before copying them into fixed-size
temporary buffers in ogs_sbi_time_from_string().
A malformed SBI request could provide an excessively long timestamp
field, causing seconds[] or subsecs[] to overflow while parsing the
RFC3339 time string. Reject oversized input and add bounds checks while
splitting seconds and fractional seconds.
This prevents a malformed SBI timestamp from terminating the NF process
with stack smashing detection.
Issues: #4612
Validate 5GS mobile identity lengths at the AMF call sites before
casting the identity buffer to fixed-size SUCI, GUTI or 5G-S-TMSI
structures.
A malformed Registration Request, Service Request or Deregistration
Request can otherwise provide a short mobile identity and make the AMF
read past the declared identity buffer while trying to find an existing
UE context.
Keep the SUCI conversion helper assert-only and reject malformed wire
input before calling it.
Validate uplink NAS PDU length before reading NAS security or mobility
management headers in AMF and MME.
Previously, only empty NAS PDUs were rejected. Short but non-empty NAS
PDUs could still reach code paths that read the NAS security header or
the inner NAS header. Also, protected NAS handling pulled the security
header without checking whether the buffer actually contained enough
bytes.
Reject too-short NAS PDUs early, check security-header pull failures, and
verify that a valid NAS header remains before dispatching the message.
This prevents malformed NGAP/S1AP NAS PDUs from being parsed past the
available buffer.
Issues: #4601 and #4602
Reject multipart header fields with empty names and guard against
header values received without a corresponding field name.
A malformed multipart body beginning a header line with ':'
can cause the multipart parser to emit a zero-length header field.
The empty field is ignored, leaving data->header_field unset.
Subsequent processing of the header value may then invoke
ogs_strcasecmp() with a NULL pointer, leading to a crash.
Treat such input as a multipart parse error and add a defensive
check in on_header_value() to ensure a header field is present
before processing the value.
Fixes: #4608
Delay replacing the old NG/S1 context until Initial UE Message
validation completes successfully.
Previously, AMF/MME could place the existing RAN context into holding
state and associate the UE with the new RAN context before validating
mandatory location and NAS IEs.
This could leave the UE with a partially updated RAN association when
the Initial UE Message was later rejected.
Issues: #4605
Delay updating the RAN UE context to the target gNB/eNB until
mandatory Path Switch Request IEs have been validated.
This avoids moving the UE context to the target RAN node when the
procedure later fails due to malformed or missing location or UE
security capability information.
Issues: #4605
Delay NH/NCC advancement and UE association updates until
handover/path-switch validation completes successfully.
Also validate mandatory transfer containers before forwarding
messages to lower layers.
This prevents malformed mobility messages from leaving partially
updated UE state when procedure validation fails.
Issues: #4605
Add ogs_hash_unset_if_owner() to remove a hash entry only when the
current value still points to the expected owner. This prevents a stale
UE context teardown from blindly deleting an identity hash entry that has
already been re-used by a newer context.
Use the owner-checked unset path for identity indexes in AMF, MME, AUSF,
UDM, PCF and SGWC.
Also handle the AMF fresh-SUCI re-registration case. When a UE registers
with a new SUCI, the old AMF-UE cannot be found by SUCI, but the same SUPI
is revealed later after authentication. Detect the existing SUPI owner in
amf_ue_set_supi() and move the old context to the new AMF-UE using the
same session-transfer path used for same-SUCI re-registration.
Add assertions before AMF/MME session-list transfer to ensure the new UE
context has no existing sessions before the old session list is moved.
Related PRs: #4574, #4575
Create PDR and Update PDR handlers iterated over SDF Filter IEs using
OGS_MAX_NUM_OF_FLOW_IN_PDR. However, the decoded PDI contains its own
fixed-size sdf_filter array, so this could read past the end of the
decoded IE array.
Limit the loop by the smaller of the decoded sdf_filter array size and
OGS_MAX_NUM_OF_FLOW_IN_PDR.
Issues: #4587
PFCP responses may arrive after the associated GTP transaction has
already been removed by timeout or cleanup. In that case,
ogs_gtp_xact_find_by_id() can legitimately return NULL, so asserting the
result can terminate SGW-C unexpectedly.
Replace those assertions in the Sxa session establishment and
modification response paths with runtime checks. Log the stale
transaction, commit the PFCP transaction where needed, and return without
crashing.
Also guard the fake bearer lookup used by PFCP error indication handling,
as the bearer context may have already been removed before the delayed
PFCP response is processed.
Issues #4586
When a duplicate SUCI/IMSI is detected during registration or attach,
the AMF/MME removed the old RAN/eNB UE context immediately while moving
the UE/session state to the new context.
This could make the core forget an NGAP/S1AP UE ID that the RAN still
held, causing subsequent messages on the old UE-associated connection to
be handled as unknown-local-UE-NGAP-ID instead of completing the proper
UE Context Release procedure.
Keep the old RAN/eNB UE context in the new UE's holding slot instead of
removing it immediately. If another held context already exists, first
try to release it and then replace the holding slot. The held context is
later released through the existing CLEAR_NG_CONTEXT/CLEAR_S1_CONTEXT
path or by the holding timer.
Also update the holding macros to avoid silently overwriting an existing
held context, and simplify related tests by removing compile-time
release-order switches.
Issues #4547
Fixed-width TLV integer fields must have exactly the expected length,
but tlv_parse_leaf() accepted shorter lengths for UINT16, UINT24 and
UINT32 while still reading the full field width.
This could allow malformed TLVs to be parsed successfully and read past
the declared IE value boundary.
Require exact lengths for 16-bit, 24-bit and 32-bit integer TLVs, matching
the encoder behavior and existing UINT8/FIXED_STR validation.
Issues: #4568
Reject NULL or empty SUPI values in the SMF UE/session creation path
before using them as hash keys. A malformed SBI request with an empty
SUPI could otherwise reach ogs_hash_get() or ogs_hash_set() with a zero
key length and trigger an assertion failure.
Also make smf_ue_find_by_supi(), smf_ue_add_by_supi(), and
smf_ue_set_supi() defensive, with explicit error logs for missing or
empty SUPI values.
IssuesL #4532
Use qos_flow->sess_id instead of qos_flow->id when looking up the
SMF session in smf_5gc_pfcp_send_one_qos_flow_modification_request().
qos_flow->id is the bearer/QoS flow pool ID, not the session ID. Using it
can make the lookup fail or return the wrong session, leading to an
assertion failure during PFCP QoS flow modification.
Move NRF discovery failure handling into amf_nnrf_handle_failed_amf_discovery()
so both SBI client timeout and NRF discovery failure paths use the same
cleanup and recovery logic.
This removes the duplicated failure handling from amf-sm.c and centralizes
UE- and session-scoped handling in nnrf-handler.c. For UE-scoped failures,
keep the old AMF discovery fallback behavior by sending an Identity Request
when SUCI/SUPI is not available during initial registration. For
deregistration, avoid sending a GMM reject and log the failure instead.
For session-scoped failures, resolve the captured RAN-UE only at the point
where a NAS/NGAP failure response must be sent, and handle stale, detached,
or mismatched NG contexts without asserting.
Also make SBI transaction ownership explicit by removing the xact in the
common failed-discovery handler before returning.
Related to #4517
Avoid assuming that the RAN-UE captured when a session-scoped NRF
discovery request was created is still alive when the discovery response
arrives.
A gNB-side disconnect or UE context release can remove the NG context
while NRF discovery is still in flight. In that case, ran_ue_find_by_id()
may return NULL. Do not assert on it at discovery-response time. Instead,
resolve ran_ue only when it is actually needed to send a NAS/NGAP failure
response in the no-NF-found path, and skip that response if the NG context
has already gone away.
Also make xact ownership explicit for failed discovery paths. If no
SearchResult is present, or if no matching NF instance is found, the
transaction is no longer forwarded via amf_sbi_send_request(), so remove
the xact before returning.
Issues #4517
InitialUEMessage starts a new UE-associated logical NG-connection, so
the RAN_UE_NGAP_ID must not already be active for the gNB. Previously,
AMF accepted a duplicate RAN_UE_NGAP_ID and passed the NAS PDU to the
NAS layer, which could result in confusing errors such as an Identity
Response being reported as an invalid 5GMM message type.
Detect duplicate RAN_UE_NGAP_ID in InitialUEMessage and send ERROR
INDICATION without modifying or releasing the existing UE context.
Also send ERROR INDICATION when an InitialUEMessage carries an invalid
NAS PDU or a 5GMM message type that is not valid for InitialUEMessage,
then clean up the newly-created RAN UE context.
Issues #4481
Store the originating SBI stream ID in nrf_assoc_t instead of caching
the raw stream pointer. A delayed Home-NRF response may arrive after
the original client has already closed the inbound stream, leaving the
cached ogs_sbi_stream_t pointer dangling.
Resolve the stream again from the stored pool ID in discover_handler().
If the originating stream is already gone, drop the orphaned Home-NRF
response and clean up the association instead of dereferencing a stale
stream pointer.
Issues #4476
Track outbound SBI transactions that are associated with an inbound
server stream, and cancel them automatically when the originating
stream or session is removed.
This prevents response-bound outbound transactions from keeping their
response timers alive after the client-side stream has gone away. In
particular, repeated NAUSF authentication and 5G-AKA confirmation
requests can otherwise leave pending Nudm_UEAU transactions behind
until the xact/timer pool is exhausted, causing later requests to fail
in the NF wrapper path.
Add a secondary stream attachment node to ogs_sbi_xact_t and keep the
attachment idempotent. ogs_sbi_xact_remove() detaches the transaction
from the stream list, while HTTP/2 stream cleanup and MHD session
cleanup remove any still-pending attached transactions.
If the originating stream id is valid but the stream itself is already
gone, log the condition and continue the upstream send without
propagating the condition to NF callers. Some NF procedures send the
original HTTP response first and then continue with follow-up SBI
transactions while still passing the original stream pointer for
convenience.
Issues #4472 and #4473
Handle subscription_data_pool exhaustion without aborting so malformed or
repeated NF status subscription requests cannot crash the process.
Change ogs_sbi_subscription_data_add() to return NULL when the pool is
exhausted, and make both NRF server-side and client-side subscription paths
handle the failure gracefully. Also handle SBI client allocation failure when
processing nfStatusNotificationUri, rolling back the partially-created
subscription and returning an error response instead of asserting.
For NF status subscription renewal, remove the expired subscription before
creating the replacement so renewal can still succeed when the subscription
pool is full. Update NF state machines to stop asserting on subscription
subscribe/update send failures and log the failure instead.
Issues #4464 and #4465
Return NULL from ogs_sbi_nf_instance_add() when the NF instance
pool is exhausted instead of asserting, and update callers to handle
allocation failure explicitly.
Also reject Nnrf_NFManagement requests for nf-instances without an
NFInstanceId before dispatching to the NF FSM. This prevents PUT/PATCH/
DELETE requests to /nnrf-nfm/v1/nf-instances from reaching paths that
expect resource.component[1] to be present.
For inter-PLMN discovery fallback, avoid referencing request->h.uri
before the outbound request is built. Log the invalid hnrf-uri instead,
clean up the temporary NRF instance, and return Bad Request.
Remove the now-unnecessary
ogs_sbi_nf_instance_maximum_number_is_reached() helper.
Issues #4456#4457#4462
Validate UE-provided QoS rules and QoS flow descriptions while parsing
NAS IEs instead of passing partially decoded malformed structures to SMF.
Reject invalid packet filter content, oversized QoS rule/flow arrays, and
invalid bitrate units. Also make bitrate conversion robust against invalid
units as defense in depth.
This prevents malformed PDU Session Modification Request payloads from
reaching SMF logic and triggering assert/fatal paths.
Issues #4455
Reject malformed QoS rules and QoS flow descriptions in the NAS parser so
invalid partially decoded structures are not passed to SMF.
This validates packet filter content, QoS rule/flow array bounds, and bitrate
units, preventing malformed PDU Session Modification Request payloads from
triggering assert/fatal paths in SMF.
Issues #4551 and #4552
Reject malformed Home Routed roaming SBI data before it reaches later
NAS/N2 handling paths that assume validated session state.
Validate VCN/HCN tunnel information before logging nested fields, require
a full DNN for HR PDU session creation, and reject V-SMF update requests
for non-HR sessions.
Validate H-SMF provided QoS flow setup data before storing it in the
session, including required qosRules, optional qosFlowDescription, and
qosFlowProfile fields. Also validate V-SMF update AddMod/Rel lists before
copying them into the session.
Build replacement QoS lists only after validation succeeds so malformed
requests cannot partially update session state or leak temporary list
entries.
Issues #4446, #4447, #4448, #4449, #4450, #4453 and #4454.
Refactor the base64 helper API to make the intended input/output types
clearer and to require callers to provide output buffer sizes.
Add explicit helpers for decoding to buffers/strings and encoding from
buffers/strings, and remove the older ambiguous decode/decode_binary and
encode/encode_binary interfaces.
Update existing users to use the new API, including SBI message handling,
SMF/AMF base64 encoding paths, GSM HR roaming NAS data decoding, and the
base64 unit tests.
This also avoids assert-based base64 decoding in gsm-build.c by using a
small local helper that reports decode failures and returns through the
existing cleanup paths.
Avoid aborting the SMF when a malformed SM Policy Decision contains
invalid PCC rule or QoS data from the PCF.
Add bounds checks before writing to the fixed-size PCC rule and flow
arrays, skip invalid flow entries with missing flowDescription, and avoid
reusing stale QoS data across PCC rules. Also handle unknown ARP
preemption capability/vulnerability values without triggering assertions.
This prevents crashes caused by malformed pccRules, flowInfos,
flowDescription, and ARP enum values while keeping the existing policy
update flow unchanged.
Issues #4442#4443#4444#4445
Validate malformed SBI inputs instead of relying on assertions in PCF
paths reachable from peer or client-controlled messages.
Handle invalid BSF Location values with proper error responses, ignore
late NRF discovery results when the associated stream has already gone
away, reject unsupported IPv6 prefix lengths without asserting, and
enforce POST for /delete subresources.
Also harden Rx-to-Gx flow conversion by validating missing or malformed
flow descriptions, including out-of-order from/to tokens.
Issues #4437#4438#4439#4440#4441
Reject malformed or oversized SBI discovery parameters instead of
allowing them to reach assertions or fixed-size arrays.
Change discovery option parsers to return OGS_OK/OGS_ERROR so callers can
propagate parse failures as Bad Request. This covers service-names, snssais,
GUAMI, TAI, target-plmn-list and requester-plmn-list.
Also handle delayed Home-NSSF responses gracefully when the original requester
stream has already been removed, and reject Home-NSSF discovery when no
serving PLMN is configured.
Issues #4431#4432#4433#4434#4435#4436
Validate ipv4Address and ipv6AddressPrefix from SM Policy
Association Create requests before storing them in the PCF session.
Previously, malformed values such as an empty ipv4Address could reach
pcf_sess_set_ipv4addr() under ogs_assert(), causing the PCF to abort
instead of rejecting the request.
Return 400 Bad Request with ERROR_INITIAL_PARAMETERS for invalid address
fields.
Issues #4428
The PFCP FAR handlers copied Outer Header Creation directly after
asserting that the decoded IE had a data pointer and non-zero length.
A malformed message with a present but empty Outer Header Creation IE
could therefore trigger an assertion failure.
Reject such malformed Create FAR and Update FAR requests with
Invalid Length and report Outer Header Creation as the offending IE,
instead of relying on assertions.
Issues #4423
Reject a decoded NAS message container when its inner message type does not
match the NAS procedure being resumed.
Previously, AMF decoded the NAS message container and dispatched based only on
the inner message type. This allowed a crafted SecurityModeComplete, received
while a Registration Request procedure was in progress, to carry a Service
Request in the NAS message container. The AMF could then switch to the service
request path before registration context such as allowed NSSAI had been
established, eventually hitting an assertion while building NGAP
InitialContextSetupRequest.
For SecurityModeComplete, compare the decoded inner message type with the
initial NAS message type already stored in amf_ue->nas.message_type. For NAS
containers carried directly by Registration Request or Service Request, require
the inner message type to match the outer cleartext message type.
Also reject unsupported inner message types before dispatching the container.
Issues #4422
Do not commit the session remote DL tunnel before confirming that at least one
DL FAR is updated.
PDUSessionResourceSetupResponseTransfer and PathSwitchRequestTransfer update
FARs only for QoS flows referenced by the received NGAP QoS flow list. If the
remote DL IP or TEID changes but none of the listed QFIs matches a local QoS
flow, far_update can be set without any actual FAR/PDR change and the SMF can
reach the PFCP modification builder with nothing to modify.
Use the received remote DL tunnel directly while updating FARs, count the
number of updated DL FARs, and reject the update if a PFCP modification would
otherwise be sent with no FAR updated. Commit sess->remote_dl_ip/teid only
after confirming that at least one DL FAR was updated.
Issues #4413
Avoid aborting UDM on malformed or out-of-sequence SBI requests.
For UEAU resynchronization, ensure authType is initialized before building
AuthenticationInfoResult after a successful authentication-subscription PATCH
response. The normal GET path already initializes authType, but the PATCH path
can be reached without that prior state.
For UECM SMF registrations, reject collection-level smf-registrations requests
without a pduSessionId before dispatching to the session FSM.
For AMF registration updates, validate that the request targets
amf-3gpp-access, reject unsupported child resources, and return Not Found when
there is no existing AMF 3GPP access registration instead of asserting.
Issues #4418#4419#4420
Reject malformed SUPI and PEI values without aborting in UDR and DBI paths.
Return errors instead of asserting on invalid parsed identifier type or value,
and handle malformed HSS Diameter User-Name values without truncation.
Issues #4410#4411#4412
Handle unexpected or incomplete successful SM context update responses from
the SMF as errors instead of aborting the AMF.
If PDU_RES_SETUP_REQ is received in an invalid update state, or if a
registration/service request update succeeds without required N2 SM
information, return an error rather than reaching ogs_assert_if_reached().
Issues #4408
Issues #4409
Do not abort rule compilation when getprotobyname() fails for protocol
names such as udp or tcp. Add built-in fallbacks for common protocol names
so SDF filters can be parsed even when protocol name lookup is unavailable.
Unknown protocol names are still rejected by returning NULL instead of
terminating the process.
Issues #4407
Avoid crashes when UDM SDM AM data contains malformed GPSI values or
oversized GPSI/NSSAI lists.
Limit stored MSISDN and S-NSSAI entries to the fixed AMF UE array sizes,
skip invalid GPSI values instead of asserting, and stop parsing once the
corresponding storage is full.
Issues #4403#4404#4405
Reject malformed IPv4 addresses and unsupported IPv6 prefixes in
Nbsf_Management pcfBindings instead of aborting the BSF process.
Return Bad Request for invalid input, while preserving Not Found for
valid but unmatched bindings. Also handle session creation failure
without asserting.
Issues #4400#4401
When HOLDING_S1_CONTEXT() runs for a UE whose MME-NAS context has
been re-associated with a newer S1 connection, the old enb_ue may be
kept in the pool while its mme_ue_id is cleared. This prevents later
cleanup of the old S1 context from disturbing the new enb_ue/mme_ue
association.
If the eNB still keeps the old S1 context and later sends a message
using the old ENB_UE_S1AP_ID and MME_UE_S1AP_ID, the MME can still
find the old enb_ue but can no longer find the associated mme_ue.
Send UEContextReleaseCommand with S1_CONTEXT_REMOVE instead, so the
eNB can explicitly release the stale context. This also prevents stale
UplinkNASTransport messages from being dispatched to NAS without an
associated mme_ue.
Apply this handling to non-handover S1AP procedures only. Handover-related
procedures are intentionally left unchanged because they involve
source/target UE contexts and handover-specific state transitions.
Related PR: #4566, #4564
Issues: #4547
When HOLDING_NG_CONTEXT() runs for a UE whose AMF-NAS context has
been re-associated with a newer NG connection, the old ran_ue may be
kept in the pool while its amf_ue_id is cleared. This prevents later
cleanup of the old NG context from disturbing the new ran_ue/amf_ue
association.
If the gNB still keeps the old NG-RAN context and later sends a message
using the old RAN_UE_NGAP_ID and AMF_UE_NGAP_ID, the AMF can still find
the old ran_ue but can no longer find the associated amf_ue. In that
case, replying with Error Indication/unknown-local-UE-NGAP-ID is not
helpful because the AMF still knows the stale NG context.
Send UEContextReleaseCommand with NG_CONTEXT_REMOVE instead, so the
NG-RAN can explicitly release the stale context. This follows the same
cleanup direction already used by ngap_handle_ue_context_release_request()
when ran_ue is found but amf_ue lookup fails.
Apply this handling to non-handover NGAP procedures only. Handover-related
procedures are intentionally left unchanged because they involve
source/target UE contexts and handover-specific state transitions, and
should be reviewed separately.
This keeps the existing HOLDING_NG_CONTEXT() and CLEAR_NG_CONTEXT()
timing unchanged, preserving the current NGAP message ordering.
Issues: #4547
When PFCP deletion completes in smf_gsm_state_wait_pfcp_deletion(),
the original SBI stream may already have been removed. In that case,
SMF cannot send the N1/N2 PDU Session Release Command to the AMF, so it
must not continue to build N1/N2 buffers or wait for the N1/N2 release
procedure to complete.
Handle the NULL stream case before building the release command. Continue
with the normal SBI cleanup procedure using POLICY_FIRST mode, then move
to smf_gsm_state_5gc_session_will_deregister to wait for the cleanup
response.
This avoids entering smf_gsm_state_wait_5gc_n1_n2_release when the N1/N2
release procedure was never started, while still allowing associated
PCF/UDM state to be cleaned up.
Original PR #4545
Update NFProfile handling to keep the existing in-place update model for
nfServices. nfServices are matched by serviceInstanceId, and existing
nf_service objects are reused so runtime client bindings remain valid across
repeated NFProfile updates.
If a new nf_service or nf_info cannot be allocated, return an error instead of
aborting the process. Propagate those failures through the NFProfile handlers so
oversized or malformed profiles can be rejected.
When profile handling fails for a newly created NF cache entry, remove it because
it may contain a partial profile. If the entry already existed, keep it in the
registry to avoid deleting a previously usable local cache because of one bad
notification or discovery result.
Issues #4466
Related to PR #4534
When a gNB is removed, AMF deassociates the RAN UE if no SMF
transaction is created during session deactivation.
However, if the UE is still in the registration procedure, there is no
registered NAS context to keep and no mobile reachable timer path to
clean up the AMF UE context later. This can leave the AMF UE context in
the pool after repeated gNB/SCTP disconnects.
Keep the existing deferred cleanup behavior for registered UEs by
starting the mobile reachable timer, but immediately remove the AMF UE
context for non-registered UEs.
Issues #4516
Original PR: #4529
Issues #4249, #4250 and #4252 reported that oversized NFProfile
lists could trigger assertions while handling externally supplied
NRF input.
Make ogs_nnrf_nfm_handle_nf_profile() return failure when bounded
SMF/AMF NFProfile lists overflow, and propagate that failure as
HTTP 400 Bad Request in the NRF registration path.
This removes the remaining assertions for peer-supplied inner-list
sizes in:
- smfInfo.sNssaiSmfInfoList[*].dnnSmfInfoList
- amfInfo.taiRangeList[*].tacRangeList
Also handle DNN allocation failure without aborting the process.
Related to PR #4527.
Issues #4249
Issues #4250
Issues #4252
Do not overwrite the locally stored UE security capabilities with the
values received in PathSwitchRequest.
During path switch, the AMF/MME should verify the UE security capabilities
received from the target RAN node against the locally stored values. If a
mismatch is detected, keep the locally stored values and include them in
PathSwitchRequestAcknowledge.
This patch adds mismatch detection for both NGAP and S1AP path switch
procedures, logs the mismatch, and sends the locally stored UE security
capabilities in the acknowledge message when required.
Issues #4393
Issues #4522
Related to PR #4518
Related to PR #4520
Validate malformed NAS QoS flow descriptions before they can reach
SMF QoS update logic. Reject unsupported QoS flow parameter counts and
invalid bitrate units during parsing, so invalid input cannot trigger
assertions in ogs_nas_bitrate_to_uint64().
Also avoid aborting while handling QoS rules and QoS flow descriptions
in PDU Session Modification Request processing. Use the packet-filter
index when reconfiguring packet filters, handle reconfiguration failures
as invalid requests, and return an error instead of calling fatal/assert
for unknown QoS flow parameters.
Finally, replace assert-based parsing of QoS rules and QoS flow
descriptions in gsm-build.c with normal error handling, so malformed
QoS data from HR roaming paths does not terminate the SMF process.
Issues #4429
Issues #4430
Issues #4511
Issues #4512
Related to PR #4513
Related to PR #4514
Use EPS_BEARER_CONTEXT_STATUS_PRESENT when checking the TAU Request
presence mask for EPS Bearer Context Status.
The previous code used EPS_BEARER_CONTEXT_STATUS_TYPE, which is the IEI/type
value rather than the presence-mask bit. As a result, the BCS handling path
could be skipped even when the EPS Bearer Context Status IE was present.
Apply the same fix to both normal TAU handling and combined
SGsAP LU accept/reject paths.
Original PR: #4505
Add common helpers to validate UE identifiers received in NGAP and S1AP
UE-associated messages before using the resolved UE context.
For NGAP, validate that AMF_UE_NGAP_ID is present, can be decoded, is
within range, resolves to an existing RAN UE context, belongs to the gNB
that sent the message, and matches the received RAN_UE_NGAP_ID.
For S1AP, validate that MME_UE_S1AP_ID and ENB_UE_S1AP_ID are present,
that ENB_UE_S1AP_ID is within range, and that the resolved eNB UE context
belongs to the eNB that sent the message.
Use the resolved context IDs directly after successful validation instead
of passing decoded UE IDs back to callers.
Handover, path switch, status transfer, reset, error indication, and UE
context release request paths are intentionally left unchanged because
they have different context lookup semantics.
Issues #4498
Supersedes PR #4501
Validate inner IPv4/IPv6 packet lengths before accessing header fields in
ogs_pfcp_pdr_rule_find_by_packet().
Malformed GTP-U packets could previously cause out-of-bounds reads while
matching PDR rules, especially with oversized IPv4 header length, invalid
IPv6 payload length, malformed IPv6 extension headers, oversized IPv6 jumbo
payload length, or truncated TCP/UDP headers.
Parse the inner IP header once before iterating over PDR rules, reject
malformed packets early, and validate TCP/UDP header availability before
reading port fields.
This also avoids repeated IP header parsing inside the rule loop and makes
the packet validation independent of whether a specific PDR rule matches.
Fixes#4491
Original PR: #4500
Handle UE-requested H-SMF PDU session modification through two explicit
paths: UP connection state transition and QoS Flow modification.
Only DEACTIVATED, ACTIVATING and ACTIVATED are valid upCnxState values
for the state transition path. If upCnxState is absent, pfcp_flags must
be present for QoS Flow modification.
Reject any other HsmfUpdateData combination with Bad Request instead of
aborting the SMF. This prevents malformed requests such as unsupported
upCnxState values or missing upCnxState/pfcp_flags from reaching the
fatal fallback path.
Based on the original fix proposed in PR #4499.
Issues: #4490
ogs_sbi_client_send_via_scp_or_sepp() called ogs_sbi_getpath_from_uri()
but did not check the return value before asserting on path. When a
caller (e.g. an NRF subscription) supplied a URI lacking a path
component (http://host:port instead of http://host:port/path),
ogs_sbi_getpath_from_uri() returned false with path=NULL and the
subsequent ogs_assert(path) aborted the process -- usable as a
denial-of-service against any SBI-based NF.
Convert the unchecked assertion into a graceful error return: log the
malformed URI, free the locally-allocated apiroot, and return false to
the caller. All existing call sites already check the return value.
Issues: #4489
Check DnnInfo and DnnInfo->dnn before storing subscribed DNN
information in the slice session array.
The AMF stores DNN information from SmfSelectionSubscriptionData in
slice->session[], which is bounded by OGS_MAX_NUM_OF_SESS. If the UDM
returns more DNN entries than this limit, slice->num_of_session can
exceed the array size and corrupt memory.
Stop processing additional DNN entries once the slice session limit is
reached, and skip malformed DNN entries without dereferencing them.
This is based on the issue reported in the original PR #4494.
This change is based on the issue addressed in original PR #4488.
When stream_add() fails in on_begin_headers(), the SBI server currently
hits ogs_assert(stream), which can abort the whole NF process.
Handle the failure as a stream-level refusal instead of a process-level
abort. Explicitly submit RST_STREAM with NGHTTP2_REFUSED_STREAM before
returning NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE.
According to nghttp2, returning NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
alone closes the stream with NGHTTP2_INTERNAL_ERROR. If a different
HTTP/2 error code is desired, the application must first submit
RST_STREAM with the desired code and then return
NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE.
NGHTTP2_REFUSED_STREAM is the better semantic match here because the
request has not been processed yet. This lets the peer treat the failure
as a temporary stream refusal rather than a generic internal server
error, which is more appropriate when the stream pool is exhausted.
Add a common ogs_pdu_session_id_is_valid() helper in lib/proto and use it
on SMF SBI session-create paths.
The OpenAPI pduSessionId field is stored as int, while the SMF session
lookup path eventually uses uint8_t. As a result, out-of-range values such
as 256 could wrap to 0 and hit the unassigned PSI assertion.
This change rejects invalid PDU session identities before creating or
looking up SMF session context.
Based on the original fix proposed in PR #4487.
Expose the last UE location update timestamp in the operator-facing JSON
info dumps.
For MME /ue-info, add the timestamp under the existing location object as
location.timestamp, matching the AMF /ue-info schema.
For SMF /pdu-info, add ue_location_timestamp to each PDU session entry,
since the value is exposed directly in the PDU session object.
The timestamp is stored as epoch microseconds in ogs_time_t. A value of 0
means the location has not yet been updated for the corresponding UE or
session.
This helps external OAM and reconciliation tools distinguish stale UE or
PDU session state from legitimately idle state.
This change is based on the original proposal in PR #4484, with the MME
field name adjusted to align with the existing AMF /ue-info schema.
Add T3396 support for selected ESM PDN Connectivity Reject causes.
This change is split out from PR #4483 and keeps only the NAS/ESM
back-off timer part.
When the MME rejects a PDN Connectivity Request with one of the ESM causes
for which UE back-off behavior is well-defined, include the Back-off timer
value IE in the PDN Connectivity Reject message.
The initial supported causes are:
- Missing or unknown APN
- Service option not supported
- Requested service option not subscribed
T3396 defaults to 12 minutes, matching the standard default back-off behavior
for these causes, and can be overridden through mme.time.t3396.value.
This is a revised implementation based on the original PR #4482.
When a UE attaches through EPC, the SMF indexes the UE by raw IMSI
bytes. When the same subscriber later attaches through 5GC, the SMF
indexes the UE by SUPI string. Since the two add paths only populated
their native index, the same physical subscriber could end up with two
different smf_ue_t objects and separate session lists.
Fix this by keeping IMSI and SUPI as two canonical representations of
the same subscriber identity. For IMSI-based SUPIs, both add paths now
converge on the same smf_ue_t:
- smf_ue_add_by_supi() derives the IMSI alias from "imsi-..." SUPI
and registers the UE in imsi_hash.
- smf_ue_add_by_imsi() derives the "imsi-..." SUPI alias from raw IMSI
bytes and registers the UE in supi_hash.
- identity setters own both field assignment and hash registration.
- identity ownership violations are treated as fatal invariants.
- malformed IMSI SUPIs are rejected instead of being accepted as
SUPI-only UE contexts.
Move common IMSI/SUPI parsing helpers to lib/proto so the validation is
not SMF-specific and can be reused by other components.
Also remove the later IMSI re-population from nsmf-handler.c. Once the
UE identity is canonicalized at add time, rewriting smf_ue->imsi from
the SBI request body would risk mutating memory already used as an
imsi_hash key.
This prevents split SMF UE contexts across 4G and 5G attach paths and
lets existing per-UE session cleanup and uniqueness checks operate on
the complete session list.
The /ue-info endpoint decodes the stored NR Cell Identity into gNB ID
and Cell ID. However, the gNB-ID length is not always the legacy 22-bit
split, and using only the current live gNB context to decode ue->nr_cgi
can produce incorrect results.
ue->nr_cgi is stored independently in the AMF UE context and can outlive
or lag the current RAN association, for example after NG release or after
a later GlobalRANNodeID change. Therefore the gNB-ID length must be
stored together with the UE's saved NR-CGI location.
This patch stores the parsed gNB-ID length in amf_gnb_t, snapshots it
into ran_ue->saved together with nr_cgi, copies it into amf_ue_t, and
uses the UE-local nr_cgi_gnb_id_length when rendering /ue-info.
The legacy 22-bit gNB ID / 14-bit Cell ID split is kept as a fallback
when no valid gNB-ID length is available.
In case there are large amount of UEs with VoLTE enabled,
but the network does not have an IMS APN, nor IMS services,
it makes sense to disable IMS voice over PS in S1 mode in
the attach/TAU accept message, thus preventing these UEs
to try and activate an IMS PDN endlessly.
To resolve this, a new flag is introduced:
```
global:
parameter:
no_ims: true
```
If this flag is set to 'true', the MME will respond with an Attach accept
or TAU accept, which has the EPS network feature:
"IMS voice over PS session in S1 mode" set to "Not supported".
By default this flag is false, thus not modifying the original behavior.
Add safe-default fallback (protocol/unspecified) when Cause IE is
missing, and use a switch on Cause->present to read the correct
union member for each cause group.
Fixes two issues:
1. NULL pointer dereference when Cause IE is absent (SIGSEGV crash)
2. Wrong union member access when Cause group is not radioNetwork
Co-authored-by: Sukchan Lee <acetcom@gmail.com>
Use exact SST and SD matching when comparing S-NSSAIs during NRF
discovery filtering and requester authorization.
Previously, an absent SD value was treated as a wildcard, allowing an
S-NSSAI with only SST to match another S-NSSAI with the same SST but a
present SD. However, 3GPP TS 29.510 requires the S-NSSAI components to be
identical for discovery query parameter matching.
Update the NRF discovery unit tests to verify that SD absent does not
match SD present, while both sides with absent SD still match.
Fixes#4373
Regenerate the S1AP and NGAP ASN.1 sources from the R19 specifications
using the updated asn1c generator.
The newer generator represents several constructed ASN.1 values as
pointers, including CHOICE alternatives, protocolIEs containers, and
SEQUENCE OF/SET OF list wrappers. Update MME, AMF, and related tests to
allocate these members explicitly, assign pointer-backed alternatives,
and access ASN.1 lists through OGS_ASN_LIST_COUNT() and
OGS_ASN_LIST_GET().
Add helper routines for descriptor-based allocation of constructed ASN.1
values and protocolIEs containers, so protocol code no longer depends on
the old embedded-structure layout.
- Update OpenAPI models to Release-19 specifications
- Refactor SBI handling to use OpenAPI_service_name_e
- Replace service type based logic with service name based handling
- Introduce service_name_array for per-service NF instance caching
- Add support for special/internal service names (e.g. namf-callback)
- Update NRF discovery handling across all NFs
- Validate SearchResult fields before processing
- Remove legacy service-type dependencies
This change aligns the SBI implementation with Release-19
specifications and simplifies service name based routing.
The AK value is 6 bytes long, but it was logged using OGS_KEY_LEN (16 bytes),
which causes the hexdump to read beyond the end of the buffer. Replace
OGS_KEY_LEN with OGS_AK_LEN to ensure correct logging and avoid potential
out-of-bounds reads.
This issue is similar to the fix applied in hss-cx-path.c for CVE-2025-15555.
Issues: #4177, #4389
The HTTP upload handling in access_handler() used ogs_malloc() and
ogs_realloc() results directly assigned to request->http.content and
checked with ogs_assert(). On allocation failure this could abort the
process, leading to a potential denial-of-service condition. The pattern
was similar to the issue previously fixed in on_data_chunk_recv()
(CVE-2022-3299).
This change introduces a temporary pointer for memory allocation and
updates request->http.content only after successful allocation. It also
adds overflow-safe length checks before resizing the buffer and removes
assert-based error handling in favor of graceful failure.
This prevents process termination on allocation failure and aligns the
memory handling logic with the hardened implementation used in
nghttp2-based handlers.
Issues: #4387
Add bounds checking to ogs_sbi_parse_plmn_list() and handle_scp_info()
to prevent out-of-bounds writes when input exceeds the fixed array limits.
- ogs_sbi_parse_plmn_list(): limit to OGS_MAX_NUM_OF_PLMN (12)
- handle_scp_info(): limit to OGS_MAX_NUM_OF_SCP_DOMAIN (8)
Without these checks, an unauthenticated HTTP/2 request with oversized
arrays can crash any SBI-based NF (PLMN list: heap overflow → arbitrary
free, SCP domain: stack overflow → stack smashing).
Issues: #4382, #4383
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 patch improves robustness of several GTPv1/v2 parsing paths by
adding explicit length validation and replacing assert-based checks
on network-controlled data with graceful error handling.
Changes include:
- GTPv1 MM Context parser:
Add bounds checks for xres_len, autn_len and num_vectors to prevent
stack overflows when decoding authentication quintuplets.
- SMF Gn handler:
Validate IMEI(SV) IE length before memcpy to prevent heap overflow
in smf_ue->imeisv.
- SMF Gn handler:
Validate Common Flags IE length before dereferencing to avoid
out-of-bounds reads when malformed IE is received.
- GTPv1 ULI parser:
Replace ogs_assert-based length checks with proper validation and
error return to prevent abort() on truncated User Location
Information IE.
- SMF fd-path:
Replace assertions on ULI payload presence with runtime checks
to avoid process termination on malformed input.
These changes ensure malformed or truncated network messages are
handled gracefully instead of triggering process aborts.
When mme_ue_set_imsi() updates an existing UE IMSI, the previous
code overwrote mme_ue->imsi before removing the old hash entry.
As a result, the old IMSI key could remain in imsi_ue_hash and keep
pointing to the same mme_ue object. After the UE context was removed,
a later lookup by the stale IMSI key could return an invalid context
and trigger a fatal path during re-attach handling.
Remove the old IMSI hash entry before updating mme_ue->imsi, then
register the new IMSI after the update.
Issues: #4357
This patch addresses a potential subscription_data pool exhaustion
issue observed during repeated NF re-registration with the NRF.
Two improvements are introduced:
1) Prevent duplicate NF status subscriptions
Before sending a new NF status subscription request, the code now
checks whether an equivalent subscription already exists in the
local subscription_data list. If a matching subscription (based on
req_nf_instance_id and subscr_cond) is found and it is not already
marked with DELETE_SENT, the new subscription request is skipped.
This prevents repeated subscription creation during re-registration
loops.
2) Ensure local cleanup after DELETE response
When handling HTTP DELETE responses for NF status subscriptions,
the local subscription_data entry is now removed regardless of the
response status. Previously, the entry was only removed on
HTTP 204 (No Content), which could leave stale entries in the local
list when the NRF returned other statuses (e.g., 404).
Keeping stale entries could lead to unbounded growth of
subscription_data and eventual pool exhaustion.
Additionally, successful DELETE operations are logged to improve
debugging visibility.
This change affects all NF state machines that handle subscription
DELETE responses (AMF, AUSF, BSF, NSSF, PCF, SCP, SEPP, SMF, UDM, UDR,
and AF test code).
Issues: #4207
mme_find_served_tai() incorrectly compares the PLMN-ID of TAC range
entries using list0->tai[j].plmn_id instead of list1->tai[j].plmn_id.
When TAC ranges are configured in mme.tai (e.g. tac: [1-11]), the range
entries are stored in list1. However, the lookup logic mistakenly reads
the PLMN from list0 while validating list1 entries, which can cause the
Served TAI match to fail even though the TAC is within the configured
range.
As a result, eNB S1 Setup may fail with:
Cannot find Served TAI. Check 'mme.tai' configuration
This patch fixes the comparison to use list1->tai[j].plmn_id so that TAC
range entries are matched correctly.
Fixes TAC range configuration such as:
tac: [1-11]
Issues: #4345
In smf_gx_cca_cb(), smf_gy_cca_cb(), and S6b CCA callbacks, the code
assumed that a Diameter session always exists when processing a CCA
message and enforced this invariant with:
ogs_assert(new == 0);
However, if a malicious or misbehaving Diameter peer sends a
Credit-Control-Answer containing an unknown or mismatched Session-Id,
fd_msg_sess_get() returns new=1, indicating that the session does not
exist locally. The assertion then triggers ogs_abort(), terminating
the entire SMF process.
This allows a single malformed CCA message to cause a denial-of-service
by crashing the SMF and dropping all active UE sessions.
Replace the assertion with a runtime check. If the session does not
exist (new != 0), the message is logged and discarded via the existing
cleanup path instead of aborting the process.
Affected callbacks:
- smf_gx_cca_cb()
- smf_gy_cca_cb()
- smf_s6b_aaa_cb()
- smf_s6b_sta_cb()
This ensures that unexpected or malicious Diameter answers do not
terminate the SMF process and are handled gracefully.
Issues: #4343
When a UE sends TAU Request with active_flag=1 and a Bearer Context
Status that mismatches MME state, the BCS cleanup deletes all sessions
but the stored procedure remains InitialContextSetup. Building an
Initial Context Setup Request with zero E-RABs returns NULL, hitting
ogs_assert and killing the process — disconnecting all eNBs.
Guard in mme_send_tau_accept_and_check_release(): if no sessions remain
after BCS cleanup, downgrade to DownlinkNASTransport so TAU Accept is
delivered without requiring bearers.
ogs_pco_parse() previously relied on ogs_assert() to verify the bounds
of Protocol/Container fields while parsing PCO/EPCO data. If the outer
PCO/EPCO length was inconsistent with the internal container encoding
(e.g., truncated Container-ID, Container-Length, or container data),
the assert would trigger and terminate the process.
Because PCO/EPCO is derived from UE-supplied NAS messages (e.g.,
PDU Session Establishment Request), a malformed EPCO IE could trigger
a remote SMF crash, resulting in a denial-of-service condition.
This patch replaces the assert-based bounds checks with explicit
runtime validation and returns an error when malformed or truncated
PCO/EPCO is detected. The SMF can then reject the request cleanly
instead of aborting.
Checks added:
- Validate minimum PCO/EPCO length before accessing header fields
- Verify Container-ID bounds
- Verify Container-Length bounds
- Verify container payload length
- Detect container count overflow beyond
OGS_MAX_NUM_OF_PROTOCOL_OR_CONTAINER_ID
With these changes, malformed EPCO inputs are safely rejected and the
SMF remains operational.
Issues: #4341
The MME terminated with abort() when processing IDR or ULA messages
containing a malformed Served-Party-IP-Address (AVP 848) or
MIP-Home-Agent-Address (AVP 334).
In mme_s6a_subscription_data_from_avp(), the return value of
fd_msg_avp_value_interpret() was checked using ogs_assert(ret == 0).
However, this function may legitimately return an error if the Address
AVP contains an invalid encoding (e.g., invalid address family or
length mismatch). Since freeDiameter treats Address AVPs as raw
OctetString during decoding, malformed values can reach this code path.
As a result, receiving such an AVP caused ogs_assert() → ogs_abort() →
abort(), terminating the entire MME process.
Fix this by replacing the assertion with proper error handling.
If fd_msg_avp_value_interpret() fails, the malformed AVP is ignored
with a warning log and processing continues.
This prevents a malformed or malicious Diameter message from crashing
the MME while preserving normal operation for valid data.
Issues: #4334
Clear presence-driven fields before processing conditional IEs to prevent
stale state when find_or_add() returns an already-existing entry.
FAR: reset dst_if_type_presence and outer_header_creation_len
URR: reset all measurement/threshold/quota fields
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a PFCP control plane sends a Session Modification Request with
Create FAR, Create QER, or Create URR IEs for IDs that were not
previously created during PDR processing, the UPF rejects them with
"Cannot find [FAR|QER|URR]-ID[N] in PDR" errors.
This is because ogs_pfcp_handle_create_far/qer/urr() use
ogs_pfcp_[far|qer|urr]_find() which only looks up existing entries,
while ogs_pfcp_handle_create_pdr() correctly uses
ogs_pfcp_pdr_find_or_add() which creates new entries if needed.
In practice, some PFCP control planes (e.g., vendor-specific PGW-C
implementations) send Create URR/QER/FAR in Session Modification
without a corresponding Create PDR that would have pre-created these
entries. The resulting PFCP error responses cascade into GTP-U Error
Indications, causing bearer teardowns and IMS PDN disconnections.
This patch:
- Changes Create FAR/QER/URR handlers to use find_or_add, matching
the existing Create PDR behavior
- Makes Remove PDR/FAR/QER/URR handlers idempotent: removing a
non-existent entry now returns success with a warning instead of
failing with an error, since the desired state (entry removed) is
already achieved
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Some UEs and fuzzing inputs may send a Registration Request with
registration_type.value set to 0. According to TS 24.501 Table 9.11.3.7.1,
unused registration-type encodings shall be interpreted by the network
as "initial registration". Without normalization, the invalid value may
propagate into subsequent logic and lead to unexpected behavior during
UE context transfer handling.
This patch normalizes registration_type.value == 0 to
OGS_NAS_5GS_REGISTRATION_TYPE_INITIAL early in
gmm_handle_registration_request() so that later procedures operate on
a valid registration type.
Additionally, improve robustness in
gmm_registration_request_from_old_amf() by ignoring placeholder
5G-GUTIs where AMF-ID and M-TMSI are zero. Some devices (and fuzzing
tools) send such values even though they do not represent a valid
previous AMF context. Treating them as actionable may incorrectly
trigger N14 UE Context Transfer attempts.
With this change, placeholder GUTIs are treated as non-actionable and
the AMF falls back to normal registration / identity procedures.
Issues: #4321
Previously, the MME aborted when receiving a Cancel-Location-Request
(CLR) with an unsupported Cancellation-Type. The default case logged
a fatal message and called ogs_assert_if_reached(), which terminated
the process.
However, Cancellation-Type values such as UPDATE_PROCEDURE_IWF (3)
and INITIAL_ATTACH_PROCEDURE (4) are defined in 3GPP TS 29.272 but are
not implemented in Open5GS. Since this field originates from external
Diameter input, the MME must not crash when encountering unsupported
values.
Replace ogs_fatal() and ogs_assert_if_reached() with ogs_error() so the
MME logs the issue and continues running instead of aborting.
This prevents a potential denial-of-service condition where a malformed
or unexpected CLR message could terminate the MME.
Issues: #4309
The AMF could abort when processing malformed or oversized multipart
SBI requests due to an assertion triggered in the multipart parser
callback.
When the parser encountered an overflow condition while assembling
multipart part data, `on_part_data()` executed `ogs_assert_if_reached()`,
causing the AMF process to terminate. This allowed malformed HTTP/2
multipart requests to trigger a denial-of-service condition.
This patch replaces the assertion-based failure with graceful error
handling:
- Introduce `multipart_part_data_t` and explicit parser state tracking.
- Add `parse_error` flag to propagate parsing failures.
- Validate the result of `multipart_parser_execute()`.
- Reject malformed multipart payloads instead of aborting.
- Replace fatal assertions with error handling and proper cleanup.
- Add centralized cleanup via `multipart_parser_data_free()`.
As a result, malformed or oversized multipart bodies are now rejected
with an error, while the AMF process remains operational.
Issues: #4290
Two issues (#4277, #4278) reported crashes caused by malformed or
unexpected inputs.
In the TLV parser, several ogs_assert() checks could be triggered by
malformed TLV blocks, resulting in process termination. These checks
are replaced with proper error handling: the parser now logs the error,
limits hexdump size, frees allocated TLVs, and returns NULL instead of
aborting.
In the SMF S5-C Create Session Request handler, additional validation
is introduced for Bearer Context handling. The implementation now
rejects requests containing multiple Bearer Contexts, missing mandatory
fields (EBI or Bearer QoS), duplicate EBI values, or invalid TEID/IP
information. Several ogs_assert() calls that could be triggered by
malformed messages are also replaced with explicit error handling.
These changes prevent crashes caused by malformed TLV blocks or
unexpected Bearer Context structures and ensure the SMF rejects such
requests gracefully.
Issues: #4277, #4278
Several users reported intermittent AMF crashes when SM Context Update
procedures overlap with NG context release or a new Registration
procedure. In these situations the RAN-UE associated with a session may
change before the asynchronous SBI response arrives.
Typical trigger scenarios include:
* UEContextReleaseRequest followed by a new Registration Request
* PDU Session Update overlapping with UE deactivation or handover
* Registration Request arriving while a previous Service Request is
still being processed
In these cases the AMF may send an Update SM Context request to the SMF
while the NG context is being released or replaced. When the asynchronous
SBI response arrives later, the AMF uses the session's current ran_ue
pointer. However, that pointer may already have been switched to a new
RAN-UE or cleared due to the release procedure.
As a result, the AMF may reference the wrong RAN-UE context or an
inconsistent state, eventually triggering an assertion such as:
amf_nsmf_pdusession_handle_update_sm_context:
Assertion `ran_ue->deactivation.group' failed
The root cause is that SBI client transactions do not preserve the
RAN-UE association at the time the request was sent. Because SBI
operations are asynchronous, the session context may change before the
response is processed.
This patch introduces a generic mechanism to attach user-defined context
to an SBI transaction:
- Add `user_data` and `user_data_free` to `ogs_sbi_xact_t`
- Allow NF-specific code to store per-transaction context
- Ensure the memory is released automatically when the transaction
is removed
The AMF now stores a snapshot of the RAN-UE ID in the SBI transaction
when sending an Update SM Context request. When the SBI response is
processed, the AMF retrieves the RAN-UE using this snapshot instead of
the session's current ran_ue pointer. This guarantees that the response
is associated with the correct RAN context even if the session state has
changed in the meantime.
This approach avoids race conditions between asynchronous SBI responses
and NG context lifecycle events, preventing the AMF from accessing an
incorrect or partially released RAN-UE context.
Reported-by:
multiple users on v2.7.6 environments
Issues: #4174, #4274
Replace assertion-based checks on network-derived values with
validation and proper GTP error handling.
- Handle ogs_gtp1_gsn_addr_to_ip() and ogs_gtp1_eua_to_ip() failures
without aborting SMF
- Fix incorrect log message for End User Address failure
- Handle PFCP outer_header_creation failure gracefully instead of assert
Prevents SMF crash triggered by malformed Gn CreatePDPContextRequest.
Issues: #4285
Replace fatal asserts in mme_s11_handle_create_session_response() with
validation and a unified failure path.
- Reject malformed/invalid IEs (Cause, TEID, PAA, AMBR, Bearer QoS)
instead of aborting the MME process
- Fix Bearer QoS length handling: treat mismatch as invalid IE and fail
gracefully
- Consolidate error handling via mme_s11_create_session_fail() and goto fail
This prevents remote crashes triggered by malformed GTPv2-C
CreateSessionResponse messages on S11.
Issues: #4284
The MME trusted the PDN Address Allocation (PAA) IE length from
CreateSessionResponse (S11) without proper bounds validation.
An attacker-controlled or malicious SGW could forge an oversized
PAA IE length (e.g., 200 bytes), causing the MME to copy the
payload into sess->paa using the attacker-supplied length.
This leads to memory corruption and a SIGSEGV crash (remote DoS).
This patch adds explicit length validation for the PAA IE:
- Rejects PAA lengths smaller than OGS_PAA_IPV4_LEN
- Rejects PAA lengths larger than OGS_PAA_IPV4V6_LEN
- Sets cause to OGS_GTP2_CAUSE_INVALID_LENGTH on malformed IE
As a result, malformed or oversized PAA IEs are safely rejected,
and the MME no longer crashes.
Issues: #4283
Replace ogs_assert() checks in ogs_gtp2_parse_tft() with explicit
runtime length validation to prevent process abort on malformed
TFT/TAD IEs.
Previously, insufficient length checks could trigger assertion
failures when parsing crafted BearerResourceCommand messages with
invalid packet filter content lengths. This allowed a malformed
TFT/TAD IE to cause a crash (SIGABRT) in SMF.
This patch:
- Adds explicit boundary checks before every field access
- Validates that content.length does not exceed remaining IE length
- Protects component array bounds during parsing
- Logs errors and returns current parsed size instead of aborting
The function now gracefully rejects malformed input without
terminating the process, preventing potential denial-of-service
conditions on S5-C interface.
No functional change for valid messages.
Issues: #4281
Replace strtoll() with strtoull() in ogs_uint64_from_string() and
remove fatal abort on conversion errors to prevent remote crash via
malformed SupportedFeatures/requester-features values.
The previous implementation could trigger OGS_LOG_FATAL and
ogs_assert_if_reached() when strtoll() detected ERANGE, allowing a
malicious or buggy peer to cause a denial-of-service by sending an
overly large hexadecimal value.
Changes:
- Use strtoull() for proper unsigned parsing.
- Add strict endptr validation (no digits, trailing garbage).
- Handle ERANGE and invalid inputs gracefully without abort().
- Normalize errno handling: success paths set errno=0.
- In ogs_sbi_parse_request(), reject invalid requester-features
(EINVAL/ERANGE) and return OGS_ERROR instead of proceeding.
Empty string is treated as valid (0), consistent with 3GPP
SupportedFeatures pattern ('^[A-Fa-f0-9]*$').
This ensures malformed requester-features values no longer crash
NRF and are properly rejected during SBI request parsing.
Issues: #4263
Validate the PDN Address Allocation (PAA) IE length in
sgwc_s5c_handle_create_session_response() before copying it
into sess->paa.
Previously, the code directly performed:
memcpy(&sess->paa, rsp->pdn_address_allocation.data,
rsp->pdn_address_allocation.len);
without validating the IE length. A malicious or malformed
CreateSessionResponse (S5-C) from a PGW with an oversized
PAA IE length could trigger a buffer overflow and crash
SGW-C (remote DoS).
This patch adds explicit length validation and rejects
responses with invalid PAA IE length, returning
OGS_GTP2_CAUSE_INVALID_LENGTH instead of proceeding.
Issue originally reported in #4282.
An initial fix was submitted in PR #4330 but was reverted
in #4331 due to issues. This commit provides a corrected
and validated implementation.
Fixes: #4282
When traffic from UE is destined to an other UE on the same UPF, the packet shouldn't be sent to the TUN interface, but should be re-encapsulated and forwarded via the destination UE's GTP-U tunnel.
Before, in the gtp-path.c, there was a TODO placeholder for this. Logic:
- Look up the destination UE session by inner packet dest IP
- Find a matching downlink PDR with FAR
- Fall back to lowest precedence PDR
- URR accounting
- Buffering and dowlink data reporting
Additionally, the multi-ue-test was extended with each UE pinging the next UE.
Signed-off-by: akos011221 <orbanakos2001@gmail.com>
open5gs doesn't support the "SMS in MME" (3GPP TS 23.272 Annex C) yet,
so better announce that we support SGs interface than giving no
information the the HSS.
Add validation for PDU Session Identity (PSI) when handling
SMF Registration resource requests in UDM.
Previously, the PSI value extracted from the SBI resource
path was used directly to locate the session context.
If the value corresponded to
OGS_NAS_PDU_SESSION_IDENTITY_UNASSIGNED (0), the lookup
would proceed with an invalid identifier.
This could lead to inconsistent session handling and
unexpected error paths.
This patch introduces an explicit validation step:
- Detect PSI == OGS_NAS_PDU_SESSION_IDENTITY_UNASSIGNED
- Log an error with the received PSI value
- Return HTTP 400 Bad Request via SBI error response
- Abort further processing of the request
This ensures that only valid, assigned PSI values are
processed and improves protocol compliance and robustness
against malformed SBI requests.
Issues: #4255
Replace hard assertions with boundary checks when parsing
SMF and AMF information from NRF NFProfile.
Previously, multiple ogs_assert() conditions assumed that
slice, TAI, TAI range, and GUAMI counts would always remain
within static limits (e.g., OGS_MAX_NUM_OF_SLICE,
OGS_MAX_NUM_OF_TAI, OGS_MAX_NUM_OF_SERVED_GUAMI).
If NRF provided NFProfile data exceeding these limits,
the process could terminate due to assertion failure,
resulting in service instability.
This patch introduces explicit overflow validation:
- SMF
- Slice list overflow protection
- NR TAI list overflow protection
- NR TAI range TAC index overflow protection
- AMF
- Served GUAMI overflow protection
- NR TAI range overflow protection
When limits are exceeded, an error log is generated and
parsing of the affected list is stopped gracefully,
preventing crash while preserving existing data.
This improves robustness against malformed or excessive
NFProfile inputs from NRF or peer NFs.
Issues: #4249, #4250, #4252
Fix a crash triggered by SCP NFProfile registrations that do not
provide any usable endpoint information.
Previously, ogs_sbi_client_associate() asserted that a client must
exist after association. However, malformed or incomplete NFProfiles
(e.g., scpInfo containing only scpDomainInfoList without scpPorts or
instance/service endpoints) could bypass endpoint validation and
result in no client being created.
This led to an assertion failure in:
ogs_sbi_client_associate()
-> ogs_assert(client)
Root causes addressed:
1. Association safety
- Remove hard assertion on missing instance-level client.
- Perform association only when a client exists.
- Improve logging for missing instance/service endpoints.
2. Endpoint validation refactor
- Move endpoint validation after client association.
- Introduce nf_instance_has_usable_client() helper to verify:
* Instance-level client, or
* Any service-level client.
3. Registration rejection
- Reject NFProfile registrations that lack usable endpoints
with HTTP 400 instead of allowing inconsistent state.
4. SCP info handling
- Treat domain-only SCP registrations as valid nf_info inputs
when num_of_domain is present.
Impact:
- Prevents assertion crashes in NRF triggered by malformed SCP
registrations.
- Ensures NF instances are accepted only when at least one usable
endpoint is available.
- Improves diagnostic logging for operator troubleshooting.
Tested with:
- SCP registration containing only scpDomainInfoList
- Registrations with instance-level endpoints
- Registrations with service-level endpoints
Issues: #4243, #4248
Enforce a 256MB maximum payload size in
on_data_chunk_recv() to prevent excessive memory allocation
from large HTTP/2 DATA frames.
Requests exceeding the limit are rejected with HTTP 413,
and allocation failures return HTTP 503.
This mitigates large payload DoS conditions.
Issues: #4244, #4247
When an NF loses heartbeat and enters re-registration, existing
NRF subscription states tied to the previous NF instance remain
both remotely (NRF) and locally (subscription_data pool).
In environments with repeated heartbeat loss or timing races
(e.g., docker-compose deployments), this leads to continuous
re-subscription loops and unbounded growth of
subscription_data entries, eventually exhausting the pool and
triggering assertion failures in ogs_sbi_subscription_data_add().
This patch introduces a pre-registration cleanup mechanism:
- Send DELETE requests for all subscriptions associated with
the NF instance before re-registration.
- Perform asynchronous local cleanup in the unsubscribe
response handler (avoiding use-after-free and double free).
- Add duplicate DELETE guard using subscription flags.
- Improve logging visibility for subscription cleanup flow.
This ensures that stale NRF subscription states are removed
and prevents subscription_data pool exhaustion during
re-registration loops.
Issues: #4207
Problem
When the implicit detach timer expires, the MME may initiate local
UE context removal if no S1 context exists.
In the previous implementation, mme_ue_remove() could be triggered
directly from mme_send_delete_session_or_detach() in this path.
This leads to a structural issue:
- The UE context may be freed while the EMM FSM is still processing
the implicit detach timer event.
- Subsequent FSM operations (state transition, ENTRY/EXIT signals)
may access the freed mme_ue.
- This results in assertion failures or crashes such as:
emm_state_registered: Assertion `mme_ue' failed
Analysis
Implicit detach handling executes within the EMM FSM context.
Immediate UE context removal from this path violates the FSM
lifecycle assumption that the context remains valid until the
event handling and state transition complete.
This creates a use-after-free risk and can also cause double-free
depending on concurrent removal paths.
Solution
Introduce deferred UE context removal via FSM:
1. Add a new flag:
mme_ue->ue_context_will_remove
2. Modify mme_send_delete_session_or_detach():
- If no S1 context exists, do not remove immediately.
- Set ue_context_will_remove = true instead.
3. In implicit detach timer handling:
- Check the flag and select the next state accordingly.
4. Introduce a new FSM state:
emm_state_ue_context_will_remove
- UE context removal is performed safely on ENTRY_SIG.
This ensures:
- UE context is not freed inside the original EMM handler.
- FSM lifecycle is preserved.
- Removal happens after state transition.
Impact
- Prevents crashes caused by use-after-free during implicit detach.
- Avoids double-free scenarios.
- Aligns UE context lifecycle with FSM design.
This change only affects implicit detach paths where S1 context
does not exist and does not alter normal detach procedures.
Fixes: #4298
NFProfile plmn_list returned from NRF overwrites the local serving
PLMN configuration. Reset num_of_serving_plmn_id instead of the
unused nf_instance->num_of_plmn_id to avoid stale accumulation.
Issues: #4207
When bearer contexts are migrated between MME-UE objects during UE
context relocation (OLD UE -> NEW UE), the existing ogs_pool-based
EBI tracking could become inconsistent.
In mme_ue_set_imsi(), bearer->ebi_node was freed from the old UE pool
without reserving the same EBI in the new UE context. This allowed
duplicate allocations and eventually exhausted the EBI pool (5..15),
triggering a fatal assertion in mme_bearer_add().
This patch replaces the pool-node based EBI handling with a bitmap
allocator, which is safe across UE context migration and supports
explicit EBI reservation.
Also update related test cases to match the new allocation order.
Fixes: #4294
Bug:
A double-free scenario in the error handling path:
When ogs_sbi_send_request_with_sepp_discovery failed, it called
ogs_sbi_xact_remove(xact) internally.
The function then returned false to its caller. The caller
(smf_sbi_discover_and_send) also called ogs_sbi_xact_remove(xact)
on failure.
This caused the discovery_option structure to be freed twice,
leading to the valgrind error:
```
==90== Invalid read of size 8
==90== at 0x49AFBB6: ogs_sbi_discovery_option_free (message.c:3633)
==90== by 0x49CC100: ogs_sbi_xact_remove (context.c:2674)
==90== by 0x407DDDC: smf_sbi_discover_and_send (sbi-path.c:392)
```
Fix:
Now the function follows proper resource ownership semantics:
the caller who creates the transaction is responsible for cleanup
when the function fails, making the error handling consistent and
preventing double-free issues.
Added missing cleanup to ogs_sbi_send_request_to_nf_instance and
af_sbi_discover_and_send.
When handling Create Indirect Data Forwarding Tunnel Request,
SGW-C unconditionally sent a PFCP Session Modification Request
with OGS_PFCP_MODIFY_INDIRECT|CREATE.
However, some session contexts do not contain any indirect
DL/UL forwarding tunnel information, which leads to assertion
failures inside PFCP handling.
This patch checks whether a session actually has an indirect
forwarding tunnel before sending the PFCP modification request,
and logs detailed context information otherwise.
This is the same class of issue previously observed with
Delete Indirect Tunnel handling in issue #4073.
Fixes: #4073
Fix an AMF crash when a UE sends a new Registration Request immediately
after UE-initiated Deregistration.
In this scenario, SM Context release and SDM subscription DELETE requests
are triggered during deregistration, but their SBI responses may arrive
later while the AMF is already handling a subsequent Registration Request
(Integrity Protected).
Previously, late SDM_SUBSCRIPTIONS DELETE responses were processed in
unexpected GMM states (registered, authentication, initial-context-setup),
leading to ogs_assert_if_reached() and AMF crashes.
This commit changes the behavior to explicitly ignore late
SDM_SUBSCRIPTIONS DELETE responses in such states, treating them as stale
and non-actionable. Fatal assertions in these paths are replaced with
warnings to prevent crashes caused by valid out-of-order SBI responses.
The fix is covered by a new regression test reproducing issue #4209,
including scenarios with and without active PDU sessions.
Limit authentication retries on repeated synchronization failures.
When the UE reports consecutive authentication failures with
"synchronization failure" cause, AMF and MME now track the failure
count per authentication procedure and send AUTHENTICATION REJECT
after two attempts, instead of retrying indefinitely.
The counter is reset on authentication state entry.
This aligns the behavior with 3GPP authentication procedures and
prevents infinite authentication loops caused by persistent
synchronization failures.
Issues: #4238
Handle BearerResourceFailureIndication arriving after the associated
S11 transaction has already expired.
Look up the associated S11 transaction before committing the S5-C
transaction, and gracefully drop the indication if the S11 transaction
no longer exists, instead of asserting and crashing.
This prevents a possible remote DoS caused by delayed S5-C failure
indications.
Issues: #4268
When handling ModifyBearerResponse in the OI (Operation Indication) path,
SGW-C assumed that the PGW S5U tunnel address was always initialized.
If the Bearer Context was not parsed and ul_tunnel->remote_ip remained
unset, building the S11 CreateSessionResponse could trigger an assertion
failure and crash the SGW-C process.
Add a defensive check in sgwc_s5c_handle_modify_bearer_response() to
validate the UL tunnel remote IP before proceeding, and return a proper
GTP error instead of aborting. Also replace an assertion with graceful
error handling in the SxA session modification response path.
This prevents a remotely triggerable SGW-C crash (DoS) caused by malformed
or incomplete ModifyBearerResponse messages.
Issues: #4257
Avoid aborting on malformed or oversized GTP messages that exhaust the
internal TLV pool.
- Replace ogs_assert() in ogs_tlv_get() with error handling and NULL return
- Detect TLV allocation and parsing failures in ogs_tlv_parse_block()
- Clean up partially parsed TLVs and return failure instead of aborting
- Limit hexdump size to prevent log flooding on malformed input
This prevents a single malformed message from crashing SGW-C/PGW-C/MME
and ensures graceful failure when TLV allocation or parsing fails.
Issues: #4234
SGW-C could be forced to abort when handling a crafted or delayed
S5-C response (Create/Modify/Delete Session) if the associated S11
transaction no longer exists.
The S5-C handler assumed that the corresponding S11 transaction is
always present and unconditionally asserted its existence, leading
to a process abort and denial-of-service.
This change removes the fatal assertion and safely handles the case
where the associated S11 transaction cannot be found by logging an
error and ignoring the response.
Issues: #4226
Prevent SGW-C and SMF from aborting when receiving late or orphan
GTPv2 bearer responses (Create/Update/Delete Bearer).
This change removes fatal assertions on missing UE/session contexts
and instead treats such cases as "Context Not Found" per 3GPP
TS 29.274.
In addition, improve FSM-level UE/session lookup by retrying context
identification using the locally stored TEID when the received TEID
is missing, zero, or no longer valid. This aligns the behavior with
TS 29.274 §5.5.2 and allows graceful handling of late responses after
context cleanup.
Together, these changes ensure that late or orphan GTPv2 responses
never crash SGW-C or SMF and are handled gracefully.
Issues: #4225
Handle late or out-of-order ESM/NAS events more safely by removing
assert-based assumptions on runtime UE/S1 contexts.
Replace fatal assertions with defensive runtime checks in ESM, NAS,
GTP, and S11 paths so that late messages received after bearer/session
or eNB-UE context release do not terminate the MME process.
This allows ongoing GTP/S11 procedures to continue or clean up safely
while gracefully handling missing S1 context, improving robustness
under real-world race conditions.
Issues: #4236
Add explicit error handling for missing EPS Bearer ID and S5/S8 U F-TEID
in Create Session Response processing. Instead of breaking out of the
loop, immediately send an appropriate GTPv2 error response and abort
processing.
Also handle the case where the referenced bearer context does not exist
by returning CONTEXT_NOT_FOUND, and add missing error logs for failed
F-TEID to IP conversion.
These changes prevent silent failures and ensure correct GTP error
signaling toward the MME.
Issues: #4224
Replace ogs_assert() and ogs_fatal() with runtime checks when allocating
UE contexts, transactions, and timers.
Handle pool and timer exhaustion gracefully by logging errors, cleaning
up partially created objects, and returning NULL instead of aborting
the process, improving control-plane robustness under high load or
resource limits.
Issues: #4220, #4221
Do not abort SGW-C when a Downlink Data Notification Ack arrives
after the related bearer or session has already been released.
Replace assert-based assumptions with runtime checks and logging,
and always commit the S11 transaction safely to prevent process
termination on late or malformed ACK messages.
Remove hard assertions in GTPv2 Bearer QoS and Flow QoS parsers and
replace them with defensive length validation. Invalid IEs are now
gracefully rejected by the caller instead of aborting the process.
Update SGW-C and SMF handlers to validate parser results and return
appropriate GTP-C error causes, preventing daemon crashes on malformed
GTPv2 messages.
Issues: #4217
SGW-C could abort when handling malformed GTPv2-C messages where an
F-TEID has neither IPv4 nor IPv6 flags set. In such cases,
ogs_gtp2_f_teid_to_ip() returned an error but the caller asserted on
OGS_OK, causing a process abort.
This change removes assertions on F-TEID and PFCP outer header creation
and replaces them with proper runtime validation and error handling.
Malformed or semantically incorrect messages are now rejected with an
appropriate GTP-C cause instead of crashing the control plane.
For Create Session Request handling, all error paths are unified through
a cleanup path to ensure partially created sessions are removed before
sending an error response, preventing resource leaks.
Issues: #4203
The meaning of pfcp_xact->assoc_xact_id differs depending on whether a PFCP
Session Modification response is related to an Error Indication.
For PFCP DEACTIVATE responses with OGS_PFCP_MODIFY_ERROR_INDICATION set,
assoc_xact_id refers to a bearer context rather than an S11 transaction.
Handle this case explicitly by resolving the bearer and UE context and
processing the session synchronization path accordingly.
For other DEACTIVATE cases, continue to resolve assoc_xact_id as an S11
transaction ID and send an appropriate GTPv2-C error response when possible,
while safely handling missing S11 transactions.
This change avoids incorrect transaction lookups and improves robustness
when handling PFCP Error Indication related DEACTIVATE responses.
When handling PFCP Session Modification responses with the DEACTIVATE flag,
SGWC assumed that a corresponding S11 transaction always existed and enforced
this with an assertion.
In some error paths (e.g. SGWU rejecting a PFCP modification due to missing
mandatory IEs or asynchronous cleanup), the associated S11 transaction may
already be released or may not exist at all. This caused SGWC to crash on
assertion failure.
Replace the assertion with a NULL check and log the condition (including IMSI
and associated transaction ID) when the S11 transaction is missing, while
allowing the PFCP transaction to be committed safely.
This change adds extensive logging across SGW-C GTP and PFCP paths
to identify the root cause of an assertion failure triggered when
building a PFCP Session Modification Request with no PDR/FAR changes.
The assertion was hit when the total number of remove/create/update
PDR/FAR entries was zero, indicating an invalid PFCP modification
state.
To trace where this condition originates, this commit:
- Promotes key debug logs to info level for better visibility
- Adds contextual logs when PFCP Session/Bearer Modification is invoked
from S11, S5-C, and SXA handlers
- Logs PFCP transaction state, modify flags, and bearer lists
- Logs detailed counters before asserting in
sgwc_sxa_build_bearer_to_modify_list()
These logs allow correlating GTP control-plane events with PFCP
modification requests and identifying cases where modification flags
are set but no effective PDR/FAR changes are generated.
A malformed SBI request with `"pduSessionId":0` (UNASSIGNED) or without
`pduSessionId` caused `smf_sess_find_by_psi()` to assert and crash.
This patch adds defensive validation in:
- smf_sess_add_by_sm_context()
- smf_sess_add_by_pdu_session()
If `is_pdu_session_id == false` or `pdu_session_id ==
OGS_NAS_PDU_SESSION_IDENTITY_UNASSIGNED`, log an error and safely discard
the request instead of creating a session.
Issues: #4201
Align full-DNN construction with 3GPP TS 23.003 §9.1.2 by switching the
Operator Identifier format from "5gc.mncXXX.mccYYY.3gppnetwork.org" to
"mncXXX.mccYYY.gprs". Introduce new helper utilities to extract and build
OI (Operator Identifier) from both PLMN-ID and FQDN, and replace the
legacy `ogs_home_network_domain_from_fqdn()` usage in AMF/SMF/PCF paths.
This resolves DNN misalignment in vSMF–hSMF PDU Session Create that
caused interop issues with external 5G core vendors during HR roaming.
Includes updates across AMF/SMF/PCF, unit tests, and supporting helpers.
Issues: #4096
In long-running deployments, a mismatch can occur between SMF’s stored
Gx/Gy/S6b Session-Id and the freeDiameter session table, typically after
peer reconnection, watchdog timeout, or internal cleanup. In such cases
`fd_sess_fromsid_msg()` may return `new != 0`, indicating that the
Diameter stack created a new session instance instead of retrieving the
existing one.
Previously, this condition triggered `ogs_assert(new == 0)` which caused
a fatal crash of the SMF (and potentially SGWC), interrupting normal
operation.
This patch replaces the assertion with a graceful recovery path:
- Log an error indicating that the Diameter session has been lost
- Free the pending request message and stored Session-Id
- Return early to trigger PDU session release handling by the upper layer
- Avoid process termination and maintain service continuity
This significantly improves robustness in long-running and fault-tolerant
deployments with commercial-grade operational requirements.
Issues: #4195
When a CPE (4G router) loses power abruptly without sending a Detach
Request, the ENB-UE context is removed first, causing the implicit
detach process to fail. This leaves sessions active in SMF/UPF/SGWC/SGWU.
Changes:
- Allow mme_send_delete_session_or_detach() to accept NULL enb_ue
- Remove enb_ue assertion in mme_gtp_send_delete_session_request()
- Conditionally set xact->enb_ue_id only when enb_ue is present
- Remove enb_ue assertion in mme_gtp_send_delete_all_sessions()
- Move ENB-UE context check in mme_s11_handle_delete_session_response()
after session cleanup to ensure proper resource release
- Change log level to INFO for Mobile Reachable timer in registered state
This ensures that implicit detach proceeds correctly even when the
ENB-UE context has already been released, allowing proper cleanup of
core network sessions.
Fixes session leak issue reported in GitHub issue #4194
Fix crash triggered by malformed PDU Session Resource Modify / Path Switch /
Handover Request Acknowledge transfers that contain invalid GTP Tunnel parameters
(IPv4/IPv6 flags both zero). Previously, these invalid states propagated to PFCP
rule creation, causing an assertion failure inside
ogs_pfcp_ip_to_outer_header_creation() and terminating SMF.
This patch adds defensive checks across NGAP handling paths and rejects
such requests early via SM-Context Update Error (HTTP 400), ensuring that
SMF continues normal operation for other UEs.
Key changes:
- Validate remote_dl_ip before processing
- Reject when IPv4/IPv6 flags are both zero
- Preserve session state by skipping invalid modifications
Prevents DoS-style SMF crash while maintaining 3GPP-compliant behavior.
Issues: #4193
When CreatePDR/PDI contains an F-TEID IE with length 0, SGWU aborted due to
assertion `pdr->f_teid.ipv4 || pdr->f_teid.ipv6` in ogs_pfcp_handle_create_pdr().
This allowed a malformed PFCP Session Establishment Request to remotely crash SGWU.
This patch adds validation for:
- Zero-length F-TEID IE (return INVALID_LENGTH)
- F-TEID without IPv4/IPv6 flag (return INVALID_F_TEID_ALLOCATION_OPTION)
Instead of asserting and aborting, SGWU now rejects the request gracefully by
returning an appropriate Cause/Offending IE.
Issues: #4182
This patch replaces fatal ogs_assert() calls in PFCP object allocation
(ogs_pfcp_{pdr,far,urr,qer}_find_or_add) with graceful error handling.
Previously, exceeding per-session resource limits (e.g., QER pool overflow
triggered via CreatePDR referencing undeclared QER-ID) would cause a process
abort in open5gs-upfd, leading to a remote denial-of-service condition.
The handler now returns PFCP Cause=NO_RESOURCES_AVAILABLE and properly
rejects malformed or resource-exhausting PFCP Session Establishment requests,
allowing the UPF to continue running without terminating all existing sessions.
Fixes: DoS vulnerability triggered by excessive implicit QER allocation.
Issues: #4181
Replace `ogs_assert(nxt == 0)` with validation and graceful error return
when parsing IPv6 jumbo payload where plen=0 but NextHeader is non-zero.
This prevents open5gs-upfd from aborting when receiving a single malformed
GTP-U IPv6 packet crafted to trigger assertion failure, resulting in a
remote DoS condition.
Malformed packets are now safely dropped and logged instead of terminating
the UPF process.
Issues: #4180
According to TS 29.244, FAR-ID is a mandatory IE in CreatePDR. However,
Open5GS previously accepted a Session Establishment Request containing a
CreatePDR without FAR-ID. When subsequent GTP-U packets matched the PDR,
the user-plane fast path dereferenced a NULL FAR pointer and aborted,
leading to a UPF crash (DoS).
This patch adds mandatory IE validation for FAR-ID in
ogs_pfcp_handle_create_pdr(), returning PFCP cause
MANDATORY_IE_MISSING when FAR-ID is absent.
As a result, malformed CreatePDR is rejected at PFCP control plane
instead of causing fatal assertion in the data path.
Fixes crash in `_gtpv1_u_recv_cb()` and improves robustness.
Issues: #4179
When receiving a PFCP Session Establishment Request containing a CreateURR
with an out-of-range URR-ID (e.g. 65535), UPF attempted to index
sess->urr_acc[] without bounds checking, leading to an assertion failure
and process abort.
This patch validates URR-ID before use and rejects the message gracefully
with an error cause if the value exceeds OGS_MAX_NUM_OF_URR. A clearer
log message is also added to indicate the valid range.
Fixes: assertion failure in upf_sess_urr_acc_timers_setup()
Issues: #4169
According to 3GPP TS 29.272 (5.2.1.1.2), when an Update Location Request
is sent due to an initial attach, the MME shall set the
"Initial-Attach-Indicator" flag in the ULR-Flags IE. This ensures that
the HSS updates the MME identity and prevents ULA rejection with
UNKNOWN_SERVING_NODE when UE moves between MMEs or when GUTI mismatch
occurs.
Commercial MME/HSS implementations (e.g., Cisco StarOS) also set the
Initial-Attach-Indicator flag by default to handle UEs that do not reset
their GUTI when changing networks.
This patch hardcodes the Initial-Attach-Indicator bit for all ULR
messages to align with expected practical behavior and resolve attach
failures caused by HSS identity mismatch.
Issues: #4165
* AMF dynamic PLMNs via APIREST
* add new feature now we can register ues when plmn is deleted
* add documentation for use the API AMF-OAM
* update tutorial 08
* fix memory not freed
fix memory not freed
fix memory not freed
* improve releases ues of plmn
The AK buffer is allocated with OGS_AK_LEN, but it was logged using
OGS_KEY_LEN, causing a stack buffer over-read under Address Sanitizer.
This change corrects the log length to OGS_AK_LEN.
Fixes the ASAN error reported during `volte cx-test`.
Issues: #4177
The previous key downloaded from `download.opensuse.org` was expired
(EXPKEYSIG FE7F42F276CEE0E6), causing `apt update` to fail when following
the Debian quickstart instructions.
This patch replaces the deprecated key URLs with valid signing key
download locations from build.opensuse.org and obs.osmocom.org.
Issues: #4175
A malformed CER containing duplicate Auth-Application-Id AVPs caused
freeDiameter to trigger FD_LOG_FATAL within parserules_check_one_rule(),
reaching an unimplemented branch and calling abort(), which terminated
Open5GS daemons (HSS/MME/PCRF/AAA) using the freeDiameter stack.
To avoid crashing on invalid Diameter messages, remove the call to
ogs_assert_if_reached() inside FD_LOG_FATAL logging path. This allows
Open5GS to gracefully reject malformed messages instead of aborting.
Issues: #4155
UPF could crash when handling PFCP Session Establishment/Update
containing a CreateURR with a malformed Dropped-DL-Traffic-Threshold IE.
Added length validation for Dropped-DL-Traffic-Threshold and
Volume Measurement IEs to prevent buffer misuse and return an
appropriate PFCP cause and offending IE value.
Also removed assertion in IE parsing functions and replaced it with
error logging and validation checks.
Issues: #4154, #4152
When PFCP Session Establishment/Modification includes CreatePDR with F-TEID
(CH=1) whose address family flags (IPv4/IPv6) do not match the UPF's GTP-U
resource configuration for the target DNN (Network Instance), UPF asserted
and crashed in ogs_pfcp_object_teid_hash_set(). This occurred because the
existing logic assumed a matching address family and enforced it via
assert().
This patch replaces the assertions with proper validation and returns an
appropriate PFCP cause (REQUEST_REJECTED) when the address family does not
match, or if local F-TEID generation fails. This prevents UPF from crashing
and allows the SMF to receive a graceful failure response.
Changes:
- ogs_pfcp_object_teid_hash_set() now returns PFCP Cause instead of void
- Validate IPv4/IPv6 compatibility for DNN resource and local GTP-U address
- Replace assert() usage with runtime error handling and logging
- Integrate cause checking in SGWU/UPF N4 handlers for both Session
Establishment and Modification
- Avoids crash and reports REQUEST_REJECTED when mismatch occurs
Tested scenario:
- UPF with IPv4-only DNN resource receiving CH F-TEID with IPv6-only flags
(or vice versa) no longer causes crash.
Issues: #4315
This patch introduces assoc_id[] to ogs_sbi_xact_t and stores a snapshot
of the RAN-UE ID (AMF_ASSOC_RAN_UE_ID) when the AMF sends SBI requests
to SMF/PCF. Since the RAN-NG context may change (e.g., during NG
Context release or RRC re-establishment) before the asynchronous SBI
response arrives, relying on sess->ran_ue_id can lead to incorrect
context resolution. The transaction-level snapshot ensures that AMF
uses the correct RAN-UE when handling SBI responses.
Key changes:
- Added assoc_id[] array to ogs_sbi_xact_t.
- Stored RAN-UE snapshot for SBI Client operations.
- Updated AMF handlers (amf-sm, nsmf-handler, nnssf-handler,
nnrf-handler, sbi-path) to use xact->assoc_id[] instead of
sess->ran_ue_id for SBI Client responses.
- Updated NAMF handlers to continue using sess->ran_ue_id since they
operate in SBI Server mode and have no transaction snapshot.
- Refactored function signatures to pass amf_ue and ran_ue explicitly.
- Added detailed comments to sess->ran_ue_id explaining the distinction
between SBI Client and SBI Server behavior.
- Updated test cases and added the new issues4174 test.
This resolves the race where RAN-UE context changes between SBI request
and response, ensuring correct session processing and eliminating
RAN-UE lookup failures during asynchronous callbacks.
Issues #4174
In case gNB sends a NGSetupRequest with a TAI that AMF does not serve,
AMF would in some cases respond with a NGSetupSuccess instead of
NGSetupFailure.
This is because of a missing check for correct PLMN.
For example, AMF was configured with the following:
PLMN 001-01:
tac: [1000-1100]
PLMN 999-93:
tac: [2000-2200]
gNB sent NGSetupRequest for PLMN 999-93 and with TAC 1050. AMF would
only check the TAC, instead of also PLMN.
When a UE performs TAU followed by a new Attach Request after a failed
Security Mode Command, the MME may crash while handling the subsequent
ESM Information Response. This occurs when multiple ESM sessions already
exist (e.g., default EPS session + PDN connectivity session), and the
internal session state is not properly reset.
In this scenario, the ESM handler incorrectly assumes that only one
session should exist and triggers the assertion:
"There should only be one SESSION"
This patch adds additional protection during the EMM authentication and
security_mode states by:
* Deleting all existing GTP sessions before triggering a new AIR
* Recording the GTP transaction count and validating that no new
transactions were created during cleanup
* Sending AIR only when session release is not pending and the
transaction count remains unchanged
These checks prevent ESM/EMM state inconsistencies and avoid the crash
in esm_handle_information_response().
Fixes: crash in TAU + Security failure + Attach sequence
Issues: #4172
Add explicit length checks for Maximum Bitrate and Guaranteed Bitrate
IEs in Create/Update QER handlers. When the IE length does not match
OGS_PFCP_BITRATE_LEN, return INVALID_LENGTH with the corresponding
offending IE type.
Also update ogs_pfcp_parse_bitrate() to log a detailed error message
and return 0 when the encoded IE length is invalid, instead of asserting.
This prevents crashes caused by malformed PFCP messages and ensures
correct cause/offending IE reporting to the peer.
Issues: #4152
- Added null-check for flow description direction token in ogs_ipfw_compile_rule()
to prevent dereferencing a NULL pointer.
- Replaced assertions with graceful error handling in Create/Update PDR handlers:
* Log failure when ogs_ipfw_compile_rule() returns error.
* Free allocated flow_description and remove the faulty PDR rule, then continue.
- Improved logging for invalid pdi.network_instance:
* Print length and include a hexdump of the invalid field.
Issues: #4151
If a GTPv2-C Create Bearer Response is received with TEID present but the
corresponding SMF session is missing, the SMF could dereference a NULL
session pointer and crash.
This patch adds a guard check for `sess == NULL` before calling
smf_s5c_handle_create_bearer_response(). In such cases, the transaction is
committed and processing stops safely.
This prevents SMF crashes caused by out-of-sync or unexpected S5-C messages.
When a large number of UEs repeatedly attach/detach, the SGWU session
counter may grow unexpectedly and eventually exhaust the sgwu_sess_pool.
Previously, sgwu_sess_add() asserted on a NULL session pointer, causing
a fatal crash.
This patch replaces the assertion with a proper NULL check. If
ogs_pool_id_calloc() fails, an error is logged and sgwu_sess_add()
returns NULL, allowing the caller to handle the failure gracefully.
This prevents SGWU daemon crashes when the session pool is depleted.
Fixes#4149
Each time Prometheus scraper queried the metrics, there was a memory
leak. Depending on the amount of metrics, this could amount to some
5MB/h of memory leakage (in case of a scrape every 10 second).
Compiled with GCC version 15.2.0 found in Ubuntu 25.10.
warning: initializer-string for array of 'unsigned char' truncates NUL
terminator but destination lacks 'nonstring' attribute (17 chars into 16
available) [-Wunterminated-string-initialization]
Compiler outputs an error when compiling against libcurl 8.14.1-2ubuntu1
found in Ubuntu 25.10.
error: call to '_curl_easy_setopt_err_long' declared with attribute
warning: curl_easy_setopt expects a long argument [-Werror=attribute-warning]
When the MME receives an E-RAB Setup Response with failure for the
default bearer, the PDN session remains in MME/SGWC context even
though it was never activated. As a result, when the UE retries
PDN Connectivity Request for the same APN, the MME prints
"APN duplicated [ims]" and rejects the request.
This patch fixes the issue by sending a Delete Session Request
toward SGWC when the default E-RAB setup fails. The failed PDN
session is then removed, allowing the UE to reattempt PDN
connectivity for the same APN.
Added a new regression test (test_issues4141_func) that reproduces
the scenario:
- First PDN Connectivity Request for IMS fails (E-RAB setup failure)
- MME sends Delete Session Request
- Second PDN Connectivity Request for IMS succeeds normally
Issue: #4141
This patch consolidates all TAU Accept and P-TMSI post-check logic into
a new helper function mme_send_tau_accept_and_check_release().
Key updates:
- Added mme_send_tau_accept_and_check_release(enb_ue, mme_ue) in mme-path.c
to send TAU ACCEPT and check P-TMSI update conditionally.
- Moved duplicated post-TAU logic (active_flag==0, P-TMSI unavailable)
from emm-sm.c, sgsap-handler.c, and mme-s11-handler.c into the helper.
- Added fallback handling when tracking_area_update_accept_proc is not set;
defaults to S1AP_ProcedureCode_id_downlinkNASTransport.
- Cleared mme_ue->tracking_area_update_accept_proc after TAU transmission
to prevent reuse in later procedures.
- Unified logging and behavior between NAS, SGS, and S11 paths.
- Updated mme-path.h with new prototype declaration.
This refactor improves consistency across TAU procedures, eliminates
code duplication, and ensures correct post-accept bearer release when
active_flag==0 and P-TMSI has not been updated.
Fixes: #4112, #4113, #4117
Inactive or PDN-disconnecting EPS bearers do not have valid SGW S1U
tunnel information. When s1ap_build_handover_request() attempted to
encode those bearers, ogs_asn_ip_to_BIT_STRING() failed, resulting in
a fatal assertion and MME crash.
This patch skips all non-active EPS bearers (esm_state_inactive or
esm_state_pdn_will_disconnect) when building the E-RAB list for
Handover Request. Active bearers are guaranteed to have valid
SGW S1U TEID/IP, ensuring safe encoding.
- Skip non-active bearers before E-RAB item construction
- Add state logging for debugging and verification
- Prevent "No IPv4 or IPv6" fatal error triggered by invalid TEID/IP
Fixes: #4131
Fix crash when discovery request specifies only DNN for SMF
The previous implementation could dereference a NULL s_nssai pointer
when handling discovery requests that contained only a DNN filter
(without any S-NSSAI). This caused an assertion failure inside
ogs_sbi_check_smf_info_slice(), which expects both arguments to be
non-null.
This patch fixes the issue by iterating over the SMF’s own slice list
and reusing each stored S-NSSAI when evaluating the DNN-only case.
The SMF instance now correctly matches any slice that provides the
requested DNN, avoiding a crash and restoring expected behavior.
The previous PR implemented the correct OR logic for multiple smfInfo
blocks but resulted in code that was harder to read. This commit rewrites
the logic in a simpler and clearer form without changing functionality.
The discovery matcher meant to accept an SMF instance when any advertised
smfInfo satisfied the requested S-NSSAI/DNN/TAI, but the previous logic
returned false as soon as one block missed the filters. That made configs
with multiple info blocks fail with “No SMF Instance”.
Track whether the request actually carries slice/TAI filters and mark the
instance as matched when at least one smfInfo passes them. Other NF types
keep their existing behaviour, while multi-block SMF configs now work as
documented.
Emergency numbers may be configured:
mme:
...
emergency:
dnn: internet.sos
number:
- digits: 110
categories: police
- digits: 112
categories: [ fire, ambulance ]
The categories are: police, ambulance, fire, marine, mountain
They are sent to the UE during attachment. Some UEs require this list
of numbers. When an emergency call is made, one of the given categories
is indicated towards the IMS in the INVITE message.
Allow to configure an emergency APN:
mme:
...
emergency:
dnn: internet.sos
The 'dnn' value specifies the APN name of the bearer to set up, when an
emergency bearer is requested by the UE. This APN must be configured
too.
Note that only authenticated UEs are allowed to establish the emergeny
bearer.
Replace fatal assertions that assumed valid SCTP stream counts with
guarded runtime checks. When a peer (eNB/gNB) advertises an invalid
`max_num_of_ostreams` such that `(max_num_of_ostreams - 1) < 1`, the
code now logs a warning and returns NULL from the add/alloc function
instead of triggering an assertion and crashing the process.
Rationale:
- Malicious or malformed SCTP transport parameters could cause
assertions like `ogs_assert((...->max_num_of_ostreams-1) >= 1)` to
abort the process. This change prevents process-wide crashes (DoS).
- Returning NULL forces callers to handle allocation/add failures
explicitly, enabling graceful recovery (logging, connection cleanup,
error response) instead of hard crashes.
This patch consolidates the TAU handling logic for both
initialUEMessage and uplinkNASTransport cases, ensuring that the
EPS Bearer Context Status (BCS) check is always performed regardless
of active_flag or S1AP procedure type.
Key changes:
- Removed duplicated TAU handling code paths in emm-sm.c.
- Commonized KDF derivation and BCS validation under a single block.
- Introduced mme_ue->tracking_area_update_accept_proc to store
the selected S1AP procedure for TAU ACCEPT transmission.
- When e->s1ap_code == initialUEMessage and active_flag == 1,
TAU ACCEPT is sent via InitialContextSetup; otherwise via
DownlinkNASTransport.
- Applied the stored proc consistently across all handlers:
mme-path.c, mme-s11-handler.c, mme-s6a-handler.c, and sgsap-handler.c.
- Added fallback to DownlinkNASTransport if proc is not set.
- Cleared tracking_area_update_accept_proc after use to avoid reuse.
This ensures consistent TAU behavior for both initialUEMessage and
uplinkNASTransport flows, unified BCS mismatch handling
When a subscription message has no Subscrcond or not supported SubscrCond, open5gs NRF does not return an error message to client. Error message added.
This patch resolves a crash occurring in SGWC during PFCP Session Modification
responses due to missing context validation for bearer/session/UE objects.
Key changes:
- Added null checks and context existence validation for sess, bearer, and UE
in sgwc_sxa_handle_session_modification_response().
- Moved ogs_gtp_xact_commit() earlier in sgwc_s11_handle_delete_bearer_response()
and added null checks to prevent invalid pointer dereference.
- Enhanced debugging logs across S1AP and SGWC components:
- Displayed enb_s1u_teid/target_s1u_teid updates with IMSI and EBI.
- Added IPv4/IPv6 address hexdumps for E-RAB setup, modification, and handover.
- Added logs in SGWC PFCP/S11/S5C paths to trace message flow and PDR/FAR counts.
These improvements make debugging bearer setup and path switch procedures
more transparent and prevent crashes caused by missing or freed contexts.
Previously, TAU procedure validated EPS Bearer Context Status (BCS)
only when active_flag == 0. When active_flag == 1, the MME skipped BCS
validation and sent TAU ACCEPT directly via InitialContextSetup.
This patch unifies BCS validation so both active_flag paths handle
bearer mismatches consistently. It also selects the correct S1AP
procedure (InitialContextSetup or DownlinkNASTransport) depending on
the UE active state.
Changes:
- emm-sm.c / sgsap-handler.c:
* Always check EPS_BEARER_CONTEXT_STATUS_TYPE presence.
* Invoke mme_send_delete_session_or_tau_accept() for both
active_flag=0 and 1.
* Send TAU ACCEPT directly only when BCS is not present.
- mme-path.c:
* Select S1AP procedure in TAU ACCEPT based on active_flag.
- mme-s11-handler.c:
* After Delete Session Response (OGS_GTP_DELETE_SEND_TAU_ACCEPT),
send TAU ACCEPT using proper S1AP procedure by active_flag.
This aligns MME TAU behavior with 3GPP TS 24.301 section 5.3.3.0a,
ensuring consistent BCS synchronization regardless of UE activity.
Instead of predetermined endpoints in the metrics library, each NF can
now set it's own endpoints on which it listens for requests to dump info
(UE/PDU/gNB/eNB).
Remove function pointers to set page/page sizes per info type
(UE/PDU/gNB/eNB info). Instead, call dumpers functions with this
information as function arguments.
When the UE sends a Tracking Area Update (TAU) Request with active_flag=0,
the MME previously sent TAU Accept without verifying the EPS Bearer Context
Status (EBCS). This caused stale bearer sessions to remain in the MME even
if the UE had already released them.
According to 3GPP TS 24.301 §5.5.3.2, the MME should release any bearer
not reported in the UE’s EBCS when active_flag=0. This patch introduces
mme_send_delete_session_or_tau_accept(), which compares the UE’s EBCS bitmask
with the MME session list and deletes any missing default bearer session
before sending TAU Accept.
If no mismatch is found, TAU Accept is sent immediately. The Delete Session
response triggers TAU Accept when deletions are required. This ensures that
the TAU Accept message reflects the UE’s current bearer context accurately.
Also includes:
- Added OGS_GTP_DELETE_SEND_TAU_ACCEPT handling in mme-s11-handler.c
- Simplified EBCS structure (uint16_t value) for bitmask comparison
- Updated TAU-related tests with realistic EBI bitmasks (0x20, 0x60)
This change aligns TAU handling with 3GPP 24.301 and prevents bearer
mismatch issues between UE and EPC during TAU.
Open5GS has a lightweight HTTP server (already used for `/metrics`) embedded in each NF.
New optional JSON endpoints were added:
| NF | Endpoint | Content |
| --- | --- | --- |
| **SMF** | `/pdu-info` | All currently connected UEs + their PDU sessions (IMSI/SUPI, DNN, IPs, S-NSSAI, QoS, state, etc.) |
| **AMF** | `/gnb-info` | All currently connected gNBs and their supported TAs, PLMNs, SCTP info, number of UEs |
| **AMF** | `/ue-info` | All currently connected NR UEs and their info, active gNB, tai, security, slices, am_policy |
| **MME** | `/enb-info` | All currently connected eNBs and their supported TAs, PLMNs, SCTP info, number of UEs |
| **MME** | `/ue-info` | All currently connected LTE UEs and their info, active eNB, tai, pdn info |
They are exposed on the same HTTP port used by Prometheus metrics (default `:9090`).
To reduce processor load when there are a large number of devices, the API includes a pager that limits output.
`/ue-info?page=0&page_size=100`
page in the range 0-n (0 is default),
`page=-1` to avoid paging
`page_size=100` (default and MAX)
Problem
-------
AMF was crashing several times per day when multiple UEs were connecting,
sending data, and disconnecting. The crash occurred in
gmm_state_de_registered() with the following log:
FATAL: Invalid state [2]
FATAL: gmm_state_de_registered: should not be reached.
This was triggered by network-initiated deregistration scenarios that were
not explicitly handled in the FSM, causing the AMF to enter an unexpected
state and abort.
- Added explicit size checks for critical IE fields (PLMNIdentity, TAC,
GTP-TEID, Cell-ID, UE security capability algorithms, etc.) before
memcpy() operations.
- When size mismatch is detected, log an error and return an Error
Indication (or Setup Failure) with appropriate protocol cause
(semantic_error or message_not_compatible_with_receiver_state).
- Introduced s1ap_send_error_indication1(enb_ue_t *enb_ue, ...)
as a helper for cases where ENB UE context is available directly.
s1ap_send_error_indication2(mme_ue_t *mme_ue, ...) now delegates
to the new function, reducing code duplication.
- Replaced ogs_assert() checks with graceful error handling paths
to avoid abnormal process termination.
This improves robustness against malformed or non-compliant NGAP/S1AP
messages and prevents potential AMF/MME crashes.
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.
In some handover scenarios, `sgwc_sxa_build_bearer_to_modify_list()` could
be invoked when there were no bearers to modify. This led to an assertion
failure:
Assertion `num_of_remove_pdr + num_of_remove_far + ...` failed
This patch adds explicit checks on `sess->bearer_list` before building or
sending PFCP Session Modification Requests. If no bearers are present, the
request is skipped and an error is logged with IMSI/APN/TEID context
instead of aborting the process.
Changes include:
- Added `ogs_list_count(&sess->bearer_list)` checks in
`pfcp-path.c`, `s11-handler.c`, `s5c-handler.c`, and `sxa-handler.c`.
- Gracefully skip SMR when bearer list is empty in
Delete Indirect Data Forwarding Tunnel Request handling.
- Log diagnostic information (IMSI, APN, TEIDs) when no bearer is found.
This prevents SGWC from crashing under DEBUG logging and concurrent HO
scenarios, and allows multiple handover sessions to proceed more stably.
When the UE context was removed (e.g. after implicit detach or Delete
Session response), ongoing paging procedures were not finalized. This
caused the MME to skip sending the appropriate paging outcome (e.g.
Downlink Data Notification ACK, Create Bearer Response, Update Bearer
Response, Delete Bearer Response, SGSAP Paging Reject, etc.) depending
on the paging type.
As a result, the SGW or MSC/VLR could continue retransmitting, and the
MME produced spurious "Unknown timer[T3413]" errors.
This patch introduces `MME_UE_REMOVE_WITH_PAGING_FAIL`, which:
- Checks if paging is ongoing before removing the UE context
- Calls `mme_send_after_paging()` to send the correct outcome message
(Unable to page UE or equivalent cause) according to paging type
- Removes the UE context afterwards
This change ensures that all paging procedures are completed with a
proper response as required by 3GPP specifications, improving network
interoperability and eliminating misleading timer errors.
When the AMF receives a DELETE request for the registration API while in
the gmm_state_authentication state, it currently crashes because the
HTTP method is not handled. This appears to be a race condition.
To fix this, explicitly handle OGS_SBI_HTTP_METHOD_DELETE by ignoring the
message and logging an error, similar to the handling of other
unexpected SBI messages.
When the AMF receives a PATCH request for the registration API while in
the gmm_state_authentication state, it currently crashes because the
HTTP method is not handled. This appears to be a race condition.
To fix this, explicitly handle OGS_SBI_HTTP_METHOD_PATCH by ignoring the
message and logging an error, similar to the handling of other
unexpected SBI messages.
- Use ogs_pool_id_calloc() / ogs_pool_id_free() instead of ogs_pool_alloc() / ogs_pool_free()
to assign stable pool IDs to connection_t and ogs_sbi_session_t.
- Pass pool ID to ogs_timer_add() instead of raw pointer.
- In connection_timer_expired() and session_timer_expired(), resolve object via
ogs_pool_find_by_id() and safely return if the object has already been freed.
- Add safety checks and error logs for invalid IDs and missing objects.
This prevents use-after-free or double-free crashes when timer callbacks
are triggered after the object has been freed under heavy load.
Previously, the code asserted the existence of a bearer when handling
Create Indirect Data Forwarding Tunnel Request. If the bearer was not
found, this caused a crash.
This patch adds a null check for the bearer. If no bearer is found,
it now logs an error and sends a GTP error response with
CAUSE_CONTEXT_NOT_FOUND, then returns gracefully.
Previously, sgwc_bearer_add() and sgwc_tunnel_add() relied on ogs_assert()
for allocation failures (bearer, tunnel, PDR, FAR). Under heavy handover
(ViLTE ping-pong HO) conditions, pool exhaustion could trigger assertions
and crash the SGW-C.
This patch:
- Adds NULL checks for ogs_pool_id_calloc() in bearer/tunnel creation
- Adds NULL checks for ogs_pfcp_pdr_add() and ogs_pfcp_far_add()
- Cleans up partially created objects on failure
- Returns System Failure for S11 CIDFT requests if tunnel creation fails
- Adds NULL checks before removing PDR/FAR in sgwc_tunnel_remove()
- Fixes log message for PDR allocation failure
These changes improve stability during repeated HO scenarios by preventing
assertion crashes when resource pools are exhausted.
During integration tests with a third-party SCP, SMF crashed after
processing the UDM response to a PUT request during UE attachment.
This issue was traced to a missing NULL-check on the `stream` pointer
inside smf_state_operational().
Previously, the code asserted `stream` unconditionally when sending
the HTTP response or PDU session created data. If the SBI stream had
already been removed, the assertion failed, causing SMF to abort.
This patch adds a NULL-check for `stream`. When `stream` is NULL,
an error log is printed instead of asserting. This prevents SMF from
crashing and allows it to continue processing.
Tested with:
- Open5GS v2.7.6-21-g0516e01
- SCP from another vendor (crash reproduced and fixed)
- Open5GS SCP (no crash observed)
Fixes: smf_state_operational() assertion failure at smf-sm.c:1075
Answer ALERT-REQUEST with either ALERT-ACK or ALERT-REJECT.
This commit leaves unimplemented (to be implemented in the future)
the part regarding setting of internal NEAF flag for UE inside MME
and then triggering SGsAP-UE-ACTIVITY-INDICATION towards VLR.
See 3GPP TS 23.272 and 3GPP TS 29.118 (grep for "Alert" and "Activity")
for further information.
PFCP PDR precedence is a uint32_t. In Open5GS the default
OGS_PFCP_DEFAULT_PDR_PRECEDENCE is 65535. The previous assert enforced
(0,255), which is incorrect and causes valid configurations to abort.
Remove the assert and pass the precedence through as-is.
Fixes assertion failures seen in TC_pdu_sess_modification in
osmo-ttcn3-hacks.
The older version of the code was wrong (or at least not exactly
correct) in many (corner) cases.
* Split the parsing of Packet Filter List into its own helper function
to simplify the code
* Improve error logging to provide more info on which QoS rule failed.
* Add some extra logic checking match between 'Length of QoS rule' and
existance of m+1 and m+2 bytes.
* Correct logic checking expected/unexpected presence of m+1 and m+2
octets based on Rule Operation Code according to specs.
Home-Routed roaming: during Xn/N2 handover the source gNB may forward
remaining DL data to the core using UL PDU Session Information (PSC).
On the V-UPF the PSC was lost on the indirect path because OHR+OHC
removed the incoming GTP-U header (and its extensions) and we did not
recreate PSC when no QER/QFI was provisioned by the V-SMF.
This change makes the V-UPF rebuild a DL PSC for the target gNB even
when QER is absent, limited to the Access->Access indirect path
(source gNB -> V-UPF -> target gNB).
Why this is needed in HR:
- In HR deployments the V-SMF typically does not provision QER/QFI for
the temporary indirect path. Without recreating PSC from recvhdr, the
extension header disappears after OHR+OHC and the target gNB cannot
see the QFI during handover buffering/forwarding.
Previously, Outer Header Removal was set according to PDU session type.
However, outer header IP version is independent of inner packet IP version or
PDU session type. It typically depends on UPF and gNB configuration. Set it to
GTP-U/UDP/IP to handle both IPv4 and IPv6 cases, according to TS 29.244, Table
8.2.64-1, Note 4: "The CP function shall use this value to instruct UP function
to remove the GTP-U/UDP/IP header regardless it is IPv4 or IPv6."
No changes at UPF are necessary because it already ignores Outer Header Removal
Description type and Kernel correctly decapsulates the outer IP header at
socket level.
This change moves the call to fd_msg_new_answer_from_req so that the answer
header is created immediately after the incoming request is received,
ensuring that the ans pointer is initialized before any message‐specific
allocations or parsing take place.
This refactoring guarantees that the answer message is set up once and early,
which improves readability and ensures that proper cleanup can occur
without repeated steps.
Refer to:
- Issues #4012
- Pull Request #4034
- Commit f23d7a5
Add robust error checks and logging to MME, SMF, PCRF, and HSS
Diameter callback functions. Prevent assertion failures by
handling unexpected or late messages gracefully.
Instead of aborting the AMF when an SM context release is requested during the
security-mode state, log an error and allow the system to continue operating.
This avoids a fatal assertion failure and improves overall availability. The
error message "Invalid state transition: cannot release SM Context during
security-mode state" provides a clear debug trace for issue #4012.
This change revises the existing ogs_addaddrinfo() function to handle
partial failures without aborting the process, ensure proper cleanup
of any nodes allocated before an error, and emit more informative logs
(including getaddrinfo() errors and situations where no usable addresses
are returned).
By introducing “tail” and “first_new” pointers, new entries can be appended
to an existing list and safely detached if memory allocation fails mid‐stream.
On top of that, a new helper API, ogs_sockaddr_from_ip_or_fqdn(), was added.
It automatically detects whether its input is a numeric IPv4/IPv6 literal
or a hostname (using AI_NUMERICHOST when appropriate), then delegates
resolution to ogs_addaddrinfo().
Errors are logged at the error level but do not trigger a fatal exit,
and any partial lists are cleaned up before returning.
Finally, the SMF configuration parser in context.c was updated to use
this new API for “p-cscf” entries, allowing both raw IP addresses
and DNS names in smf.yaml.
Corresponding adjustments were made in context.h (to change the p_cscf
and p_cscf6 arrays to mutable char pointers) and in the cleanup routine
smf_context_final() to free any dynamically allocated strings.
Together, these improvements eliminate duplicate parsing logic,
streamline configuration handling, and increase the overall resilience
of address resolution across Open5GS.
This change revises the existing ogs_addaddrinfo() function to handle
partial failures without aborting the process, ensure proper cleanup
of any nodes allocated before an error, and emit more informative logs
(including getaddrinfo() errors and situations where no usable addresses
are returned).
By introducing “tail” and “first_new” pointers, new entries can be appended
to an existing list and safely detached if memory allocation fails mid‐stream.
On top of that, a new helper API, ogs_sockaddr_from_ip_or_fqdn(), was added.
It automatically detects whether its input is a numeric IPv4/IPv6 literal
or a hostname (using AI_NUMERICHOST when appropriate), then delegates
resolution to ogs_addaddrinfo().
Errors are logged at the error level but do not trigger a fatal exit,
and any partial lists are cleaned up before returning.
Finally, the SMF configuration parser in context.c was updated to use
this new API for “p-cscf” entries, allowing both raw IP addresses
and DNS names in smf.yaml.
Corresponding adjustments were made in context.h (to change the p_cscf
and p_cscf6 arrays to mutable char pointers) and in the cleanup routine
smf_context_final() to free any dynamically allocated strings.
Together, these improvements eliminate duplicate parsing logic,
streamline configuration handling, and increase the overall resilience
of address resolution across Open5GS.
This commit fixes compilation errors in the SMF GSM state handlers
by declaring and initializing the n2smbuf variable at the top of
both smf_gsm_state_operational and smf_gsm_state_wait_pfcp_deletion,
and removes the redundant type specifiers from the switch‐case assignments.
Added a handler to catch invalid NAMF_COMM API messages
and prevent assertion failures, and upgraded related SBI log statements
from warnings to errors.
This update adds a comprehensive description of the Home Routed Roaming
functionality, enhances the architecture section and message
flow diagrams to illustrate the new routing process, and provides
clear configuration examples and command‑line snippets to assist
users with setup.
This commit adds Xn and N2 handover procedures to the Home-Routed Roaming code.
Direct forwarding is now fully operational.
Indirect forwarding for N2 handovers is not yet supported.
To preserve the GTP-U header and extension header (even without QER)
along the source gNB -> V-UPF -> target gNB path, future work will create
PDRs without Outer Header Removal IE and FARs without Outer Header Creation IE
and implement the necessary UPF logic.
If gsm_build_pdu_session_establishment_accept() fails due to invalid PCO,
the SMF previously hit an assertion and crashed. This patch adds a proper
error check and transitions to the reject state to prevent the crash.
This was originally reported in issue #3969.
A missing error handling path in 'smf_gsm_state_wait_pfcp_establishment'
led to an assertion failure.
Problem:
During inter-eNB/RAN handover scenarios, such as S1/N2 handover followed by X2/Xn handover cancellation,
the UE context may end up partially moved or duplicated across multiple eNBs. If the handover
is canceled by the target eNB and followed by subsequent UE Context Release or PathSwitchRequest
procedures, the MME can crash due to inconsistent context state. Specifically, when deassociating
the mme_ue <-> enb_ue (or amf_ue <-> ran_ue) pair, the code unconditionally resets the association
fields (`mme_ue->enb_ue_id`, `enb_ue->mme_ue_id`, etc.), even if they no longer reflect an actual
association due to the earlier handover cancellation.
Root Cause:
The MME or AMF state machine incorrectly assumes that the associated context IDs are still valid
and proceeds to unlink the context. When the PathSwitchRequest arrives after the UE context has
been (partially or fully) released, the assertion `enb_ue != NULL` or the mismatch in expected ID
(e.g., `mme_ue->enb_ue_id != enb_ue->id`) leads to a crash.
Solution:
This patch introduces stricter association validation before unlinking UE contexts. Specifically:
- The unlinking functions such as `enb_ue_unlink()` and `amf_ue_deassociate()` were replaced with
more explicit versions: `enb_ue_deassociate_mme_ue()` and `amf_ue_deassociate_ran_ue()`, which
compare the current context ID with the expected one.
- If the ID mismatch is detected, the deassociation is skipped and a detailed error is logged
(rather than crashing with an assertion).
- This approach prevents crashes during handover cancellation cases and avoids incorrectly
cleaning up a context that is already associated with a new peer.
Additionally:
- The same pattern was applied consistently across MME and AMF modules including:
- `s1ap-handler.c`, `mme-context.c`, `mme-s11-handler.c`, `mme-gtp-path.c`
- `ngap-handler.c`, `nsmf-handler.c`, `sbi-path.c`
- All previously direct field resets (`xxx_ue->xxx_ue_id = OGS_INVALID_POOL_ID`) are now guarded
with validation logic.
- Logging was improved to aid in debugging unexpected deassociation cases.
This change improves robustness of the MME/AMF against abnormal handover procedures and
ensures graceful handling of late context release requests or race conditions during
handover cancel and re-establishment.
Fixes: assertion failure in `sgw_ue_check_if_relocated()` during PathSwitchRequest
Add a check to ensure only IPv4, IPv6, or IPv4v6 PDN types are allowed.
For any other (unknown) PDN type, send a PDN Connectivity Reject with cause
Unknown PDN Type instead of proceeding to a fatal assertion.
This prevents the MME from crashing when it receives a malformed NAS message.
In certain race conditions, the AMF could receive an SBI response
after the RAN UE context has already been removed.
The ran_ue_find_by_id assertions in
both amf_npcf_am_policy_control_build_create and
amf_nsmf_pdusession_build_create_sm_context would
trigger a fatal abort.
This change removes those assertions so that late SBI client events are
safely ignored and do not crash the AMF.
During PDU Session release, under memory pressure or upon receiving
an RST_STREAM, the SMF could still attempt to process an already-closed
HTTP/2 stream. This led to a fatal assert(stream) in smf_state_operational(),
terminating the entire SMF process even though the error affected
only a single UE context.
This commit adds a null check for the stream before sending the HTTP status.
If the stream has already been removed, SMF now logs an error instead of
asserting.
Previously, if the AMF received an smf-select-data response (or related SBI
messages) from the NUDM-SDM after the UE context had been released, the GMM
state machine would hit an unhandled event and abort with a fatal assertion.
This commit adds a new case for OGS_SBI_SERVICE_NAME_NUDM_SDM
in gmm_state_exception(), explicitly ignoring SBI messages for AM_DATA,
SMF_SELECT_DATA, UE_CONTEXT_IN_SMF_DATA, and SDM_SUBSCRIPTIONS
(with a warning log).
Any truly unexpected resource names now emit an error log instead
of triggering assert_if_reached. As a result, the AMF will safely drop late
NUDM-SDM responses without crashing.
Previously, malformed S-NSSAI parameters could trigger a fatal assertion in
amf_update_allowed_nssai when the UE had zero slices in its subscription
database. This patch introduces an explicit check for amf_ue->num_of_slice == 0,
logs a clear error message including the UE’s SUPI, and returns false to
reject the registration.
The removed assertion prevents AMF crashes and ensures
that other UEs continue to be served normally.
Previously, malformed Protocol Configuration Options (PCO) data would trigger
ogs_assert failures in both the generic parser and SMF build routines,
causing the SMF process to abort unconditionally.
This commit replaces those fatal assertions with conditional checks:
In ogs_pco_parse(), switch from ogs_assert(size == data_len) to
ogs_expect(size == data_len), allowing the function to return gracefully.
In SMF's PCO build (smf_pco_build) and all downstream build paths
(including GN, GSM, S5C modules), replace ogs_assert(pco_len > 0)
with explicit if (pco_len <= 0) checks that:
Ensure that malformed or incomplete PCOs no longer crash the process,
but instead are handled cleanly so the network function can continue operating.
When SM Context creation fails (e.g. 504 from SMF) the AMF continued
to build and send a NAS downlink message by dynamically looking up
the AMF UE context from ran_ue->amf_ue_id inside ngap_build_downlink_nas_transport().
If ran_ue_deassociate() had already removed that mapping, the lookup
would return NULL, triggering a fatal assertion and crashing the AMF.
This patch changes:
1. nas_5gs_send_to_downlink_nas_transport() and
ngap_build_downlink_nas_transport() signatures to accept an
explicit amf_ue_t * parameter alongside ran_ue_t *.
2. All calls to nas_5gs_send_to_downlink_nas_transport() to pass
the correct amf_ue pointer (from sess->amf_ue_id).
3. Removal of the dynamic lookup and fatal assertion in
ngap_build_downlink_nas_transport(), replacing it with
ogs_assert(amf_ue) on the passed-in context.
By carrying the valid AMF UE context through the call chain, we
ensure that downlink NAS transport always has a correct pointer,
even when the ran_ue-to-amf_ue mapping has been cleared. This
prevents invalid internal state transitions and eliminates the
ngap_build_downlink_nas_transport() crash when handling SMF failures.
SM context release in initial‐context‐setup should not abort the AMF.
Use ogs_error instead of ogs_assert_if_reached to log
the invalid state transition and maintain process availability.
Any unexpected HTTP methods or resource names generate an error
and an assertion, ensuring that truly invalid cases are caught.
By adding these checks and early exits, we avoid fatal assertion failures
in scenarios where the AMF’s state machine would otherwise have no matching
transition for a late SBI callback.
In upf_sess_add, replace the unconditional assertion on sess with a check
that detects when the session pool is exhausted. If allocation fails,
log an error message (“Maximum number of Session reached”) and
return NULL instead of aborting the process.
This change prevents the UPF from crashing when the PFCP session limit (4096) is
exceeded and allows it to reject additional session establishment requests
cleanly.
In lib/sbi/message.c parse_multipart(), http->content may be NULL.
This occurs on empty-body multipart POSTs and causes a segfault.
Add guard to check http->content, log an error, and return OGS_ERROR.
In state_operational, guard against dispatching to NF instance FSMs whose
state has been reset to zero by ogs_fsm_fini() in event_termination(). Drop any
incoming SBI events for those instances and log an error, preventing assertion
failures when late HTTP callbacks arrive after an asynchronous SIGTERM shutdown.
In the previous implementation, the AMF would send a Partial-handover error
indication whenever it encountered a session not found in the subscriber DB,
even if valid sessions remained. This resulted in unexpected error responses
during NG handover.
To resolve this, we record the initial SMF transaction count before iterating
through the UE session list. Sessions without a valid SMF context now produce
a warning and are skipped, while continuing to send Handover Notify messages
for provisioned sessions. After processing, we compare the SMF transaction
count to the initial value. If no valid sessions were handled, we send a
Partial-handover error indication.
With this change, unprovisioned sessions no longer trigger a premature error
indication, allowing valid PDU sessions to complete NG handover successfully.
In lib/sbi/client.c, the conditional compilation for
CURLMOPT_MAX_CONCURRENT_STREAMS was using #ifdef, which does not
ensure the option is set when the symbol is undefined.
Replace the check with #if CURL_AT_LEAST_VERSION(7,67,0) so that the
client applies the max concurrent streams setting on supported
libcurl versions. This fixes pool.event always showing the default
value and enables dynamic adjustment according to pool.stream.
SMF constructs up2cp FAR's outer_header_creation with |ogs_gtp_self()->gtpu_ip|
as DST IP address. Therefore, set |ogs_gtp_self()->gtpu_ip| to GTPU advertise
address. If advertise addr is not set, fall back to socket address as usual.
According to 3GPP TS 29.272 Annex A, when the HSS/UDM responds with
DIAMETER_ERROR_USER_UNKNOWN (5001), the MME/AMF should respond to the UE with
NAS EMM cause #8 (EPS services and non-EPS services not allowed), rather than
cause #11 (PLMN not allowed).
Previously, Open5GS returned cause #11 by default. However, this behavior is
problematic for private LTE environments where multiple operators may use the
same PLMN (e.g., 999/99 as per ITU-T E.212). In such cases, a UE rejected
with cause #11 will add the PLMN to its Forbidden PLMN list (FPLMN), causing
the device to avoid that PLMN for an extended period—even if another
compatible private network using the same PLMN exists.
This patch restores compliance with TS 29.272 by changing the default mapping
from cause #11 to cause #8 in both the 4G MME (emm_cause_from_diameter) and
5G AMF (gmm_cause_from_sbi) when handling unknown subscriber cases.
This ensures:
- Standard-conformant behavior across networks
- Better UE behavior in roaming or private LTE scenarios
- Avoids unnecessary FPLMN blacklisting in UE
Reference Issues:
- #263
- #1281
- #1332
Prevent crashes when UE context is missing in AMF and MME by replacing direct
assertions with conditional checks and error logging.
Removed unconditional ogs_assert(ran_ue) in AMF's GMM handlers and
ogs_assert(enb_ue) in MME's EMM handlers.
Now, if the UE context lookup returns NULL, log an error (including SUPI/IMSI,
NAS message type, and IDs), dump the NAS packet in hex for debugging,
and exit the handler gracefully instead of aborting.
Fix missing N2 signaling when tunnel information is unchanged,
causing AMF crash on repeated PathSwitchRequest
When a second PathSwitchRequest arrives without any tunnel changes,
the handler previously returned HTTP 204 No Content and omitted N2 information.
This led to a fatal assertion in the AMF SM context, since it expected
to receive updated N2 data even when the tunnel remained the same.
This patch modifies ngap_handle_path_switch_request_transfer to build
and send the N2 SM buffer in the “else” branch.
It calls ngap_build_path_switch_request_ack_transfer to construct
the Path Switch Request Acknowledge N2 message and then delivers it
with smf_sbi_send_sm_context_updated_data_n2smbuf.
A new test case is also added to verify that N2 signaling is correctly
transmitted when tunnel parameters have not changed.
In src/smf/context.c:
- Wrap UPF selection logic in a conditional that checks if pfcp_node
is non-NULL.
- If no UPF is available (pfcp_node == NULL), log an error and assert
that sess->pfcp_node remains NULL, instead of crashing.
- Only call selected_upf_node() and set up the GTP session when a prior UPF
entry exists.
In src/smf/gn-handler.c:
- After invoking smf_sess_select_upf(), verify sess->pfcp_node.
- If no UPF was selected, log an error ("No UPF available for session") and
return OGS_GTP1_CAUSE_SYSTEM_FAILURE instead of asserting.
In src/smf/s5c-handler.c:
- Mirror the same check for sess->pfcp_node after smf_sess_select_upf().
- If no UPF is available, log an error and return
OGS_GTP2_CAUSE_SYSTEM_FAILURE.
- If the selected UPF is not yet PFCP-associated, log a specific error
message and return OGS_GTP2_CAUSE_REMOTE_PEER_NOT_RESPONDING.
These changes ensure that SMF does not abort when no UPF is configured or
associated; instead, it fails the session request with an appropriate GTP cause.
* [AMF] Fix UE context transfer when only NRF is client
If UE context transfer is initiated and the new AMF does not get the
old AMF from NRF or no UE context is retrieved from the old AMF,
we do not want to reject UE registration. Send identity request instead.
Test "transfer-error-case" is added into the commit.
* [tests] Unite tests for UE context transfer
All tests for UE context transfer with different configs are placed
into test folder transfer.
* [tests] Make two binaries for UE context transfer tests
For each test config a different test binary is created.
This commit adds support for processing network-initiated PDU Session
Modification in a home-routed roaming context, following section 4.3.3.3
of the specification.
Previously, Open5GS assumed the _links map contained an array under the key
"items". However, the 3GPP specification (TS29.510 section 4.9.4 and TS29.501
Table 6.1.6.2.25-1) defines this member name as "item".
As a result, when interacting with vendor NRF implementations that use "item",
Open5GS could not find the array and logged "No items", causing JSON errors.
This change updates both serialization and parsing in lib/sbi/custom/links.c:
- In ogs_sbi_links_convertToJSON(), replace the property name "items" with
"item" when building JSON.
- In ogs_sbi_links_parseFromJSON(), retrieve the array under "item" and adjust
the error message to "No item" if the member is missing.
With these corrections, Open5GS will correctly handle NRF responses using "item"
and remain compliant with the indirect communication model defined by 3GPP.
In case AMF is configured for multiple PLMN's, it would send a wrong
GUAMI in the Registration Accept message to the UE, also in other NAS
and SBI messages. Previously, it would only send the first configured
PLMN.
In ipfw2.c errx() would call exit(), aborting the UPF thread on rule parse
errors. Add a macro mapping errx() to ogs_log_message() so errors are logged.
We no longer call exit() and the main loop continues on error.
Prior to this change, `session_write_callback()` unconditionally asserted that
`sbi_sess->poll.write` was non-NULL when the write queue drained, then removed
it from the poll set. In edge cases—particularly when using curl 8.x with
external epoll and `SIGPIPE` disabled—a late `EPOLLOUT` or errant write-ready
notification could arrive after `poll.write` had already been cleared. This
triggered the assertion in `nghttp2-server.c:1765`, aborting the process on
shutdown or session teardown.
This commit replaces the hard assertion with a runtime guard. If `poll.write`
is present, it is removed and reset to NULL as before. If it is already NULL,
we emit an warning log (`ogs_warn`) instead of aborting. This ensures any stray
write events after cleanup are safely ignored, allowing a clean exit without
crashing.
- Wrap `ogs_pollset_remove()` and pointer clear in `if (sbi_sess->poll.write)`
- Log an warning when `poll.write` is unexpectedly absent
- Preserve original behavior when `poll.write` is valid
This change resolves the fatal assertion observed on process exit after the
EPOLLERR/SIGPIPE fix and improves overall shutdown robustness.
Previously, any SCTP recv would trigger ogs_fatal and an assert_if_reached
when MSG_EOR wasn’t set, causing the AMF or MME to crash on oversized
or fragmented packets. Since we rely on a 32 KB receive buffer and
do not support SCTP reassembly, this change replaces the conditional
fatal/assert logic with a single ogs_error call in both ngap_recv_handler
and s1ap_recv_handler.
Oversized or partial SCTP messages are now logged and dropped instead of
crashing the process.
Previously, both AMF and MME assumed that RAN UE contexts would always
be present, triggering fatal assertions when a context lookup failed.
This change introduces explicit checks in the common_register_state handlers
to detect missing NG and S1 contexts without crashing:
- Check ran_ue existence and abort if NG context has already been removed
- Detect deassociated RAN-UE (invalid amf_ue_id) and
break to avoid further processing
- Validate AMF-UE ID matches ran_ue->amf_ue_id and skip on mismatch
- Replace hard assertions on MBR/GBR presence in S1AP e‐RAB setup
with a runtime check: if any of the four parameters (MBR DL/UL, GBR DL/UL)
is missing, log an error and treat the bearer as Non-GBR
- Mirror the same logic in SMF’s NGAP build routines for PDU Session Resource
Setup and Modify transfers: drop the assertions, emit detailed error messages
with the missing MBR/GBR values, and omit GBR IEs
- Ensures graceful handling of incomplete QoS configurations by defaulting
to best‐effort (Non-GBR) rather than crashing
Prevent the NRF from processing requests that target its own
instance ID. This prevents a denial of service vulnerability.
If an SBI request attempts to delete or modify the local NRF
instance, respond with 404 Not Found and log an error, avoiding
a crash due to the state machine assertion.
The token parsing loop in ogs_ipfw_compile_rule() lacked a bound on the
number of tokens stored in the 'av' array. This could overflow the stack
buffer when parsing overly long flow descriptions. Add a check to ensure
'i' remains below MAX_NUM_OF_TOKEN-2 before assigning to 'av[i]'.
- Add support for PDU Session Release in 3GPP TS 23.502 section 4.3.4.3
Note: PCF-initiated release flow for Home-Routed Roaming is not implemented;
- Fix N4 release step ordering in 3GPP TS 23.502 section 4.3.4.2 UE or network requested PDU Session Release for Non-Roaming and Roaming with Local Breakout
- In `udm_ue_state_operational()`:
- Wrap the call to `udm_nudr_dr_handle_subscription_authentication()`
in an `if` check.
- On failure (`false`), log an error via
`ogs_error("udm_nudr_dr_handle_subscription_authentication() failed")`.
- Transition the FSM to `udm_ue_state_exception` using `OGS_FSM_TRAN()`.
This change ensures that failures during subscription authentication
REST calls are not silently ignored, and that the UE state machine moves into
an exception state for proper error handling and recovery.
In amf_context_parse_config(), update the loop condition to ensure that
((i * 2) + 1) remains below
(OGS_NAS_MAX_NETWORK_NAME_LEN - 1) before performing any writes.
This change prevents potential out-of-bounds memory writes during
the conversion of an ASCII string to USC-2, thereby fixing a buffer
overflow issue.
This issue was observed on Ubuntu 25.04 and reported in the osmocom
nightly package.
This commit adds support for two Supported-Features AVPs in the
UpdateLocationAnswer (ULA) to enable 5G-NSA roaming. The first AVP
includes subscriber restrictions, while the second AVP signals that NR
as Secondary RAT is supported. Updates include modifications to
lib/diameter/s6a/message.c, lib/diameter/s6a/message.h, and
src/hss/hss-s6a-path.c.
This commit enhances the SM Policy request sent to the PCF
by incorporating user location information and time zone data.
The SMF now builds a userLocationInfo structure using the session's NR TAI
and NR CGI details, along with a timestamp generated from the current GMT time.
Additionally, the UE's time zone is included in the request context,
and the ratType is explicitly set to NR.
In Open5GS 2.7.x, when using curl 8.x with external epoll, an issue occurred
where the peer connection was closed, triggering EPOLLERR. At this point,
POLL_OUT should have been set to trigger the write event handler, invoking
`event_cb()` and calling `curl_multi_socket_action`. This would allow
`curl_multi_info_read` to execute without blocking.
However, when `event_cb()` wasn't invoked, `curl_multi_socket_action` was
not called, causing `curl_multi_info_read` to block. This resulted in a busy
loop in epoll, continuously checking for the closed peer connection.
This issue specifically affects Open5GS 2.7.x with curl 8.x, and is observed
on Ubuntu versions starting from **noble** and later. It does not occur on
Ubuntu Jammy.
The solution involves globally ignoring SIGPIPE and fixing the epoll logic
to ensure POLL_OUT is triggered when EPOLLERR occurs, allowing `curl_multi_socket_action`
to be invoked and `curl_multi_info_read` to run non-blocking. This resolves
the busy loop and connection issues caused by peer disconnects when using
curl 8.x and external epoll.
This fix improves the stability and performance of Open5GS when used with
curl 8.x and Ubuntu versions **noble** and above.
This commit fixes an issue where the callback header (3gpp-Sbi-Callback)
was incorrectly added in non-callback requests. Specifically, for registration
(PUT) and subscription requests in the AMF and SMF modules, the callback
header was included even though these are not asynchronous notifications.
Changes include:
- Removing the callback header assignment in src/amf/nudm-build.c and
src/smf/nudm-build.c for registration and subscription requests.
- Removing the callback header in NRF subscription-related builds in
lib/sbi/nnrf-build.c where it was not required.
- Adding the callback header only for actual notification or callback
operations (e.g. in src/amf/nsmf-build.c for N1/N2 transfer failure and
in src/nrf/nnrf-build.c for NF status notifications).
- Introducing a new callback macro in lib/sbi/message.h for
Namf_Communication_onN1N2TransferFailure.
This aligns the implementation with the standard, ensuring that callback
headers are only included in genuine callback/notification messages.
When UPF/SGW-U is restarted, missing f_teid_len validation causes an error.
This patch adds checks for f_teid_len > 0 in ogs_pfcp_pdr_swap_teid and
in the SGW-U and N4 handler functions.
When a UE handover occurs, the target UE may already be removed. This
patch adds a NULL pointer check and logs an error instead of causing a
segmentation fault in both enb and sgw deassociation functions.
Renamed backup/restore security context functions to save/restore
memento and updated flag to "can_restore_context". Updated AMF and MME
state machines to restore context on failure, preventing malicious
deletion triggered by spoofed NAS messages.
- Changed amf_region_id type from uint16_t to uint8_t in context.h.
- Updated context.c to use ogs_amf_region_id() for extracting and comparing
the region ID.
- Backup sensitive security context fields (e.g. xres, kasme, rand, autn,
keys, counters) when transitioning from REGISTERED state.
- Set the can_restore_security_context flag in common_register_state()
based on whether the transition originates from a REGISTERED or
de-registered state.
- In emm_state_authentication(), restore the security context and revert
to the REGISTERED state on authentication failure only if restoration
is allowed; otherwise, transition to an exception state.
- Remove the redundant unconditional state transition in the cleanup block
to prevent overriding a valid restoration.
Replace unsafe strcpy calls with ogs_cpystrn in both ogs_pfcp_dev_add()
and ogs_pfcp_subnet_add() to ensure proper length checking.
This change prevents potential buffer overflows when handling ifname
and dnn fields, which could otherwise lead to unintended overwrites
(e.g., fd and num_of_range).
Previously, the EPC used the UE-provided KSI directly in the Authentication
Request (except for the special case where the UE sent
OGS_NAS_KSI_NO_KEY_IS_AVAILABLE, which was reset to 0).
This commit changes the EPC to follow the 5G Core approach
for issuing KSI in Attach-Request.
Now, when a Attach Request is received and a new Authentication Vector is
generated, the EPC performs the following steps:
- Extract the KSI value from the UE's request.
- Increment the extracted KSI by 1.
- Use the incremented KSI in the Authentication Request sent to the UE.
This detailed process ensures that the EPC issues the KSI consistently
with 5G Core standards, improving key management and interoperability.
Previously, sample.yaml was used for both 5GC and EPC attach tests.
Because SMF had SBI configured, it sent a register PUT to NRF even in
EPC-only tests (where nrf/scp was not run), leading to a missing HTTP
response and connection timer expiry.
Now, attach.yaml is used for EPC, preventing the unwanted NRF registration.
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.
When another NF restarts, curl reuses the existing connection, which in
curl 8.9.1 causes the nghttp2 server to send an RST. This commit sends a
GOAWAY frame to every active session on shutdown, ensuring a graceful
termination and avoiding RST errors.
Previous versions such as curl 7.81.0 did not exhibit this behavior.
Previously, nf_instance pointers were stored in nf_type_array and
service_type_array. This led to dangling pointers when an NF instance
was removed via ogs_sbi_nf_instance_remove(), causing incomplete cleanup
and improper recovery on UDR or other NF restarts. The issue resulted in
the system falling back to nf_instance->client with the default port 80,
leading to connection failures.
To resolve the problem, nf_instance_id is now stored instead of the
pointer. The validity of an NF instance is verified using
ogs_sbi_nf_instance_find(nf_instance_id), which ensures proper cleanup
and correct recovery.
In case that NF do not send ProblemDetails in the response.
Do not assume that ProblemDetails is always present, to prevent null
pointer dereferencing.
When receiving a PFCP Session Establishment Request with an invalid PDN type(0),
the UPF would crash due to a failed assertion.
This commit improves error handling by:
- Removing the session_type assertion check that caused the crash
- Changing warning log to error log for better visibility
- Returning CAUSE_SERVICE_NOT_SUPPORTED instead of proceeding
with invalid type
This prevents potential DoS attacks through malformed PFCP messages.
Before this, there were 2 different ways to search for neighbouring
NF's:
a) in the case AMF was started _before_ UDM, AMF would create
subscription to NRF to notify it when a UDM would (un)register. In this
case, NF instance would remain in AMF's context indefinitely.
b) in the case AMF was started _after_ UDM, AMF would have to use NF
discovery mechanism to search for NF's. In this case, NF instance would
remain in AMF's context for the duration of Search's validity (defaults
to 30 seconds). After validity expires, NF would expire. This means that
for heavy traffic situations, AMF would constantly issue discovery
requests.
[SBI] save only wanted NF instances on NF List Retrieval
When retrieving a list of NF Instances from NRF, save only the NF's that
we want. Check the NF instance against our subscription list for either
the NF type or NF Service.
This can still cause a DoS on NRF when NF starts in case there are 100's
of NF's in the network, but prevents using too much memory on NF.
* [UDM][UDR] Add support for nssai resource in nudm-sdm
* Resolve Memory Issue
* Protect from multiple field entries, remove macros
* remove request_from_server, make use of xact state
* typo....
* definition cleanup
When a duplicate PDU session establishment is received, the AMF logs a
warning and proceeds to update the SM context via the SBI interface. This
process eventually calls amf_nsmf_pdusession_build_create_sm_context(), which
uses the SUPI to build the SBI URI header. If the SUPI is NULL, then the header's
resource component becomes NULL. This leads to a call to ogs_uridup() that
asserts on the NULL value, causing a crash.
This commit adds a check before invoking the SBI update. If the SUPI is NULL,
the update is skipped and a warning is logged. This prevents the invalid URI
build process and avoids the subsequent crash in ogs_uridup().
During handover between two gNBs, the AMF enters an invalid state when it
receives an unexpected SBI response from the UDM in the process of sending
a smf-select-data request. This bug could lead to an AMF crash as the state
machine in gmm_state_registration encountered an unknown state.
The fix adds explicit handling for SBI messages with resource names such as
AM_DATA, SMF_SELECT_DATA, UE_CONTEXT_IN_SMF_DATA, and SDM_SUBSCRIPTIONS.
If the HTTP response status is not OK, CREATED, or NO_CONTENT, a warning
is logged and the message is ignored. This prevents the AMF from transitioning
into an abnormal state and improves overall stability during frequent handovers.
Previously, policies were configured via YAML files without MongoDB.
This update enhances the YAML approach by adding the 'supi_range' key to
filter policies based on UE SUPI ranges. When both 'supi_range' and
'plmn_id' are provided, both conditions must be met.
Note that PLMN-ID filtering will be deprecated in a future release.
Replace enb_ue with source_ue to correctly reference the target eNodeB
context during handover. Added null checks and assertions to ensure proper
session cleanup in both mme-s11-handler.c and s1ap-handler.c.
This commit modifies the message length check in ogs_pfcp_recvfrom.
Previously, the condition only verified that the received size was less than
the expected length, which could allow messages that are too long to be
processed.
The condition now requires an exact match between the received
size and the expected total PFCP message length, ensuring proper message
validation.
This commit adds additional checks in the PFCP receive callback to ensure
that a complete PFCP message is received before parsing. A minimum header
length check and a total message length validation are now performed. This
prevents incomplete, fragmented messages from being processed and avoids
potential parsing errors and DoS conditions.
Previously, the function `udm_nudm_sdm_handle_subscription_create()` would
trigger a fatal assertion failure if the maximum number of SDM subscriptions
was reached.
This commit adds error handling to check if the subscription pool allocation
fails.
If `udm_sdm_subscription_add()` returns NULL, an appropriate error message is
logged, and a 400 Bad Request response is sent back to the client instead of
causing a crash.
Wrap SSL_CTX_set_keylog_callback calls with an OpenSSL version check
to ensure compatibility with versions older than 1.1.1.
This prevents compilation issues on earlier OpenSSL releases,
such as those found on Ubuntu 18.04(bionic).
Each received PFCP message triggered ogs_pfcp_node_find(), causing a DNS
resolution if node_id was FQDN. Under heavy traffic, this could lead to
excessive DNS queries.
- Implement a 300-second refresh interval to avoid repeated DNS lookups.
- Store last_dns_refresh in each node to defer new queries until needed.
- Treat config-based nodes with no Node ID as UNKNOWN, matching them by IP
alone until ogs_pfcp_node_merge() updates their ID.
- Validate IPv4, IPv6, or FQDN types in ogs_pfcp_node_merge() and reject
invalid IDs.
- Provide inline code comments for clarity and maintainability.
This commit addresses an Open5GS bug where the AMF process crashes
when receiving npcf-am-policy-control service responses during UE handovers.
The crash was occurring in the gmm_state_authentication() function
when the AMF encountered an unexpected SBI (Service Based Interface) message
from the PCF related to AM Policy Control requests.
Added a new case block in gmm_state_authentication() to explicitly handle
messages with the service name OGS_SBI_SERVICE_NAME_NPCF_AM_POLICY_CONTROL.
- Replace direct usage of OGS_ADDR/OGS_PORT macros with
ogs_sockaddr_to_string_static() for consistent IPv4/IPv6 logging.
- Remove redundant stack buffer allocations for address printing.
- Update PFCP node address handling to use addr_list and related
merges, avoiding obsolete sa_list references.
- Use ogs_pfcp_extract_node_id() and related APIs to safely extract
PFCP Node ID, improving error handling and reducing stack usage.
- Changed ogs_sockaddr_strdup to ogs_sockaddr_to_string_static
- Replaced dynamic allocation with a static buffer
- Updated source and header files accordingly
Created util.h and util.c to implement the ogs_pfcp_get_node_id function,
which retrieves the node_id from a PFCP message. Utilized the
ogs_pfcp_status_e enum for enhanced error handling, distinguishing
between success, absence, and error states.
Modified the `ogs_gtp/pfcp_context_parse_config` function to iterate through
all configured GTP/PFCP server addresses. When a Fully Qualified Domain
Name (FQDN) resolves to multiple IP addresses, the server now binds and
listens on each IP address individually.
These modifications enhance the flexibility and reliability of the GTP/PFCP
server within Open5GS, allowing it to handle multiple network
interfaces and redundant IP configurations as required.
In case that mapped HPLMN SST was not set by the UE in the request to
Establish PDU Session, AMF/SMF would assume it is set to 0 (since the
recent change to allow SST value 0).
3GPP TS 23.003: 28.4.2 Format of the S-NSSAI
The SST field may have standardized and non-standardized values. Values
0 to 127 belong to the standardized SST range and they are defined in
3GPP TS 23.501 [119]. Values 128 to 255 belong to the Operator-specific
range.
Introduce client_delegated_config to manage delegation settings for NRF and SCP
separately. This ensures that in Model C, all NRF-related procedures
(registration, heartbeat, deregistration, etc.) communicate directly with the
NRF without routing through the SCP. This change aligns Open5GS behavior with
3GPP standards, providing consistent direct communication for both discovery
and management in Model C, and maintaining indirect communication in Model D.
- Direct Communication with NRF
```
sbi:
client:
nrf:
- uri: http://127.0.0.10:7777
```
- Indirect Communication by Delegating to SCP
```
sbi:
client:
scp:
- uri: http://127.0.0.200:7777
```
- Indirect Communication without Delegation
```
sbi:
client:
nrf:
- uri: http://127.0.0.10:7777
scp:
- uri: http://127.0.0.200:7777
delegated:
nrf:
nfm: no # Directly communicate NRF management functions
disc: no # Directly communicate NRF discovery
scp:
next: no # Do not delegate to SCP for next-hop
```
- Indirect Communication with Delegated Discovery
```
sbi:
client:
nrf:
- uri: http://127.0.0.10:7777
scp:
- uri: http://127.0.0.200:7777
delegated:
nrf:
nfm: no # Directly communicate NRF management functions
disc: yes # Delegate discovery to SCP
scp:
next: yes # Delegate to SCP for next-hop communications
```
- Default delegation: all communications are delegated to the SCP
```
sbi:
client:
nrf:
- uri: http://127.0.0.10:7777
scp:
- uri: http://127.0.0.200:7777
# No 'delegated' section; defaults to AUTO delegation
```
This update allows the parsing and handling of user-defined port numbers
in the `advertise` field or explicitly in the `server` configuration for
SBI. Users can now specify non-default ports for both binding and
advertising while maintaining compatibility with existing configurations.
The feature includes logic to handle FQDNs with embedded port numbers
(e.g., `example.com:8080`) and ensures proper memory management during
parsing. Updated the client association logic to utilize custom ports
when specified.
Examples:
- Bind to the address on the eth0 and advertise as open5gs-amf.svc.local
```
sbi:
server:
- dev:eth0
advertise: open5gs-amf.svc.local
```
- Specify a custom port number 7777 while binding to the given address
```
sbi:
server:
- address: amf.localdomain
port: 7777
```
- Bind to 127.0.0.5 and advertise as open5gs-amf.svc.local
```
sbi:
server:
- address: 127.0.0.5
port: 7777
advertise: open5gs-amf.svc.local
```
- Bind to port 7777 but advertise with a different port number 8888
```
sbi:
server:
- address: 127.0.0.5
port: 7777
advertise: open5gs-amf.svc.local:8888
```
- Add `sslkeylogfile` configuration options to `*.yaml.in` in NFs.
- Update `open5gs-common.dirs` to include `var/log/open5gs/tls` directory
- Extend `ogs_sbi_context_s` structure in `context.h` to include `sslkeylog`
- Modify `context.c` to parse and handle `sslkeylogfile` settings
- Update `server.c` and `server.h` to manage the `sslkeylog` field
in server structures
- Update `ogs_sbi_client_add` and `ogs_sbi_client_remove` functions to handle
`sslkeylog` field.
- Adjust `meson.build` to create the TLS log directory during installation
This commit introduces SSL key logging functionality to Open5GS,
enabling the capture of SSL/TLS keys. This feature is essential
for debugging encrypted traffic and allows integration with tools
like Wireshark for decrypting TLS sessions.
- Added functionality to parse and validate the plmnList JSON array
during a PATCH request.
- Updated the nf_instance structure with new PLMN data from the request.
- Ensured robust error handling for invalid PLMN entries
and excessive PLMN counts.
- Responded with appropriate HTTP status codes for success and error scenarios.
- Removed `create_sctp_socket_from_addr_list` function.
- Introduced direct use of `sctp_socket_family_from_addr_list` in
`ogs_sctp_server` and `ogs_sctp_client`.
- Ensured proper handling of address family selection for SCTP sockets,
defaulting to `AF_INET` or `AF_INET6` based on the address list.
- Added error handling for cases where no suitable address family is found.
Addressed feedback on commit 33532a5 by switching SGsAP's SCTP socket
from SOCK_SEQPACKET to SOCK_STREAM. This change eliminates the need
for the 'addr' field, as SOCK_STREAM does not require specifying the address
in sctp_sendmsg.
All references to the 'addr' field have been removed from the VLR structure
and related functions, simplifying SCTP message handling and ensuring better
compatibility with multiple addresses.
Updated `sgsap-sctp.c` accordingly to reflect these changes
and improve the reliability of SCTP connections.
Added checks to validate the SUPI ID in the ogs_dbi_auth_info function
before calling ogs_assert. This prevents a crash when the SUPI ID is malformed,
such as when it does not contain a hyphen.
The fix ensures that invalid SUPI values are logged and handled gracefully,
avoiding assertion failures and crashes in the UDR.
- Modified the `ogs_nas_qos_rule_s` structure to increase the size
of the `identifier` field from 4 bits to 6 bits in order to allow
for larger QoS Flow Identifiers (QFI).
- Adjusted the URR access logic in `upf_sess_urr_acc_add` to prevent
out-of-bounds access by ensuring the URR ID is within the valid range.
Refactored the SCTP socket creation logic to dynamically select
the address family based on the provided address list.
A new function, `create_sctp_socket_from_addr_list`, was introduced
to check for the presence of an IPv6 address in the address list and
create an SCTP socket accordingly.
If an IPv6 address is found, it uses AF_INET6; otherwise, it defaults
to AF_INET. This change was applied to both the `ogs_sctp_server` and
`ogs_sctp_client` functions.
Updated the VLR (mme_vlr_t) lookup mechanism to identify VLR instances
using socket pointers rather than IP addresses.
Replaced the `mme_vlr_find_by_addr` function with `mme_vlr_find_by_sock` across
relevant modules, including `mme-context.c`, `mme-context.h`, and `mme-sm.c`.
Adjusted memory management for the `addr` field within the VLR structure
to ensure proper allocation and deallocation. Removed address assignments
in `sgsap-sctp.c` for usrsctp and updated logging to reflect the new socket-based
identification.
Added support for binding to local IP addresses in ogs_sctp_client and
ogs_sctp_server, and correct SGsAP configuration
Implemented the ability to bind to one or multiple local IP addresses using
`sctp_bindx()` in both the `ogs_sctp_client()` and `ogs_sctp_server()` APIs.
Users can now specify local addresses in the configuration files under the new
`local_addresses` field, reducing unnecessary complexity and signaling caused
by binding to `ANY_ADDR`.
This update addresses issue https://osmocom.org/issues/6509 by ensuring
correct operation in multi-interface and complex networking setups.
Additionally, corrected the `sgsap` configuration by changing it
from `server` to `client`, and added support for specifying `local_addresses`
for local binding as follows:
```
sgsap:
client:
- address: msc.open5gs.org # SCTP server address configured on the MSC/VL
local_address: 127.0.0.2 # SCTP local IP addresses to be bound in the M
```
Modified the PCF logic to bypass the BSF dependency when it is not available.
This change ensures that the 5G Core can operate without requiring a BSF,
allowing PDU sessions to be established successfully in setups
where only a single PCF is used.
Resolved a heap-buffer-overflow issue
in the ogs_nas_5gs_decode_registration_request function caused
by improper handling of empty pkbuf.
Added validation checks to ensure pkbuf size is non-zero
before accessing its data.
Reviewed similar patterns in other decoding functions
to prevent similar vulnerabilities.
Added a handler in gmm_state_registered() to process SBI client events
for UE context transfer, preventing fatal errors and AMF crashes during
Initial Registration.
This commit resolves additional crashes in the AMF caused by improper handling
of UE registration requests in various states of the GMM state machine.
The issue occurs when the AMF receives multiple registration requests
from the same UE while the previous UE context is being released,
leading to outdated or invalid authentication vectors being processed.
Although a previous fix addressed this problem in the gmm_state_exception
function, similar crashes were identified in other states within gmm-sm.c.
To address this, the handling of multiple registration requests
from the same UE has been refined across all relevant states.
The fix ensures proper synchronization and validation of UE contexts,
preventing the AMF from processing outdated authentication data and
maintaining stability during such edge cases.
This prevents incorrect restoration behavior by ensuring the TEID is only
swapped when F-TEID.ch is false, indicating the TEID has already been assigned.
Added a check to ensure that TEID restoration via swap occurs only
when F-TEID.ch is false. In the restoration process, when F-TEID.ch is false,
it indicates that the TEID has already been assigned, and the swap operation is
necessary to restore the TEID. However, if F-TEID.ch is true, it means that
the UPF needs to assign a new TEID for the first time, and performing a swap
in this case would be incorrect.
This check ensures that the swap operation is only triggered
when the TEID is already assigned and prevents potential issues
during the TEID assignment process.
This commit addresses an issue in the AMF where it crashes
upon receiving the Nausf_UEAuthentication_Authenticate response
in the gmm_state_exception function.
The crash occurs when the same UE continuously sends registration requests
while the previous UE context is released before the AUSF response is received,
leading to incorrect states in the gmm state machine.
The root cause was a lack of proper handling in the gmm_state_exception function
for the scenario where multiple registration requests from the same UE cause
the AMF to process outdated authentication vectors.
This update introduces a fix to handle this edge case
and prevent the AMF from crashing.
- Added handling for empty NAS PDUs to prevent potential heap-buffer-overflow.
- Implemented safeguards to reject invalid NAS messages and mitigate DoS attacks
by removing S1/NG Context for affected UEs.
In case an external HSS is used, and the NAM field is set to 0 (PACKET_ONLY),
Open5GS MME will only respond with an "EPS_ONLY" attach accept. This behavior
causes a lot of UEs (mainly phones) to disconnect after 1-2 seconds without
further signalling.
To resolve this, a new flag is introduced:
```
global:
parameter:
fake_csfb: true
```
If this flag is set to 'ture', the MME will respond with a combined EPS/IMSI
attach accept even if the HSS NAM field is set to "PACKET_ONLY", or if the
MME has no SGs connection towards a CS core.
By default this flag is false, thus not modifying the original behavior.
Note: some commercial core network vendors do include the LAI part in a
"fake" combined EPS/IMSI attach accept message. As that field is optional, and
testing also indicates that it is not needed, this patch does not implement it.
According to TS 29.510, the NFProfile structure in the NFDiscovery API does not
include the nfProfileChangesSupportInd attribute. However, Open5GS NRF currently
includes this attribute in NFDiscovery API responses, which has led to
complaints from certain NF vendors.
This commit modifies the nrf_nnrf_handle_nf_discover function
in src/nrf/nnrf-handler.c to ensure that the nfProfileChangesSupportInd
attribute is excluded when constructing NFProfile for NFDiscovery responses.
This commit introduces a new parameter in the global configuration
to support UPG-VPP UPF. When the following setting is added:
```
global:
parameter:
use_upg_vpp: true
```
The SMF generates PFCP messages specifically tailored for UPG-VPP UPF.
This allows seamless integration and operation with UPG-VPP
by automatically adapting the message structure to its requirements.
- Added support for the N9 For Roaming interface type:
- Core interface act as V-UPF.
- Access interface act as H-UPF.
- Modified V-UPF behavior:
- V-UPF updates only the TEID and IP Address in the GTP-U header.
- The content following the Extension Header is passed through directly
between the UE and H-UPF.
This implementation ensures seamless data flow between the UE, V-UPF, and H-UPF
while maintaining integrity for Home Routed Roaming scenarios.
TS 29.571 - 5.5.2 Simple Data Types defines BitRate type as
String representing a bit rate that shall be formatted as follows:
Pattern: '^\d+(\.\d+)? (bps|Kbps|Mbps|Gbps|Tbps)$'
Examples: "125 Mbps", "0.125 Gbps", "125000 Kbps"
Taking the "0.125 Gbps" example, rather than round 0.125 down to 0, parse it as
a double-float first before multiplying by 10^9, resulting in 1.25e8 (bps).
Resolved an issue where Handover was failing when attempting to handover
from GNB-ID/eNB-ID 1 to GNB-ID/eNB-ID 0.
The problem occurred because the hash table managing GNB_ID values would
remove any entry with the default GNB-ID/eNB-ID of 0 before re-adding entries.
Consequently, any GNB/eNB configured with a GNB-ID/eNB-ID of 0
would be inadvertently deleted whenever another GNB was added.
This fix modifies the handling of the hash table to prevent the default
GNB-ID/eNB-ID (0) from being removed unintentionally, allowing handovers
between GNB-ID/eNB-ID 0 and other GNBs/eNBs to proceed without error.
```
TS36.413
8.7.3 S1 Setup
8.7.3.4 Abnormal Conditions
If the eNB initiates the procedure by sending a S1 SETUP REQUEST message
including the PLMN Identity IEs and none of the PLMNs provided by the eNB
is identified by the MME, then the MME shall reject the eNB S1 Setup Request
procedure with the appropriate cause value, e.g., “Unknown PLMN”
```
Modified code to address abnormal conditions where the eNB initiates
the S1 Setup Request with a PLMN Identity IE that is unrecognized by the MME.
In this case, the MME now properly rejects the S1 Setup Request
with the cause value "Unknown PLMN" in compliance with the 3GPP specification
(8.7.3.4).
In accordance with TS29.500 Section 5.2.2.2 on mandatory HTTP standard headers,
the User-Agent header in HTTP/2 requests is required to include the NF type
of the HTTP/2 client. Additionally, it is specified that the content
of the User-Agent header may be followed by a hyphen and custom information
when needed, providing greater flexibility for identifying the originating
NF type or adding other specific details.
To accommodate this requirement, I modified the code to allow for additional
information to be appended after the NF type in the User-Agent header,
separated by a hyphen.
This change ensures that the User-Agent header format can be customized
as needed for indirect communication scenarios and requests originating
from the SCP, improving compliance with the specification and enhancing
the adaptability of the header format for HTTP/2 communications.
While experimenting with CSFB, it was observed that when the UE returns
to E-UTRAN after a CS call, the UE performs a Tracking Area Update
with a combined Tracking Area/Location Area update and IMSI attach.
Currently, Open5GS's MME simply responds with a TAU Accept message
but does not inform the MSC/VLR.
As a result, no further MT (Mobile Terminated) CS/SMS services are possible
in cases where the MSC/VLR only attempts paging on GERAN.
However, some MSC/VLR implementations with fast fallback may still attempt
paging on E-UTRAN, allowing MT CS/SMS services to function intermittently.
According to 3GPP TS 29.118 Section 5.2.2 Procedures in the MME,
specifically Section 5.2.2.2.1, if the timer Ts6-1 is not running,
the MME shall start the location update for non-EPS services procedure
upon receiving a combined Tracking Area Update Request indicating
combined TA/LA updating with IMSI attach. However, SGs timers are not
implemented in Open5GS, which is a separate issue.
To comply with the specification and ensure that the MSC/VLR is informed
when the UE becomes reachable via SGs, the following changes have been
implemented:
1. Delay UEContextReleaseCommand:
When the active_flag is set to 0, the UEContextReleaseCommand is now delayed
until the MME receives the TAU Complete message from the UE. This ensures
that the UE has acknowledged the new P-TMSI before the network releases
the context, maintaining proper synchronization between the UE and the network.
2. Include Mobile Identity Only When P-TMSI Changes:
The Mobile Identity is now included in the Attach/TAU Accept messages
only when the MSC/VLR updates the P-TMSI. This ensures that the UE receives
the Mobile Identity information solely when there is an actual change
in the P-TMSI, preventing unnecessary or incorrect handling
of TAU Complete messages.
3. Send SGsAP-REALLOCATION-COMPLETE Conditionally:
The SGsAP-REALLOCATION-COMPLETE message is now sent to the MSC/VLR
only upon receiving a Attach/TAU Complete message from the UE.
This confirmation indicates that the UE has successfully updated its P-TMSI,
ensuring that the MSC/VLR is accurately informed of the change.
4. Handle P-TMSI Confirmation:
When the MSC/VLR updates the P-TMSI, Open5GS stores the new P-TMSI
in the next field of the mme_ue structure. Upon receiving the TAU Complete
message from the UE, indicating acknowledgment of the new P-TMSI,
Open5GS confirms the update by transferring the P-TMSI from the next field
to the current field. This ensures that the MME maintains an accurate and
up-to-date record of the P-TMSI as confirmed by the UE.
Fixed an issue in SCP TLS communication for Open5GS where omitted port numbers
in HTTP/HTTPS URIs (e.g., "https://scp.localdomain" implying port 443) were not
handled correctly.
Updated the code to ensure that during FQDN and port comparisons,
cases where the port number is set to 0 are accounted for.
This fix resolves the problem with indirect SBI communication over SCP using TLS
allowing proper connectivity between network functions like BSF and NRF.
Previously, the global configuration section was required for NF to start,
which differed from earlier versions where it was optional. This commit modifies
the implementation to make the global section optional again,
allowing NF to start without explicitly defining global settings.
This change restores the previous behavior and improves usability for users
who do not need to customize global settings.
The memory leaks occurring in specific exception handling scenarios have been
resolved. For instance, when an HTTP2 connection closes, memory associated
with objects like response messages was not being freed properly.
This update addresses and fixes these issues.
Implement support for Node-Identifier IE in GTPv2 S2b Create-Session-Request
to SMF for Diameter S6b integration
This patch adds support for processing the Node-Identifier IE within GTPv2
Create-Session-Request messages sent via the S2b interface to the SMF.
When the ePDG includes the Node-Identifier IE containing both host and realm
of the AAA-Server, the SMF now uses this information to populate
the Destination-Realm and Destination-Host AVPs in the Diameter S6b AAR message.
This enables seamless integration and allows the SMF to route requests directly
to the appropriate AAA-Server, enhancing interoperability in setups
where the host and realm data are required by the Diameter network.
This field was previously omitted, which could lead to
improper handling of interface-specific logic in certain scenarios.
The addition of the 3GPP Interface Type ensures correct behavior
in compliance with the 3GPP standards for PFCP message handling.
1. Fix SGW-U/UPF bug by comparing QFI only when PDI's QFI is present
Resolved an issue where the QoS Flow Identifier in the GTP-U Extension Header
was incorrectly compared regardless of the presence of PDI's QFI.
Updated the implementation to perform the comparison
only when PDI's QFI is present.
2. Add Outer Header Removal settings to SGW's PDR where necessary
Addressed the absence of Outer Header Removal in the SGW's PDR
by adding it to all required locations, ensuring proper header handling.
3. Remove unnecessary GTP-U Extension Header Removals
Eliminated all instances of GTP-U Extension Header Removal
since they should only be used during handover from 5GS to EPS.
This cleanup prevents improper header removals in other scenarios.
4. Delete unnecessary usage of Network Interface and UE IP Address
Removed all redundant references to Network Interface and UE IP Address,
streamlining the codebase and reducing potential confusion.
5. Change precedence so that Control has higher priority than Data
Adjusted the precedence settings to ensure that Control messages
are given higher priority over Data, enhancing the system's efficiency
and responsiveness.
1. Set packet filter identifier values to 0 when the UE requests to:
- Create new QoS rule
- Modify existing QoS rule and replace all packet filters
- Modify existing QoS rule and add packet filters - As specified in TS24.501, section 9.11.4.13, Table 9.11.4.13.1.
2. Revise QoS rule modification logic:
- Instead of replacing packet filters based on their identifiers (EPC approach), update the implementation to delete all existing packet filters within the QoS rule and add new ones.
- This ensures that when modifying an existing QoS rule to replace all packet filters, the packet filters are correctly reset and updated per 5G Core requirements.
- **Correct Packet Filter Identifier Handling:**
Remove the addition of +1 when searching for the packet filter context using `smf_pf_find_by_identifier()` in the 5G Core SMF. According to 3GPP TS24.008 Section 10.5.6.12 and TS24.501 Section 9.11.4.13, the Packet Filter Identifier should range from 1 to 15 (or 0 to 15) depending on the operation and should be used directly as received from the UE.
- **Adjust Maximum Number of Packet Filter Identifiers:**
Change the maximum number of Packet Filter Identifiers from **16** to **15** in the SMF to comply with the 3GPP specifications. The standards specify that the number of packet filters shall be greater than 0 and less than or equal to 15 for certain operations.
**Background:**
In the current 5GC implementation, the SMF incorrectly adds +1 to the identifier received from the UE and allows up to 16 identifiers, leading to mismatches and potential communication issues. These discrepancies cause the SMF to fail in correctly locating the packet filter context, resulting in improper QoS rule enforcement.
**Changes Made:**
- **For Packet Filter Identifier Handling:**
- Updated the SMF code to use the identifier received from the UE directly without modification:
```c
// Corrected code for 5GC:
pf = smf_pf_find_by_identifier(
qos_flow, qos_rule[i].pf[j].identifier);
```
- **For Maximum Number of Packet Filter Identifiers:**
- Adjusted the code to enforce a maximum of 15 packet filters as per the specifications.
**Impact:**
- **Compliance:**
- Ensures that the 5GC implementation of Open5GS adheres to the 3GPP TS24.008 and TS24.501 specifications regarding Packet Filter Identifier handling and limits.
- **Functionality:**
- Corrects the mapping and management of packet filters between the UE and SMF in 5GC, preventing potential communication issues and misconfigurations.
- **EPC Implementation:**
- The EPC implementation remains unaffected by these changes. EPC correctly handles the Packet Filter Identifier by decrementing it by 1 before sending it to the UE and adding +1 when searching for the packet filter context.
**Conclusion:**
By making these adjustments, we ensure proper synchronization between the UE and SMF in the 5G Core and maintain compliance with the 3GPP specifications. This fix resolves the mismatches caused by incorrect identifier handling and enforces the correct limit on the number of packet filters, enhancing the reliability and standards compliance of the 5GC implementation without impacting the existing correct behavior in EPC.
Decrement the Packet Filter Identifier by 1 before sending it to the UE
during GSM message construction. This correction ensures proper synchronization
between the UE and SMF, allowing `smf_pf_find_by_identifier()` to accurately
locate the corresponding `pf` context without adjusting the identifier
during the search.
This fix aligns the 5GC implementation with the EPC behavior,
where the identifier was correctly decremented before transmission to the UE,
preventing mismatches and synchronization issues.
I have modified the PAA's IPv6 prefix length from 8 to 64.
This adjustment ensures that the prefix length now correctly reflects
the standard /64 notation, in accordance with the specifications.
I wanted to let you know that I have modified the SMF configuration
to send S2b PGW GTP-U instead of S5/S8 PGW GTP-U in WLAN.
This adjustment should ensure that the correct interface type is used,
as per the specifications.
Implement Control Message handling between V-SMF and H-SMF
during Home Routed Roaming process
Completed the implementation of control messages exchanged
between V-SMF and H-SMF as part of the Home Routed Roaming process
The issue was that the PLMN-ID of the TAI was incorrectly being
retrieved from the PLMN-ID of the EUTRAN_CGI.
As a result, when the PLMN-IDs of the TAI and EUTRAN_CGI were improperly set,
the MME would crash.
All issues have now been resolved.
SMF selection according to 4.3.2.2.3 of TS23.502.
V-SMF makes discovery in the V-NRF according to V-NSSF.
H-SMF makes discovery in the H-NRF according to H-NSSF.
(The AMF goes through the V-NSSF and forwards the message seeking the NRF to the H-NSSF.)
This commit doesn't add any PCRF specific metrics, only all the
boilerplate code to instantiate libmetrics and hence have the generic
prometheus metrics available.
There's no real need for a separate thread, it all can run with a timer.
Furthermore, this will ease submitting events towards app so that they
can update diameter metrics.
Implement HSS selection process as described in TS 29.272 Section 7.16.
Use hss_map config entry to map between plmn and HSS realm & host.
Closes: https://github.com/open5gs/open5gs/issues/3422
Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
This commit is a follow-up from previous one, split to ease review.
In this commit, the SGSN Context Ack towards SGSN plus session creation
towards SGW is further delayed until authorizing + SecurityModeCommand
against UE has succeeded, hence meaning we have a fully operating
context to communicate with it.
As per 3GPP TS 23.401 Annex D.3.6 step 6, "Security functions may be
executed" during TAU (UE cell reselection 2g->4g).
The idea is that the 4G network should check the integrity of the TAU,
and only if iexisting and valid then accept it right away. Otherwise,
an authorization procedure is started.
Until now, during 2g->4g TAU we were retrieving and acking the PDP Context
received from the SGSN and creating the session against the SGW right away.
Tests done so far with real phones ended up in unsuccesful results when
tring to reuse the 4g context derived from 2g, due to yet unknown
reasons.
Hence, with this patch we simply force for now the re-auth and
recreation of security context before completing the TAU. This showed
good results during testing with real phones.
The security context is recreated through:
* S6a 3gpp-Authentication-Info towards HSS
* S1AP/NAS Authentication Request+Response towards UE
* SecurityModeCommand towards UE.
This patch is the first step towards delaying SGSN Context Ack after the whole
authentication is done against the UE. Patches are splitted for ease of
review.
This patch is only delaying session setup after the S6a procedure.
Follow-up patch will delay it further.
In case that UE requests a PDU session with specific SSC Mode
for which it is not authorized, reject the request
instead of trying to continue processing it.
The osmocom ttcn3-mme-ogs test uses an APN consisting simply of the NULL
byte. This corresponds to one label of length zero, so simply the APN "".
Since commit 333d3fe1 ogs_fqdn_parse() returning zero is considered an
error in ogs_gtp1_parse_pdp_context().
Fix this by returning a negative value on error in ogs_fqdn_parse() and checking for
that.
The standard mandates that one SSC Mode is the default (if UE does not
request one), with up to 2 additional SSC Modes can be selected.
Always check also the default SSC Mode if it can be selected.
Same logic applies for Session Types.
Set flag LimitedSubscriptions in the supportedFeatures field in
SDMSubscription. This flag should be set in case that AMF supports
unique SDM Subscription, notifying UDM in this case of the support.
The old comment describe the 4G to 2G mobility, not the 2G to 4G.
Correct the comments.
Also set the translated bearer vulnerability to 1, translated bearer
should always vulnerable to it.
The clang scan-build procedure
```
Assume Ubuntu docker container with open5gs mounted to /src.
Assume these tools are installed to docker container:
sudo apt install -y clang-tools clang
For easy reference to clang scan-build tool:
Put normal open5gs build procedure into a file called /src/build
=======================
Inside docker container:
=======================
export CLANG_OUT_DIR=/src/scan_build_results
scan-build -disable-checker deadcode.DeadStores --override-compiler --keep-going
--exclude subprojects --exclude tests --exclude lib/asn1c -maxloop 200 -o $CLANG_OUT_DIR -plist-html /src/build 2>&1 | tee /src/logclang.txt
=======================
Results:
=======================
Results are in html format in $CLANG_OUT_DIR - top level index.html
```
Note that in this analysis the following suppressions were assumed:
- no deadcode.DeadStores analysis since those are not functional findings
- exclude lib/asn1c for reason that is outside of open5gs control
- exclude tests for reason that those are not functional findings
- exclude subprojects since those are outside of open5gs control
- create SDM subscription to UDM when PDU session is created, just
before sending SMF registration to UDM
- delete SDM subscription when PDU session is released
- handle SDM Change Notification, but not yet process items in it
UEContextReleaseCommand fails to encode as an ASN.1 message
if the Group is 0. This is added because there is currently
no exception handling when the gNB sends a Group of 0.
When a GTP transaction occurs, the ENB-UE associated with the MME-UE may change.
To address this, we have changed the structure to include the ENB-UE
in the GTP transaction, similar to AMF.
When a UEContextReleaseRequest and a Service Request occur simultaneously,
the ENB-UE in the Release Access Bearer Request/Response GTP transaction is
designed to persist even if the ENB-UE Context changes.
UEContextReleaseCommand fails to encode as an ASN.1 message
if the Group is 0. This is added because there is currently
no exception handling when the gNB sends a Group of 0.
ngap_send_amf_ue_context_release_command() is unnecessary.
So, change ngap_send_amf_ue_context_release_command()
to ngap_send_ran_ue_context_release_command.
According to TS29.503, we can choose whether or not to allow LBO roaming
on a per-session basis.
To this end, we have made changes to allow us to set this via the WebUI.
NF should accept 204 No Content for Update Subscription requests.
According to 3GPP 29.510 NRF specification document in figure 5.2.2.5.6.1
NRF may return 204 or 200 for success update operations.
2a. On success, if the NRF accepts the extension of the lifetime
of the subscription, and it accepts the requested value for the "validityTime"
attribute, a response with status code "204 No Content" shall be returned.
2b. On success, if the NRF accepts the extension of the lifetime
of the subscription, but it assigns a validity time different than
the value suggested by the NF Service Consumer, a "200 OK" response code shall
be returned. The response shall contain the new resource representation
of the "subscription" resource, which includes the new validity time,
as determined by the NRF, after which the subscription becomes invalid.
I changed it so that all NFs can receive both 200 and 204 STATUS.
I also changed the default behavior of NRFs to respond with 204,
which is NO CONTEXT.
- Upgraded libraries to 4.5 to address compile error issues with CXX11 support
- Change the default version of FreeBSD Vagrant to 14.1-STABLE
- FreeBSD Platform documentation also changed to 14.x version
TS24.008
10.5.6.12 Traffic Flow Template
Table 10.5.162: Traffic flow template information element
Number of packet filters (octet 3)
The number of packet filters contains the binary coding
for the number of packet filters in the packet filter list.
The number of packet filters field is encoded in bits 4
through 1 of octet 3 where bit 4 is the most significant
and bit 1 is the least significant bit.
For the "delete existing TFT" operation and
for the "no TFT operation", the number of packet filters shall be
coded as 0. For all other operations, the number of packet filters
shall be greater than 0 and less than or equal to 15.
The array of TLV messages is limited to 16.
So, Flow(PDI.SDF_Filter) in PDR is limited to 16.
Therefore, we defined the maximum number of flows as 16.
TS24.008
10.5.6.12 Traffic Flow Template
Table 10.5.162: Traffic flow template information element
Number of packet filters (octet 3)
The number of packet filters contains the binary coding
for the number of packet filters in the packet filter list.
The number of packet filters field is encoded in bits 4
through 1 of octet 3 where bit 4 is the most significant
and bit 1 is the least significant bit.
For the "delete existing TFT" operation and
for the "no TFT operation", the number of packet filters shall be
coded as 0. For all other operations, the number of packet filters
shall be greater than 0 and less than or equal to 15.
The array of TLV messages is limited to 16.
So, Flow(PDI.SDF_Filter) in PDR is limited to 16.
Therefore, we defined the maximum number of flows as 16.
When exiting a diameter interface, the session state data could be NULL.
So we added code to check the session state data
to prevent SIGSEGV occurring.
We're experiencing an issue after changing SearchResult.validityTime
from 3600 seconds to 30 seconds.
When AMF finds a PCF through Discovery, it can be deleted
after 30 seconds by ValidityTime.
We have changed our implementation to not send the PCF-ID in this case.
What we need to do is proactively add a part that will re-discover
the PCF when a situation arises where we really need the PCF-ID.
* [UPF/SGW-U] Optimizing data-path (#3306)
In ogs_pfcp_up_handle_pdr, there is a copy operation performed on recvbuf,
which can reduce the sending performance in the data path. Personally,
We believe that this copy operation can be eliminated.
Of course, if it is canceled, the recvbuf does not need to be released again
at the location where ogs_pfcp_up_handle_pdr is called. After testing,
it has indeed shown an improvement in performance of approximately 15-18%.
/*
sendbuf = ogs_pkbuf_copy(recvbuf);
if (!sendbuf) {
ogs_error("ogs_pkbuf_copy() failed");
return false;
}*/
sendbuf = recvbuf;</div>
* update it
UE attached to 4G cell, terminates 4G connection,
then attempts 5G cell attach with TAC update - fails connection
Setup a UE on a 4G cell. Also have a 5G cell available to the UE.
Next, disable the 4G cell. The 4G connection terminates normally.
The UE scans the network and finds the 5G cell.
At this time the UE sends a registration to the 5G cell.
Open5gs sent back a reject with reason "Semantically incorrect message".
Then the UE did not try to attach again and lost the call forever.
Compare this scenario with a different core that we tested this scenario on.
With a different core (other than open5gs) the core sent back a reject
also but with a reason "UE can't be derived by network".
Then the UE tried attach again and the 5G call was successful.
Although this was successful for the other core it could be suggested
that not rejecting at all is good behavior.
There is a workaround which is that the Samsung UE could be put into
airplane mode and taken out of airplane mode and at that point
the UE is able to attach to the 5G cell. But this is a lot of manual effort
on the user of the UE which could be avoided with a simple open5gs change.
Note: Issue only happens when registration request + tracking area update
occurs on 5G cell attach following LTE cell being disabled.
If only registration occurs without a tracking area update
(such as the first time system is up) then it is ok with no rejection.
To solve this issue, added Additional-GUTI to the ClearText Group.
On 4G only... when UE sent an inactivity UEContextReleaseRequest,
Open5GS sent back UEContextReleaseCommand **with cause=normal-release.
This, in turn, does not allow the Samsung UE to return to the low power state
in our testing of the scenario.
Comparing the behavior of open5gs to other cores that we have tested
the other cores are sending a ** cause=“Radio Network Layer Cause”:
User inactivity ** when the UE sends inactivity. And this is what allows
other cores to transition the UE to the low power state whereas
with open5gs the UE is not entering the low power state.
We've fixed to allow open5gs to come to the same level of compliance
in this area as to the other cores.
Update Bearer Request
Modify Bearer Context Request
Modify Bearer Context Accept
Update Bearer Response
In the process above, we incorrectly used the Timer
that the MME uses to wait for the eNB.
We used xact's holding timer, which continues to hold the transaction
for further exception handling even after sending the Update Bearer Response.
This timer should end exactly when the Update Bearer Response is sent
by the MME to the SGW-C. Therefore, we have added a new peer timer
in xact for this purpose.
We fixed an issue in #3302 where MME does not send Downlink Data Notification
Acknowledge to SGW-C in Error Indication situation.
However, it did not work properly when this occurred in conjunction
with releasing the bearer as shown below.
>>>Seesion-Termination in Diameter
>>>SMF sends E-RABReleaseCommand and
Deactivate EPS bearer request context
1. SGW-U received Error Indication
2. SGW-U sends PFCP Report Request to SGW-C
3. SGW-C sends PFCP Report Response to SGW-U
4. SGW-C sends Downlink Data Notification to MME (MME Connected with eNB)
>>> eNB sends E-RABReleaseCommand
>>> UE sends Deactivate EPS bearer context accept
5. MME sends UEContextReleaseCommand to the eNB
6. eNB sends UEContextReleaseComplete to the MME
7. MME sends S1-Paging to the eNB
8. eNB sends Service-Request to the MME
9. MME sends InitialContextSetupRequest to the eNB
10. eNB sends InitialContextSetupResponse to the MME
No bearer context, so cannot send Downlink Data Notification Acknowledge
So, we've fixed it as below.
>>>Seesion-Termination in Diameter
>>>SMF sends E-RABReleaseCommand and
Deactivate EPS bearer request context
1. SGW-U received Error Indication
2. SGW-U sends PFCP Report Request to SGW-C
3. SGW-C sends PFCP Report Response to SGW-U
4. SGW-C sends Downlink Data Notification to MME (MME Connected with eNB)
>>>>>>>> Since eNB Connected, we send Downlink Data Notification Acknowledge here.
>>> eNB sends E-RABReleaseCommand
>>> UE sends Deactivate EPS bearer context accept
5. MME sends UEContextReleaseCommand to the eNB
6. eNB sends UEContextReleaseComplete to the MME
7. MME sends S1-Paging to the eNB
8. eNB sends Service-Request to the MME
9. MME sends InitialContextSetupRequest to the eNB
10. eNB sends InitialContextSetupResponse to the MME
We've encountered an issue where Downlink Data Notification Acks are not sent
in the following situations.
1. SGW-U received Error Indication
2. SGW-U sends PFCP Report Request to SGW-C
3. SGW-C sends PFCP Report Response to SGW-U
4. SGW-C sends Downlink Data Notification to MME
(MME Connected with eNB)
5. MME sends UEContextReleaseCommand to the eNB
6. eNB sends UEContextReleaseComplete to the MME
7. MME sends S1-Paging to the eNB
8. eNB sends Service-Request to the MME
9. MME sends InitialContextSetupRequest to the eNB
10. eNB sends InitialContextSetupResponse to the MME
Here, MME needs to send Downlink Data Notification Acknowledge.
So, we've fixed it
I created ogs_sbi_xact_find_by_id() with a hash
to replace ogs_sbi_xact_cycle().
Modified to find the xact via xact->id
when making an HTTP request with the SBI client function
and waiting for the HTTP response.
Pool library has the following issues with XXX_cycle,
including mme_enb_cycle()/amf_ue_cycle()
```
INIT POOL(SIZE:5)
Alloc Node1
Alloc Node2
Alloc Node3
Alloc Node4
Alloc Node5
Free Node4
Free Node3
PoolCycle(Node4) is NULL (Freed...OK!)
PoolCycle(Node3) is NULL (Freed...OK!)
Alloc Node6
Alloc Node7
PoolCycle(Node4) is Not NULL (Freed...but NOK!)
PoolCycle(Node3) is Not NULL (Freed...but NOK!)
PoolCycle(Node6) is Not NULL (Allocated...OK!)
PoolCycle(Node7) is Not NULL (Allocated...OK!)
```
If we use ogs_poll_alloc() to create and allocate a node,
the correct behavior of calling ogs_pool_free() on this node
and then later calling ogs_pool_cycle() on this node must always return NULL.
However, the behavior of calling ogs_pool_cycle() on this node
in the future may return a “valid” pointer.
To solve the problem, we added hash id to the pool memory and
ogs_pool_find_by_id() function is added.
3GPP TS 23.003 Ch. 2.8.2.2.2 (Mapping in the UE) states "The P-TMSI
signature is sent intact to the MME."
So simply use the PTMSI signature from the TAU and pass it throught to the
SGSN Context Request.
The algorithms described in 3GPP TS 23.003 Ch. 2.8.2.1.2 an 2.8.2.2.2
are not directly the inverse of each other.
To send a SGSN Context Request (in 2G -> 4G mobility) the algorithm in
2.8.2.2.2 has to be done in reverse (like mentioned in 2.8.2.2.3 -
Mapping in the new MME).
When parsing an SGSN Context Request (for 4G -> 2G mobility) the reverse
of 2.8.2.1.2 (as described in 2.8.2.1.3) has to be used.
PTMSI signature handling is added in a separate commit.
When setting hashes, we typically delete and set hashes that are set to OLD.
A hash set to OLD should be deleted by setting it to NULL,
but here we're deleting it with a value of NEW.
Therefore, we modified it to delete the OLD gNB/eNB ID
instead of NEW by setting a NULL value to Hash as Key.
Consider the following situation.
```
1. SMF->SGW-C->MME: First Update Bearer Request
2. MME->UE: First Modify EPS bearer context request
3. SMF->SGW-C->MME: Second Update Bearer Request
4. MME->UE: Second Modify EPS bearer context request
5. UE->MME: First Modify EPS bearer context accept
6. MME->SGW-C->SMF: First Update Bearer Response
7. UE->MME: Second Modify EPS bearer context accept
8. MME->SGW-C->SMF: Second Update Bearer Response
```
Until now, only one GTP transaction was managed for one bearer.
Therefore, if the UE does not send an EPS Modify bearer accept to the MME,
and the SMF/SGW-C sends an Update Bearer Request to the MME,
The NEW update bearer request overwrites the OLD that was previously managed.
So we modified it to manage them simultaneously.
However, we don't know if this is the right way to implement it.
So if the SMF/SGW-C sends 5 MMEs of Update Bearer Request and
the UE sends only 3 MMEs of Modify EPS bearer context accept,
we have no way to associate it.
Therefore, it's implemented so that we just process them sequentially and
2 of them are just timeout.
When the second AMF, which is the transfer, runs later than the SMF,
there is no client information.
Fixed to pre-create the Client when the Resource URI is transferred.
Fixed to not change the session information stored in the DB
when transferring context from GERAN to EUTRAN.
Note that the Tracking Area Update Procedure differs
from the Attach Procedure in 5.3.2 in the point
at which HSS and ULR/ULA are performed.
3GPP TS 23.401
Ch 5.3.3 Tracking Area Update procedures
<Attach Procedure>
1. Security-mode complete
2. Update Location Request/Answer
3. Create Session Request/Response
<Tracking Area Update Procedure>
1. Security-mode complete
2. Create Session Request/Response
3. Update Location Request/Answer
When TAU creates a Create Session Request message,
there is no session type information in the Subscriber DB
that is received from HSS in the Update Location.
Therefore, TAU does not reflect the Session Type
but creates PDN Type by reflecting the information
in the Request Type as it is.
HTTP Location header field does not contain the "5g-aka-confirmation"
substring. Which means that when we try to delete the authentication
from AUSF, it fails.
/nausf-auth/v1/ue-authentications/1
vs
/nausf-auth/v1/ue-authentications/1/5g-aka-confirmation
IP assigned from SMF: session->paa
Static IP read from the Subscriber DB: session->ue_ip
When passing the PDP context information to the SGSN, we actually wanna
provide it with the IP address currently in use.
Try to fix the following error
"MME_Tests.ttcn:955 : no SGSN Context Response from MME"
MME_Tests.ttcn:1572 MME_Tests control part
MME_Tests.ttcn:1457 TC_ue_cell_reselect_eutran_to_geran testcase
If the UE continuously attempts to Attach while changing PDN Type,
it will cause the wrong IP to be assigned.
(e.g PDU-Type : IPv4v6 -> IPv4 -> IPv4v6)
This is because we use two variables at the same time,
one to read and store the Static IP from the Subscriber DB and
one to store the IP assigned from SMF, called session->paa.
When the UE attaches with PDN-Type set to IPv4v6,
MME saves the allocated IP in session->paa.
However, MME thinks it has been assigned a static IP based on the information
in session->paa, so changing the PDN-Type may result in the wrong IP
being assigned.
To solve this problem, I separated the variable(session->paa) that stores
the allocated IP received from SMF and the variable(session->ue_ip) that stores
the Static IP read from the Subscriber DB.
Therefore, the information read from the Subscriber DB
(session->session_type and session->ue_ip) should not be modified.
When using ogs_buffer_to_bcd(), an overflow occurs if the input buffer length
is larger than the output bcd size, causing a crash.
We adjusted the size of the input buffer length using ogs_min as follows.
```
sgwc_ue->imsi_len = ogs_min(imsi_len, OGS_MAX_IMSI_LEN);
memcpy(sgwc_ue->imsi, imsi, sgwc_ue->imsi_len);
ogs_buffer_to_bcd(sgwc_ue->imsi, sgwc_ue->imsi_len, sgwc_ue->imsi_bcd);
```
When we run the test, for example,
./tests/registration/registration simple-init,
wee get an INFO message like the one below.
```
05/17 14:24:03.933: [sbi] INFO: NF EndPoint(addr) setup [127.0.0.200:7777] (../lib/sbi/context.c:474)
```
When we run the code in Open5GS, the log level initially defaults to INFO.
However, for test code, we change the log level to ERROR
by automatically inserting the -e error option into argv.
The reason for this is to prevent WARNING and INFO messages
from appearing when the test code is run.
However, the log level to ERROR is changed at the bottom of
the initialize routine, which caused the above message
to be printed during testing.
To prevent this from being printed, I modified the code
to change that log level to ERROR a little earlier.
The validity time for NF Instances obtained through NF Discovery was
not properly implemented. Since the validity was 3600 seconds(1 hour),
which caused 5G Core to not work properly after 3600 seconds(1 hour).
There was an issue where an NF Instance should be deleted
when its validity time expired, but it was not working correctly
due to incorrect use of reference count.
Therefore, I have modified the Validity of NF Instances obtained
through NF Discovery to work properly.
I also changed the default value of valdityPeriod to 30 seconds.
Fixed not using Reference Count for adding/deleting NF Instances.
Up until now, NF Instances have been managed by referencing the Reference Count.
Initially, when an NF Instance is added, the Reference Count is incremented and
when it is deleted, the Reference Count is decremented.
If a UE discovers another NF Instance through the NF Discovery function,
the Reference Count is incremented. And if a UE de-registers,
the Reference Count of the discovered NF is decremented.
However, there's a problem with this approach.
When other NF is de-registered,
there is no guarantee that it will be 100% notified.
For example, if a UDM is de-registered, but an SCP is de-registered before it,
the AMF will not be notified that the UDM has been de-registered.
In situations where this is not clear, Reference Count cannot be used.
Therefore, we have modified it to not use the Reference Count method.
Also, when a UE connects, it is modified to always search
whether an NF Instance exists by NF Instance ID whenever it is discovered.
To do this, we modified lib/sbi/path.c as shown below.
```diff
@@ -281,13 +281,15 @@ int ogs_sbi_discover_and_send(ogs_sbi_xact_t *xact)
}
/* Target NF-Instance */
- nf_instance = sbi_object->service_type_array[service_type].nf_instance;
+ nf_instance = ogs_sbi_nf_instance_find(
+ sbi_object->service_type_array[service_type].nf_instance_id);
if (!nf_instance) {
nf_instance = ogs_sbi_nf_instance_find_by_discovery_param(
target_nf_type, requester_nf_type, discovery_option);
- if (nf_instance)
- OGS_SBI_SETUP_NF_INSTANCE(
- sbi_object->service_type_array[service_type], nf_instance);
+ if (nf_instance) {
+ OGS_SBI_SETUP_NF_INSTANCE_ID(
+ sbi_object->service_type_array[service_type], nf_instance->id);
+ }
}
```
An assert shall be triggered.
The vulnerable code path is in src/mme/mme-fd-path.c:
```
/* s6a process Subscription-Data from avp */
static int mme_s6a_subscription_data_from_avp(struct avp *avp,
ogs_subscription_data_t *subscription_data,
mme_ue_t *mme_ue, uint32_t *subdatamask)
{
...
/* AVP: 'MSISDN'( 701 )
* The MSISDN AVP is of type OctetString. This AVP contains an MSISDN,
* in international number format as described in ITU-T Rec E.164 [8],
* encoded as a TBCD-string, i.e. digits from 0 through 9 are encoded
* 0000 to 1001; 1111 is used as a filler when there is an odd number
* of digits; bits 8 to 5 of octet n encode digit 2n; bits 4 to 1 of
* octet n encode digit 2(n-1)+1.
* Reference: 3GPP TS 29.329
*/
ret = fd_avp_search_avp(avp, ogs_diam_s6a_msisdn, &avpch1);
ogs_assert(ret == 0);
if (avpch1) {
ret = fd_msg_avp_hdr(avpch1, &hdr);
ogs_assert(ret == 0);
if (hdr->avp_value->os.data && hdr->avp_value->os.len) {
mme_ue->msisdn_len = hdr->avp_value->os.len; /* 1 */
memcpy(mme_ue->msisdn, hdr->avp_value->os.data,
ogs_min(mme_ue->msisdn_len, OGS_MAX_MSISDN_LEN)); /* 2 */
ogs_buffer_to_bcd(mme_ue->msisdn,
mme_ue->msisdn_len, mme_ue->msisdn_bcd); /* 3 */
*subdatamask = (*subdatamask | OGS_DIAM_S6A_SUBDATA_MSISDN);
}
}
```
When NSSF was first implemented, nf-status-notify was not required.
This is because there was no need to be notified
if other NFs were registered or de-registered in the NRF.
However, this situation changed with the addition of SEPP.
NSSFs can be notified whenever a SEPP registers or de-registers an NRF.
Therefore, we added nf-status-notify,
which was not implemented when the NSSF was originally created.
When running the open5gs package with systemd network config, the 1st IP address
of the UE pool configured in open5gs-upfd config file for ogstun is
being assigned to the interface through this file.
That was discussed as being a desirable default setup.
However, in the event a user wants a setup where no IP address is
assigned to the tundev, then it's not enough removing the IP address,
because then the implicit routing rules regarding the subnet of the IP
address added automatically by the kernel are also removed.
This patch adds config sections to set up the routing explicitly, with
the aim to get the routing still applied if the user decides to comment
out the IP address, so that packets are still forwarded properly in that
case.
Related: https://osmocom.org/issues/6361
A friend in the community was trying to connect an SMF made by another
manufacturer with an SBI interface and found a big problem with Open5GS.
All of the code in the part that generates the Resource URI
from HTTP.location is invalid.
For example, suppose we create a Resource URI with SMContext as below.
{apiRoot}/nsmf-pdusession/<apiVersion>/sm-contexts/{smContextRef}
In this case, Open5GS extracted the {smContextRef} part of the HTTP.location
and appended it to the beginning
{apiRoot}/nsmf-pdusession/<apiVersion>/sm-contexts/.
This implementation may not work properly if the apiRoot changes.
Consider a different port number as shown below.
<HTTP.location>
127.0.0.4:9999/nsmf-pdusession/v1/sm-contexts/1
The SMF may send an apiRoot to the AMF with a changed port number,
in which case the AMF must honor it.
Therefore, instead of extracting only the smContextRef from HTTP.location,
we modified it to use the whole thing to create a Resource URI.
We modified all NFs that use HTTP.location in the same way, not just SMFs.
Add an option to disable printing the timestamp. This is useful to not
have duplicate timestamps, when stderr is piped into a logging system
that adds timestamps on its own. For example with systemd's journald:
$ journalctl -u open5gs-smfd
Apr 10 13:25:18 hostname open5gs-smfd[1582]: 04/10 13:25:18.274: [app] INFO: Configuration: '/etc/open5gs/smf.yaml' (../lib/app/ogs-init.c:130)
Configuration change:
```
<OLD Format>
logger:
file: /var/log/open5gs/smf.log
<NEW Format>
logger:
file:
path: /var/log/open5gs/smf.log
```
Example config, to have no timestamps on stderr:
```
logger:
default:
timestamp: false
file:
path: /var/log/open5gs/smf.log
timestamp: true
```
The way subnet is set up has changed as shown below.
```
<OLD Format>
smf:
session:
- subnet: 10.45.0.1/16
<NEW Format>
smf:
session:
- subnet: 10.45.0.0/16
gateway: 10.45.0.1
```
For more information, please refer to Pull Request #2975.
In InitialUEMessage, send a NAS message with a message type
other than Registration Request, Deregistration Request, or Service Request,
the following messages from UE will not be accepted.
We found this issue in not only the initial state but multiple states.
We believe if an attacker has the ability to inject a NAS message to the core,
it can perform a DoS attack on the victim UE.
So, I've fixed that The MME/AMF deletes MME_UE_S1AP_ID/AMF_UE_NGAP_ID,
and will not accept any following messages from the UE.
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.
If a Create Bearer Response occurs after a Delete Bearer Response,
SGW-C crashes.
The execution is stopped by the following ASSERT
because it tries to access the UL Tunnel
deleted by the Delete Bearer Response.
```
03/28 17:28:41.229: [gtp] DEBUG: [7] LOCAL Find GTPv2 peer [172.22.0.9]:2123 (../lib/gtp/xact.c:949)
03/28 17:28:41.229: [gtp] DEBUG: [7] LOCAL Receive peer [172.22.0.9]:2123 (../lib/gtp/xact.c:966)
03/28 17:28:41.229: [gtp] DEBUG: [7] LOCAL UPD RX-96 peer [172.22.0.9]:2123 (../lib/gtp/xact.c:448)
03/28 17:28:41.229: [sgwc] DEBUG: Create Bearer Response (../src/sgwc/s11-handler.c:707)
03/28 17:28:41.229: [gtp] DEBUG: [7] LOCAL Commit peer [172.22.0.9]:2123 (../lib/gtp/xact.c:629)
03/28 17:28:41.230: [gtp] DEBUG: [7] LOCAL Delete peer [172.22.0.9]:2123 (../lib/gtp/xact.c:1149)
03/28 17:28:41.230: [sgwc] FATAL: sgwc_s11_handle_create_bearer_response: Assertion `ul_tunnel' failed. (../src/sgwc/s11-handler.c:802)
03/28 17:28:41.231: [core] FATAL: backtrace() returned 8 addresses (../lib/core/ogs-abort.c:37)
./open5gs-sgwcd(+0x189b7) [0x5b3c92cf09b7]
./open5gs-sgwcd(+0x13c6d) [0x5b3c92cebc6d]
/open5gs/install/lib/x86_64-linux-gnu/libogscore.so.2(ogs_fsm_dispatch+0x113) [0x70600ed63402]
./open5gs-sgwcd(+0x629d) [0x5b3c92cde29d]
/open5gs/install/lib/x86_64-linux-gnu/libogscore.so.2(+0x11754) [0x70600ed54754]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x8609) [0x70600ecfc609]
/lib/x86_64-linux-gnu/libc.so.6(clone+0x43) [0x70600ec21353]
```
To solve this problem, I have modified to handle the exception appropriately,
display the error situation in the Cause of the Create Bearer Response,
and proceed with the execution.
AS shown in 3GPP TS 29.244 C.2.1.1 diagram, the meaning of Threshold
value is different in Diameter Gy and in PFCP interfaces.
In Diameter Gy the value sets the trigger for the "remaining credit",
while in PFCP the value sets the trigger for the "used credit".
ThresholdPFCP = Quota - ThresholdGy
If eg. PCRF or AAA diameter link is not yet ready (eg. PCRF crashed),
and a client sends a CreateSessionRequest announcing its ow F-TEID,
then open5gs-smfd answers with Create Session Response Cause=
"Remote peer not responding", but it is not setting the received F-TEID
in the header of the response, instead it sends with TEI=0.
As a result, the peer cannot match the CreateSessionResponse,
and needs to rely on its own timeout timer to figure out
that specific request failed.
To address this issue, I modified the GTP Response message to check
the Sender F-TEID and send it accordingly, setting the destination TEID
to the value of the Sender F-TEID.
I've made this modification only for SMF, but MME and SGW-C have not done so;
if you need to, you can work from the examples in SMF.
Similarly, the same situation can happen with PFCP. If anyone needs to do this
in the future, I think you can work on it this way.
This is the continuation of commit
12158eebb8, which only checked the code in
CCA[Update], but not in CCA[Initial].
The handling in CCA[Initial] is a bit more complex since depending on
the outcome, we may end up with a Result-Code != SUCCESS in MSCC but the
session may still be created at the OCS because the message Result-Code
= SUCCESS. In that scenario, we want to abort setting up the PDN session
but we still need to make sure we terminate the Gy session that was just
created.
Cause is set according to particular NF standard.
Additionally:
- OGS_SBI_HTTP_STATUS_MEHTOD_NOT_ALLOWED typo fixed.
- [PCF] Fixed SM Policy establishment error handling
First of all, it crashes when creating a Dedicated Bearer
on the default Session that is created for the first time.
This behavior should be possible, so the related ASSERT is removed.
Next, the InitialContextRequest is modified
during the Attach Request to include the first Bearer.
Finally, there was an issue where trying to create a Dedicated Bearer
with SGsAP enabled resulted in an InitialContextSetupRequest message
with a PTI of zero. This is because MME initializes the PTI to 0
upon receiving the Create Bearer Request while processing SGsAP.
All of these issues has been fixed.
Do not attempt to run "systemctl reload" on the open5gs services, unless
they are running. This fixes the logrotate service failing on this
postrotate script, if units are not running or not installed.
1. According to ETSI TS 129 118 4.1, if the Network Access Mode (NAM) is set
to "Packet only," no SGs association should be established.
2. If the NAM is set to "Packet and Circuit," and the SGs association is
rejected by the CS core, this rejection should only impact
the SGs association itself and not result in a UE attach rejection
for a UE with a valid HSS account.
a cryptographic vulnerability in the SUCI decryption routines
of Open5GS 5G—specifically Profile B, which uses P-256 (secp256r1)
for its elliptic curve routines.
If a mobile device user passes a public key within its SUCI
that does not correspond to a valid point on the P-256 elliptic curve,
the Open5GS UDM will not check the point
before running elliptic curve operations with it and returning a response
to the mobile device user.
If the public key is not checked to be a valid point, an attacker can leverage
this behavior to extract the Profile B private key from the UDM,
as has been done in other domains
(https://owasp.org/www-pdf-archive/Practical_Invalid_Curve_Attacks_on_TLS-ECDH_-_Juraj_Somorovsky.pdf).
Note that Profile A is not similarly vulnerable to this, as it is impossible
to construct an invalid point on a curve25519 elliptic curve.
There was some work that went into developing a practical proof of concept
of this kind of attack against free5gc last year; it can be found here:
https://www.gsma.com/security/wp-content/uploads/2023/10/0073-invalid_curve.pdf
And here is the free5gc security advisory:
https://github.com/advisories/GHSA-cqvv-r3g3-26rf
To mitigate this issue in Open5GS, the public key of the UE must be validated
by the UDM prior to use. Adding a validation function such as the following
should work:
I designed this code based on information from https://crypto.stackexchange.com/questions/90151/verify-that-a-point-belongs-to-secp256r1.
'node_timeout' and some other functions can remove a smf_sess_t
while that session is still waiting for a PFCP reply
and has an active PFCP xact.
In this case, xact->data points to the deleted session
and xact's timeout function (sess_5gc_timeout for example)
eventually refers to this already freed session.
This fix prevents duplicate deletes from occurring by checking to see
if the session context has already been deleted when the timeout occurs.
Additionally, it moves session deletions out of timer callbacks into
state machine by reselect_upf().
Due to the way 'ogs_timer_mgr_expire' calls timer callbacks,
one must not stop or expire timers from within a timer callback.
And now one must not remove sessions from within a timer callback.
If eg. PCRF or AAA diameter link is not yet ready (eg. PCRF crashed), and
a client sends a CreateSessionRequest announcing its ow F-TEID,
then open5gs-smfd answers with Create Session Response Cause=
"Remote peer not responding", but it is not setting the received F-TEID
in the header of the response, instead it sends with TEI=0.
As a result, the peer cannot match the CreateSessionResponse, and needs
to rely on its own timeout timer to figure out that specific request failed.
This also happens in PFCP, so to solve this problem, I added teid/seid_presence
to the interface that sends the error message as shown below.
void ogs_gtp2_send_error_message(ogs_gtp_xact_t *xact,
int teid_presence, uint32_t teid, uint8_t type, uint8_t cause_value);
void ogs_pfcp_send_error_message(
ogs_pfcp_xact_t *xact, int seid_presence, uint64_t seid, uint8_t type,
uint8_t cause_value, uint16_t offending_ie_value);
When we try to send an SBI message to SMF to release a session,
sometimes ran_ue is NULL. This happens when the Mobile Reachable Timer expires
and Implicit Deregistration is triggered.
To account for this case, we added the `ran_ue` parameter to the SBI interface
and made it work even if it is NULL.
This AVP is optional and was added in later releases of the 3GPP TS
32.299 spec. For instance, it shows up in Release 16 (V16.2.0), but
doesn't show up in Release 12 (V12.7.0).
Some OCS, like PortaOne OCS, implement older versions of the release
(V12.14.0), and hence fail when receiving the 3GPP-RAT-Type inside
Multiple-Services-Credit-Control AVP.
Since nowadays we also send the 3GPP-RAT-Type in PS-Information AVP,
which has been specified for longer time (it already shows up in
V12.7.0), drop it from Multiple-Services-Credit-Control to have greater
compatibility with other vendors.
* [SBI] Handle and store AMF info
* [SBI] Add "target GUAMI" discovery option
* [SBI] Handle UeContextTransfer request and response messages
* [AMF] Handle NF discovery from AMF to AMF
* [AMF] Add UE Context Transfer Request/Response from AMF to AMF
* [SCP] Handle UeContextTransfer
* Follow-up on #3052
* [AMF] force authentication after 'Ue context transfer' for now
* [AMF] force authentication after 'Ue context transfer' for now
---------
Co-authored-by: Sukchan Lee <acetcom@gmail.com>
This happens for instance when the session is terminated due to a
rejection coming from the OCS, hence no originating GTP xact producing
the tear down.
The xact may well be NULL, eg. when tearin down the session
(send_ccr_termination_req_gx_gy_s6b()) because OCS rejected an update:
Hence there's no GTP xact originating the tear down, aka e->gtp-xact
passed to the function is NULL.
smf_gx_send_ccr() is already handling this case properly, contrary to smf_gf_send_ccr().
When building the MIME Multipart Media Encapsulation format
within an SBI message in the NF of a third-party product,
Open5GS does not parse properly if it contains a Preamble CRLF.
For example,
```
TCP/HTTP2
Stream: Data, Stream ID: 1, Length 841
MIME Multipart Media Encapsulation, Type: multipart/related, Boundary: "gc0pJq08jU534c"
--->Preamble: 0d0a
First boundary: --gc0pJq08jU534c\r\n
Encapsulated multipart part: (application/json)
Boundary: \r\n--gc0pJq08jU534c\r\n
Encapsulated multipart part: (application/vnd.3gpp.5gnas)
Boundary: \r\n--gc0pJq08jU534c\r\n
Encapsulated multipart part: (application/vnd.3gpp.ngap)
Last Boundary: \r\n--gc0pJq08jU534c--\r\n
```
Assume the UE has Attached, the session has been created,
and is in the IDLE state with the UEContextRelease process.
This could result in the following call flow.
1. TAU request without Integrity Protected
2. Authentication request/response
3. Security-mode command/complete
MME can be performed simultaneously by the HSS(S6A) and UE(S1AP).
Update-Location-Request
Service request
Service reject
Delete Session Request
Delete Session Response
Update-Location-Answer
UEContextReleaseCommand for Service reject
TAU reject
UEContextReleaseCommand for TAU reject
UEContextReleaseComplete
UEContextReleaseComplete
MME crashes when UE sends a service request(S1AP) during ULR/ULA(S6A) with HSS,
which has been fixed.
Transaction Identity doesn't map 1-to-1 with Procedure Transaction
Identity: The value ranges change, and PTI cannot use value 0 8which
means unused).
Hence, for now let's simply set the PTI to a valid default value instead
of asserting during mme_sess_add:
Assertion `pti != OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED'
Related: https://github.com/open5gs/open5gs/issues/3020
1. HandoverRequired
2. HandoverRequest
3. HandoverFailure
4. UEContextReleaseCommand
5. HandoverPreparationFailure
If UEContextReleaseComplete is not received,
the Source-UE will have the Target-UE.
6. HandoverRequired
There may be cases where the Source UE has a Target UE
from a previous HandoverRequired process. In this case,
it is recommended to force the deletion of the Target UE information
when receiving a new HandoverRequired.
7. HandoverRequest
8. HandoverFailure
9. UEContextReleaseCommand
10. UEContextReleaseComplete
11. HandoverPreparationFailure
... Crashed ...
For bi-directions, the rules are created in the same form as for downlink
as shown below, so to apply them for uplink, we need to swap the rules
according to the interface.
RX : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
GX : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
PFCP : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
RULE : Source <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> Destination <UE_IP> <UE_PORT>
TFT : Local <UE_IP> <UE_PORT> REMOTE <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT>
RX : permit in from <UE_IP> <UE_PORT> to <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT>
GX : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
PFCP : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
RULE : Source <UE_IP> <UE_PORT> Destination <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT>
TFT : Local <UE_IP> <UE_PORT> REMOTE <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT>
APER encoding fails when using the asn_uint642INTEGER function on a 32-bit machine as shown below.
```C
asn_uint642INTEGER(AMF_UE_NGAP_ID, 0xffffffff);
...
aper_encode_to_buffer(...)
```
INTEGER APER encode/decode functions seem to be operating internally with long variables instead of intmax_t.
That is probably the reason of the failure.
@v0-e fixed this issues in the mouse07410/asn1c pull request.
https://github.com/mouse07410/asn1c/pull/176https://github.com/mouse07410/asn1c/pull/177
When there is no MME-UE Context, going to cleanup without setting
s6a_message could cause a segmentation fault.
We fixed the problem by moving the location of setting s6a_message
to before cleanup.
The UPF is sending Session Report Request after the Session was Deleted,
when the Gy interface is active.
UPF is sending PFCP session report request after the session has been deleted
when the Gy interface is active. This is because some of the timers related to
the report are not deleted when the session is deleted.
We have fixed it to delete all the timers in the session
when the SESSION is deleted.
Problems with Purge-UE-Request/Answer can occur in the following situations
1. Attach Request
2. Authentication request
3. Authentication reject
4. UEContextReleaseCommand
5. UEContextReleaseComplete
6. Purge-UE-Request
7. Attach Request
8. Purge-UE-Answer
9. (UE Context Remove)
To resolve this issue, we have changed to delete the UE-Context
via mme_ue_remove() immediately upon receiving UEContextReleaseComplete()
without calling mme_s6a_send_pur().
1. Reachable assertion in ogs_nas_5gmm_decode
Location: lib/nas/5gs/decoder.c:4445
```c
int ogs_nas_5gmm_decode(ogs_nas_5gs_message_t *message, ogs_pkbuf_t *pkbuf)
{
int size = 0;
int decoded = 0;
ogs_assert(pkbuf);
ogs_assert(pkbuf->data);
ogs_assert(pkbuf->len);
```
When a NAS payload is received over `src/amf/context.c:1675`NGAP that has no data, the ogs_assert(pkbuf->len) assertion will be triggered.
2.Reachable assertion in ogs_nas_emm_decode
```
int ogs_nas_emm_decode(ogs_nas_eps_message_t *message, ogs_pkbuf_t *pkbuf)
{
int size = 0;
int decoded = 0;
ogs_assert(pkbuf);
ogs_assert(pkbuf->data);
ogs_assert(pkbuf->len);
```
Nearly identical to (1), but for LTE.
3. Reachable assertion in nas_eps_send_emm_to_esm
```
int nas_eps_send_emm_to_esm(mme_ue_t *mme_ue,
ogs_nas_esm_message_container_t *esm_message_container)
{
int rv;
ogs_pkbuf_t *esmbuf = NULL;
if (!mme_ue_cycle(mme_ue)) {
ogs_error("UE(mme-ue) context has already been removed");
return OGS_NOTFOUND;
}
ogs_assert(esm_message_container);
ogs_assert(esm_message_container->length);
```
The ESM message payload may be 0-length, as the length is determined by a field in the NAS payload (which can be chosen arbitrarily by an attacker). This leads to the length assertion above being triggered.
5. Reachable assertion and incorrect hash calculation in ogs_kdf_hash_mme
```
void ogs_kdf_hash_mme(const uint8_t *message, uint8_t message_len, uint8_t *hash_mme)
{
uint8_t key[32];
uint8_t output[OGS_SHA256_DIGEST_SIZE];
ogs_assert(message);
ogs_assert(message_len);
ogs_assert(hash_mme);
memset(key, 0, 32);
ogs_hmac_sha256(key, 32, message, message_len,
output, OGS_SHA256_DIGEST_SIZE);
memcpy(hash_mme, output+24, OGS_HASH_MME_LEN);
}
```
When handling NAS attach requests or TAU requests, the ogs_kdf_hash_mme function is passed the NAS payload. However, the length field is represented as an unsigned 8-bit integer, which the passed length of the packet may overflow. This leads to the passed value being truncated.
When the passed value is a multiple of 256, the above assertion (ogs_assert(message_len)) is triggered. Otherwise, the hash is computed on only the first n bits of the message (where n = actual_message_len % 256).
There is an issue with SESSION RELEASE not working properly
depending on the PDU session release complete order
in the PDUSessionResourceReleaseResponse.
If the AMF receives PDUSessionResourceReleaseResponse
followed by PDU session release complete, it works correctly.
However, if it receives PDU session release complete
followed by PDUSessionResourceReleaseResponse, it does not work correctly
and sends an Error Indication to the UE/gNB.
To fix this issue, we added pdu_session_release_complete_received and
pdu_session_resource_release_response_received to the content
so that CLEAR_SM_CONTEXT_REF() is executed when both are received.
Because a race condition can occur between S6A Diameter and S1AP message,
the following error handling code has been added.
1. InitialUEMessage + Attach Request + PDN Connectivity request
2. Authentication-Information-Request/Authentication-Information-Answer
3. Authentication Request/Response
4. Security-mode command/complete
5. Update-Location-Request/Update-Location-Answer
6. Detach request/accept
In the ULR/ULA process in step 6, the PDN Connectivity request is
pushed to the queue as an ESM_MESSAGE because the NAS-Type is still
an Attach Request.
See the code below in 'mme-s6a-handler.c' for where the queue is pushed.
if (mme_ue->nas_eps.type == MME_EPS_TYPE_ATTACH_REQUEST) {
rv = nas_eps_send_emm_to_esm(mme_ue,
&mme_ue->pdn_connectivity_request);
if (rv != OGS_OK) {
ogs_error("nas_eps_send_emm_to_esm() failed");
return OGS_NAS_EMM_CAUSE_PROTOCOL_ERROR_UNSPECIFIED;
}
} else if (mme_ue->nas_eps.type == MME_EPS_TYPE_TAU_REQUEST) {
r = nas_eps_send_tau_accept(mme_ue,
S1AP_ProcedureCode_id_InitialContextSetup);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
} else {
ogs_error("Invalid Type[%d]", mme_ue->nas_eps.type);
return OGS_NAS_EMM_CAUSE_PROTOCOL_ERROR_UNSPECIFIED;
}
If you perform step 7 Detach request/accept here,
the NAS-Type becomes Detach Request and the EMM state changes
to emm_state_de_registered().
Since the PDN, which is an ESM message that was previously queued,
should not be processed in de_registered, the message is ignored
through error handling below.
Otherwise, MME will crash because there is no active bearer
in the initial_context_setup_request build process.
See the code below in 's1ap-build.c' for where the crash occurs.
ogs_list_for_each(&mme_ue->sess_list, sess) {
ogs_list_for_each(&sess->bearer_list, bearer) {
...
if (mme_ue->nas_eps.type == MME_EPS_TYPE_ATTACH_REQUEST) {
} else if (OGS_FSM_CHECK(&bearer->sm, esm_state_inactive)) {
ogs_warn("No active EPS bearer [%d]", bearer->ebi);
ogs_warn(" IMSI[%s] NAS-EPS Type[%d] "
"ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
mme_ue->imsi_bcd, mme_ue->nas_eps.type,
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
continue;
}
...
}
}
As mentioned in the sgwu.yaml configuration file, it is possible to configure multiple addresses with different source_interface values for the gtpu interface.
Following the this section, I defined two addresses, one with source_interface set to 0 and another with source_interface set to 1. My expectation was to see different addresses for the two PDRs in the Session Establishment Response message during session establishment. However, both addresses were the same, and it was the address I had set for source_interface = 0.
When I looked into the code, I found the reason for the issue. In the lib/pfcp/context.c file, on line 1185, the function that determines the address is called as follows:
...
} else {
ogs_gtpu_resource_t *resource = NULL;
resource = ogs_pfcp_find_gtpu_resource(
&ogs_gtp_self()->gtpu_resource_list,
pdr->dnn, OGS_PFCP_INTERFACE_ACCESS);
if (resource) {
...
In the last parameter of this function, a constant value, OGS_PFCP_INTERFACE_ACCESS, is used. This causes every PDR with any source_interface to be considered as "access," and the value 0 is used for its interface.
I replaced the value with pdr->src_if, and the bug was resolved.
A race condition can occur in the following situations.
In conclusion, we can use this situation to determine
whether or not the UE Context has been removed and avoiding a crash.
For example, suppose a UE Context is removed in the followings.
1. Attach Request
2. Authentication-Information-Request
3. Authentication-Information-Answer
4. Authentication Request
5. Authentication Response(MAC Failed)
6. Authentication Reject
7. UEContextReleaseCommand
8. UEContextReleaseComplete
The MME then sends a Purge-UE-request to the HSS and deletes
the UE context as soon as it receives a Purge-UE-Answer.
Suppose an Attach Request is received from the same UE
between Purge-UE-Request/Answer, then the MME and HSS start
the Authentication-Information-Request/Answer process.
This can lead to the following situations.
1. Purge-UE-Request
2. Attach Request
3. Authentication-Information-Request
4. Purge-UE-Answer
5. [UE Context Removed]
6. Authentication-Information-Answer
Since the UE Context has already been deleted
when the Authentication-Information-Answer is received,
it cannot be processed properly.
Therefore, mme_ue_cycle() is used to check
whether the UE Context has been deleted and
decide whether to process or
ignore the Authentication-Information-Answer as shown below.
Instead of checking if caller memset'ted the structure to zero, memset
it inside the function regardless.
There is no added benefit of a memset() + memcmp() to check if caller
cleared the structure used for outputing data from the database.
In an Inter-RAT setup a UE could perform a TAU coming from a 2G/3G network.
In that case the UE/MS is unknown to the MME and it should request the
SGSN context (MM, PDP) from the old SGSN. This is done through the following
GTPv1C message exchange on the Gn interface of SGSN and MME:
SGSN <- MME: SGSN Context Request
SGSN -> MME: SGSN Context Response
SGSN <- MME: SGSN Context Acknowledge
Diagram with full set of steps can be found at 3GPP TS 23.401 D.3.6.
This commit doesn't aim to be a complete implementation of the mentioned
procedure, since it's quite a complex one, with lots of fields and logic
required. This so far only implements in general the minimally
successful case by filling as much as possible the required set of
fields.
This will allow for a base onto which do incremental improvements and
fixes while testing against UEs and SGSNs (such as osmo-sgsn, which
doesn't yet support this procedure but will potentially earn it soon).
The reverse direction, aka UE issuing cell reselection 4G->2G was
already implemented (same as here, initial non-complete implementation)
in open5gs-mmed in commit 3d693da73e.
Related: https://osmocom.org/issues/6294
Within the PathSwitchRequest packet,
the E-RABToBeSwitchedDLList has two bearers.
If the E-RAB-ID of both bearers is 5, the MME's list memory is destroyed
and the MME crashes. To fix this issue, we modified the code so that
the MME can work correctly with invalid S1AP messages.
This will be useful for other procedures where only the RAI is known,
but not the specific CI. This is the case of idle mobility from Gb or Iu
to EUTRAN, where MME needs to request contexts based on the RAI mapped
in the GUTI obtained from the UE during TAU.
This also makes the config more resilient in RIM scenario, where an SGSN
can be picked now even if CI doesn't match, instead of failing or faling
back to the default route SGSN.
While they were continuing their fuzzy testing and developing PacketRusher, an unusual issue with the AMF was observed. The problem arises when a single Ethernet frame containing three bundled SCTP chunks is sent. This behavior is reproduced with PacketRusher when attempting to concurrently register two UEs with the same MSIN.
The expected behavior is that the PDU Session Establishment Accept is sent inside a DownlinkNASTransport to RAN UE NGAP ID 1. However, it is actually sent inside an InitialContextSetupRequest to RAN UE NGAP ID 2. The MAC of this NAS message is invalid for the Security Context of RAN UE NGAP ID 2 (probably valid for RAN UE NGAP ID 1)
When the input string contains a number and a unit too large to be
represented by a 64-bit variable, AMF/SMF would crash due to conversion
resulting in a negative value and unable to be used in compiling NAS-PDU
container.
Now the value gets clipped at int64_t maximum value.
Failed to encode ASN-PDU [-1] (../lib/asn1c/util/message.c:42)
../lib/core/ogs-list.h:62:24: warning: invalid conversion from 'void*' to 'ogs_list_t*' {aka 'ogs_list_s*'} [-fpermissive]
../lib/core/ogs-rbtree.h:79:32: warning: invalid conversion from 'const void*' to 'const ogs_rbnode_t*' {aka 'const ogs_rbnode_s*'} [-fpermissive]
[SBI] Fix compiler error - possible uninitialized variable
[SCP] Fix compiler error - Error: this condition has identical branches
In case of additional compiler warnings turned on, the compiler warns
about potentially unused variables. Fix those issues.
Both types are defined under lib/proto/type.h, and the conversion
function is used in several different protocols, so let's better move it
to generic lib/proto/conv.h and remove the "gtp2" prefix.
The assert is checking for sess->session->name, but afterwards there's a
check to skip ses->session not being null, which means the assert can
crash while dereferencing sess->session.
I've resolved an issue where sending continuous
'PDU Session Release Request' message to the same session,
when more than two sessions were created, was causing an SMF crash.
For your reference, this problem did not occur
when only one session was created.
In an Inter-RAT setup a UE could perform a RAU coming from a 4G network.
In that case the UE/MS is unknown to the SGSN and it should request the
SGSN context (MM, PDP) from the MME. This is done through the following
GTPv1C message exchange on the Gn interface of SGSN and MME:
SGSN -> MME: SGSN Context Request
SGSN <- MME: SGSN Context Response
SGSN -> MME: SGSN Context Acknowledge
This commit doesn't aim to be a complete implementation of the mentioned
procedure, since it's quite a complex one, with lots of fields and logic
required. This so far only implements in general the minimally
successful case by filling as much as possible the required set of
fields.
This will allow for a base onto which do incremental improvements and
fixes while testing against UEs and SGSNs (such as osmo-sgsn, which
doesn't yet support this procedure but will potentially earn it soon).
This commit doesn't implement the reverse direction, aka UE issuing cell
reselection 2G->4G. Initial support for this scenario will hopefully be
added soon as a follow-up patch, similar to this one.
Related: https://osmocom.org/issues/6294
As per TS 29.060:
The Initial/request message is "SGSN Context Request", sent by peer A.
Peer B sends a response message "SGSN Context Response" with same SeqNr.
Peer A sends a response message "SGSN Context Acknowledge" with same
SeqNr.
If Peer B doesn't see a "SGSN Context Acknowlegde", it should keep
retransmitting "SGSN Context Response" as usual.
In an Inter-RAT setup a UE could perform a RAU coming from a 4G network.
In that case the UE/MS is unknown to the SGSN and it should request the
SGSN context (MM, PDP) from the MME. This is done through the following
GTPv1C message exchange on the Gn interface of SGSN and MME:
SGSN -> MME: SGSN Context Request
SGSN <- MME: SGSN Context Response
SGSN -> MME: SGSN Context Acknowledge
This commit doesn't aim to be a complete implementation of the mentioned
procedure, since it's quite a complex one, with lots of fields and logic
required. This so far only implements in general the minimally
successful case by filling as much as possible the required set of
fields.
This will allow for a base onto which do incremental improvements and
fixes while testing against UEs and SGSNs (such as osmo-sgsn, which
doesn't yet support this procedure but will potentially earn it soon).
This commit doesn't implement the reverse direction, aka UE issuing cell
reselection 2G->4G. Initial support for this scenario will hopefully be
added soon as a follow-up patch, similar to this one.
Related: https://osmocom.org/issues/6294
This information will be required by the Gn interface in MME when
answering an SGSN with an "SGSN Context Response" message during MS cell
reselection EUTRAN->GERAN.
* [AMF/MME] UEContextReleaseCommand in Integrity (#2786)
Modified not to send UEContextReleaseCommand in Integrity Unprotected
NAS message such like Registration or Service request.
* [AMF/MME] UEContextReleaseCommand after Interity Protected (#2786)
Modified not to send UEContextReleaseCommand in Integrity Unprotected
NAS message such like Registration or Service request.
* Update 03-VoLTE-dockerized.md
adding "-" in docker-compose commands and added filename t the docker-compose command
* Adding up command to docker-compose
Need to bring docker images up to run the Open5Gs system.
Allow network operators to omit the time zone in the 4G EMM Information
and 5G Configuration Update. This is useful for better compatibility
with some UEs.
The parameter is optional according to:
* 4G: 3GPP TS 24.301 Table 8.2.13.1
* 5G: 3GPP TS 24.501 Table 8.2.19.1.1
Bug:
In case that AMF does not have subscription data for the UE,
PDU session remains unreleased after implicit de-registeration.
The exact test case:
- UE registered (integrity protection applied)
- UE deregistered (Nudm_SDM_Unsubscribe, Nudm_UECM_Registration (purgeFlag))
- UE registered, PDU session activated
UE data are still stored in AMF. So if integrity protected applies,
the steps 4 - 14 [ETSI TS 123 502 V16.7.0](https://www.etsi.org/deliver/etsi_ts/123500_123599/123502/16.07.00_60/ts_123502v160700p.pdf) are skipped.
Only AM Policy Association Establishment is performed.
- UE is moved out of radio coverage, 2 x (4 min + Timer t3512) expires
Result: UE is implicitly de-registered, PDU session is not released
The steps of implicit de-registeration:
1. Implicit Timer Expiration
2. UDM_SDM_Unsubscribe
3. UDM_UECM_Deregistration
4. PDU session release request
5. PDUSessionResourceReleaseCommand + PDU session release command
6. PDUSessionResourceReleaseResponse
7. AM_Policy_Association_Termination
So PDU session release is performed after the confirmation of
UDM_UECM_Deregistration.
Since there is no UDM_SDM subscription, the UDM steps are skipped
and PDU session is not released.
Fix:
If the AMF does not have subscription data for the UE which registers,
the AMF registers with the UDM using Nudm_UECM_Registration and
retrieves subscription data with Nudm_SDM_Get.
[ETSI TS 123 502 V16.7.0](https://www.etsi.org/deliver/etsi_ts/123500_123599/123502/16.07.00_60/ts_123502v160700p.pdf), 4.2.2.2.2 General Registration, 14a-c:
> If the AMF does not have subscription data for the UE, the AMF retrieves the Access and Mobility Subscription data, SMF
> Selection Subscription data, UE context in SMF data and LCS mobile origination using Nudm_SDM_Get.
1. UE sends RegistrationRequest to AMF.
2. AMF sends Nudm_UECM_Registration to UDM.
3. UE sends RegistrationRequest to AMF.
4. GMM state is gmm_state_authentication
5. UDM sends Nudm_UECM_Registration response to AMF.
6. AMF crashs since no Handler in gmm_state_authentication state
According to 3GPP TS 29.510, the search parameter "tai" should be a
single item, not an array of items.
TS 29.510: Table 6.2.3.2.3.1-1:
URI query parameters supported by the GET method on this resource
Revert "[SBI] Change discovery option TAI from array to single item"
This reverts commit b4beff1ae16c64b3c6d84d8bdb47c36e19b705f2.
wip
This problem can be occurred in the following scenarios.
1. Run NFs(NRF/SCP/SMF/UPF/AUSF/UDM/PCF/BSF/NSSF/UDR) except AMF.
2. Run AMF
3. Run gNB/UE and try to register
4. STOP PCF
5. AMF Crashed
AMF discovered the PCF through SCP during the UE registration process.
At this time, ogs_sbi_nf_fsm_init() is not called,
so AMF does not have state information about PCF.
In other words, AMF state is NULL.
In such a situation, when PCF is terminated at this time,
a crash occurs as AMF attempts to change the PCF state.
So, I've fixed that state information is initialized to solve this problem.
This commit splits filling Requested-Service-Unit, Used-Service-Unit and
QoS-Information into their own helper functions for better readibility,
and then partially reverts 125740727e,
where lots of AVPs were left out of INITIAL_REQUEST messagesi during the
changes made.
After looking through 3GPP TS 32.299 and rfc4006, it seems expected to
send Requested-Service-Unit only during INITIAL_REQUEST, and
Used-Service-Unit during UPDATE_REQUEST, so that part is kept.
However, I am not able to find clear indications that AVPs such as QoS
Information and RAT-Type should not be sent during INITIAL_REQUEST.
So, since we have the info, better set it already during
INITIAL_REQUEST, since the OCS may want to grant different resources
based on that information if available too.
* [AUSF] Fix removing UE context on authentication removal request
AUSF crashed when trying to access ausf_ue->sm fields after they were
already deleted.
* [AMF] Delete UE authentication result after UE deregisters from 5G core
Based on TS 29.509 - 5.2.2.2.5 Authentication Result Removal with 5G AKA
method:
In the case that the Purge of subscriber data in AMF after the UE
deregisters from the network or the NAS SMC fails following the
successful authentication in the registration procedure, the NF Service
Consumer (AMF) requests the AUSF to inform the UDM to remove the
authentication result.
* [SBI] Ignore unknown enum values and continue parsing (#2622)
* [SBI] Reject empty enum lists (#2622)
Enum lists that are empty due to ignoring
unsupported enum values are also rejected.
* Revert changing `generator.sh`
amf_ue->mac_failed flag to be cleared during security mode procedure but it was not.
At this point, the only way to cleare the amf_ue->mac_failed flag is by UE Context Release.
But I'd like to connect UEs as fast as possible without UE Context Release.
* Add "subscriber_status" cmd to open5gs-dbctl to set values for
"subscriber_status" and "operator_determined_barring" DB fields.
* Add webui View+Edit for those same fields.
* open5gs-hssd now takes those values into account and submits
Operator-Determined-Barring AVP with DB-retrieved value if
subscriber_status is set to OPERATOR_DETERMINED_BARRING.
For more information, see TS 29.272 section 5.2.2.1.3 and 7.3.30.
Tests were crashing due to AF using the wrong OpenAPI structure, while
the SBI library tried to convert a different structure to JSON.
Before the added support for nullable fields in OpenAPI documents, both
structures were identical.
Depending on the OpenAPI yaml files, fields can be marked as "nullable".
Which means that the field can be either present, not present, or null.
This feature is important for example in SmContextUpdateData structure,
where many fields are described similar as the following:
This IE shall be included for the modification .... For deleting the
field, it shall contain the Null value.
currently if no IP address is available from the configured
subnets in the SMF when attempting to assign an IP to an UE
we assert and the SMF crashes. Handle the error more gracefully
by returning an error cause instead.
Open5GS documentation instructs to install into open5gs.git/install/
during build [1]:
"""
$ cd open5gs
$ meson build --prefix=`pwd`/install
$ ninja -C build
"""
As a result, this directory appears all the time when using git, since
it's not in the .gitignore file. Add it.
[1] https://open5gs.org/open5gs/docs/guide/02-building-open5gs-from-sources/
> Using external babel configuration
> Location: "/tmp/open5gs-2.6.5/webui/.babelrc"
> Failed to build on /tmp/fdd1769d-9793-45ac-a613-b20e09756073
Error: commons.js from UglifyJs
Name expected [commons.js:8066,6]
at /tmp/open5gs-2.6.5/webui/node_modules/next/dist/server/build/index.js:182:21
at /tmp/open5gs-2.6.5/webui/node_modules/webpack/lib/Compiler.js:269:13
at Compiler.emitRecords (/tmp/open5gs-2.6.5/webui/node_modules/webpack/lib/Compiler.js:375:38)
at /tmp/open5gs-2.6.5/webui/node_modules/webpack/lib/Compiler.js:262:10
at /tmp/open5gs-2.6.5/webui/node_modules/webpack/lib/Compiler.js:368:12
at next (/tmp/open5gs-2.6.5/webui/node_modules/tapable/lib/Tapable.js:218:11)
at Compiler.<anonymous> (/tmp/open5gs-2.6.5/webui/node_modules/webpack/lib/performance/SizeLimitsPlugin.js:99:4)
at Compiler.applyPluginsAsyncSeries1 (/tmp/open5gs-2.6.5/webui/node_modules/tapable/lib/Tapable.js:222:13)
at Compiler.afterEmit (/tmp/open5gs-2.6.5/webui/node_modules/webpack/lib/Compiler.js:365:9)
at /tmp/open5gs-2.6.5/webui/node_modules/webpack/lib/Compiler.js:360:15 {
errors: [ 'commons.js from UglifyJs\nName expected [commons.js:8066,6]' ],
warnings: []
}
Error executing command, exiting
After the page remains inactive for 10 minutes,
clicking on the edit page will result in a blank screen
when you click on edit after 10 minutes,
all user data is lost. After capturing the network packets,
it can be observed that the frontend sends a fresh request
to the backend for data, and the backend responds correctly,
but the page does not refresh correctly.
`function recent(fetchedAt) {
if (fetchedAt === null) return false;
const interval = 10 * 60 * 1000; // 10 minutes
return ((Date.now() - interval) < fetchedAt);
}`
j
The crash is caused by ogs_assert(data) in listEntry_create(void *data).
Reason for the failing assertion is that in
OpenAPI_subscription_data_t *OpenAPI_subscription_data_parseFromJSON(
cJSON *subscription_dataJSON)
in line 501 of file subscription_data.c the event string is transformed
into an integer/enum value, which in case of an unknown event is 0.
Steps to reproduce:
1. Deploy NRF
2. Run curl --http2-prior-knowledge --header "Content-Type: application/json" --data '{"nfStatusNotificationUri": "test@example.com", "reqNotifEvents": ["unknown"], "subscriptionId": "12345"}' "http://<NRF_IP>:<NRF_PORT>/nnrf-nfm/v1/subscriptions"
There was a memory problem in the encryption using snow_3g_f8,
so AMF/MME crashed.
To solve this problem, we used the snow-3g encryption library
created as below.
https://github.com/rcatolino/libressl-snow3g
However, it seems that this library cannot be used to create
integrity hash like snow_3g_f8.
So, we decided to keep both snow-3g libraries for the time being.
1. lib/crypt/snow3g* : for INTEGRITY (NIA1, EIA1)
2. lib/crypt/openssl/snow3g* : for ENCRYPTION (NEA1, EEA1)
Scenario is handover on S1AP, data forwarding is enabled, and
the Source ENB is forwarding DL PDCP packets to EPC(SGWU)
with PDCP SN included. SGWU is also forwarding these packets
to the Target ENB.
However the PDCP SN is not present in the forwarded packets
from SGWU to Target ENB.
I modified this part, and there was the same problem in 5GC, fixed it as well.
A lot of code in GTP-U has been modified,
so if you have any problems, please let us know right away.
curl --noproxy '*' --http2-prior-knowledge -X POST --header "Content-Type: multipart/related" --data-binary @pdu http:/192.168.29.231:7777/nsmf-pdusession/v1/sm-contexts
Attaching file 'pdu'
SMF crashes as not able to decode the message properly. SmContextCreateData is not accessible.
After examining the call stack and reading the source code, I found that
in /lib/core/ogs-pool.h line 152: (pool)->array[i] = i+1;
then in lib/pfcp/context.c line 78: pdr_random_to_index[ogs_pfcp_pdr_teid_pool.array[i]] = i;
ogs_pfcp_pdr_teid_pool.array[i] may exceed the size of pdr_random_to_index, leading to a heap-buffer-overflow.
Modifications were made to resolve the following assertion..
Invalid HNET PKI Value [0] (../lib/sbi/conv.c:135)
ogs_supi_from_supi_or_suci: Expectation `supi' failed. (../lib/sbi/conv.c:262)
udm_ue_add: Assertion `udm_ue->supi' failed. (../src/udm/context.c:144)
backtrace() returned 8 addresses (../lib/core/ogs-abort.c:37)
A situation in which you establish two sessions and release both of them.
In the first SESSION, the UE normally sent PDUSessionResourceReleaseResponse
and PDU session release complete. However, these were not sent when releasing
the second SESSION.
At this point, when the UE tried to do a deregistration,
the SMF was not properly handling the exception.
I've just fixed this.
After the UE performs Registration/Attach, SQN field is created.
If we edit subscriber information when SQN value is present, WebUI crash occurs.
It is because the way to handle Long Type(SQN:Long) is different
when the mongoose version is 6 or higher.
To avoid this crash, we use the mongoose version down to 5.x first.
Whether or not to send a Setting ACK is determined by the nghttp2 library.
Therefore, when nghttp2 informs us that it want to send an SETTING frame
with ACK by nghttp2_session_want_write(), we need to call session_send()
directly to send it.
NAS, GTP, PFCP, SBI, all except S1AP/NGAP use x1000 multiplier for Kbps, Mbps, Gbps ... etc.
From now on in WebUI all units also use a multiplier of x1000.
Based on the standard document below, when the UE is in the IDLE state,
we checked the implicit timer and tried to send a message to the UE,
but it doesn't work properly.
So, first of all, I deleted the related code.
- TS 24.301 Ch 5.3.7
If ISR is not activated, the network behaviour upon expiry of
the mobile reachable timer is network dependent, but typically
the network stops sending paging messages to the UE on the
first expiry, and may take other appropriate actions
- TS 24.501 Ch 5.3.7
The network behaviour upon expiry of the mobile reachable timer is network dependent,
but typically the network stops sending paging messages to the UE on the first expiry,
and may take other appropriate actions.
Move the config to the sgsn node instead of having a specific route with
specific format "default: route", since anyway internally it's already
applied to the sgsn object.
When AMF release the NAS signalling connection,
ran_ue context is removed by ran_ue_remove() and
amf_ue/ran_ue is de-associated by amf_ue_deassociate().
In this case, implicit deregistration is attempted
by the mobile reachable timer according to the standard document,
and amf_ue will be removed by amf_ue_remove().
TS 24.501
5.3.7 Handling of the periodic registration update timer and
Start AMF_TIMER_MOBILE_REACHABLE
mobile reachable timer
The network supervises the periodic registration update procedure
of the UE by means of the mobile reachable timer.
If the UE is not registered for emergency services,
the mobile reachable timer shall be longer than the value of timer
T3512. In this case, by default, the mobile reachable timer is
4 minutes greater than the value of timer T3512.
The mobile reachable timer shall be reset and started with the
value as indicated above, when the AMF releases the NAS signalling
connection for the UE.
The 'data' struct used to specify the diameter dispatch options for the
MME callbacks was not being initialized properly, which meant that the
App id could contain garbage. This was preventing the callbacks from
being invoked when receiving ISD/CLR requests.
The RAN INFORMATION RELAY message has no associated response, and hence
it should not start T3-RESPONSE timer to retrigger retransmissions.
TS 29.060 11.1:
"The Error Indication, Version Not Supported, RAN Information Relay,
Supported Extension Headers Notification and the SGSN Context Acknowledge
messages shall be considered as Responses for the purpose of this clause"
TS 29.060 7.5.14.1:
"For handling of protocol errors the RAN Information Relay message is treated as a
Response message."
Add CIFuzz workflow action to have fuzzers build and run on each PR.
This service is offered by OSS-Fuzz where open5gs already runs. CIFuzz can help
catch regressions and fuzzing build issues early, and has a variety of features
(see the URL above). In the current PR the fuzzers gets build on a pull request
and will run for 300 seconds.
Signed-off-by: David Korczynski <david@adalogics.com>
Each SMF's NfProfile can contain multiple SmfInfo items. The issue was
that AMF checked only the first SmfInfo for correct S-NSSAI/NR-TAI
information.
In case of a 5G core setup with SMF handling 2 or more slices, and UE
trying to establish multiple PDU sessions, AMF would report an error
when trying to find the correct serving SMF.
[amf] ERROR: [1:0] (NF discover) No [nsmf-pdusession] (../src/amf/nnrf-handler.c:85)
Since [redesign](8553c77733)
of fivegs_smffunction_sm_sessionnbr gauge, the metric doesn't
expose some decrements. The decreasing of gauge had been
moved out of function stats_remove_smf_session.
It should be decreased every time stats_remove_smf_session
is called, but this particular case is easily reproducible
by killing UPF while the session is established.
The current code uses the cc request number as an index to the
transaction array (xact/xact_data). Since cc request number is a 32 bit
integer this is unfeasible for longer sessions and if more than a
handful of messages are exchanged per session.
The array size was already increased in #2038 which simply delays the
issue.
Furthermore, the current code asserts that cc_request_number is <=
MAX_CC_REQUEST_NUMBER which leads to an out-of-bounds write if
cc_request_number == MAX_CC_REQUEST_NUMBER.
Instead use a smaller array and index into it using cc_request_number
% array size. More than 2 requests should never be in flight at any one
time (initial or update request together with a termination request) so
an array size of 4 should be fine.
- have a more consistent naming among the NF's
- always have the same prefix (amf_/smf_/pcf_) depending on the NF
- function name is always the same, how the function calculates the load
is NF specific and internal to the function itself (but not the function
name).
- the 'if' clause was comparing some value with an always '1' due to
wrong calculation. Consequently, this 'if' statement never executed.
- sizes for session pool and UE pools are directly linked between each
other. We need to count the number of items only in one of the pools to
correctly represent the NF load
- if anything, we should also check the load of the application pool to
determine correct load of the NF
When converting bitrates from bits per second to kilobits per second,
if the conversion results in fractions, the resulting value should be
rounded upwards
The improved algorithm better handles some odd bitrates.
With the current version, the bitrates 63 Kbps and 65 Kbps would get
converted into 48 Kbps (unit 16 Kbps x 3) and 64 Kbps (unit 64 Kbps x
1).
Especially in the first case, the conversion error is quite signicant.
Current version tries to find the biggest 'unit', while the 'value' is
still above 0.
With the updated version, the algorithm tries to find the 'unit' low
enough, that the resulting 'value' can still fit into the 16-bit space
without overflow.
From the OpenAPI document,TS29571_CommonData.yaml : BitRate
String representing a bit rate; the prefixes follow the standard symbols from The International
System of Units, and represent x1000 multipliers, with the exception that prefix "K" is
used to represent the standard symbol "k".
ogs_pool_init() shall be used in the initialization routine.
Otherwise, memory will be fragment since this function uses system malloc()
Compared with ogs_pool_init()
ogs_pool_create() could be called while the process is running,
so this function should use ogs_malloc() instead of system malloc()
Multimedia-Auth-Answer and Server-Assignment-Answer
defines the AVP User-Name as mandatory. It must also be
present on failure cases.
See 3GPP TS 29.273 Rel 17.
Signed-off-by: Alexander Couzens <lynxis@fe80.eu>
[ETSI TS 128 552 V16.9.0](https://www.etsi.org/deliver/etsi_ts/128500_128599/128552/16.09.00_60/ts_128552v160900p.pdf):
Registration type label is not provided.
A nonstandard PLMNID label is added to achieve uniqueness.
- 5.3.1.3 Number of PDU sessions requested to be created by the SMF
PLMNID and SNSSAI are defined during PDU session creation processing.
Some requests can be rejected during processing before label values are known.
Those requests are not counted under particular labels.
To count also such requests, the basic metric with empty labels is exposed too.
```
fivegs_smffunction_sm_pdusessioncreationreq{plmnid="",snssai=""} 1
fivegs_smffunction_sm_pdusessioncreationreq{plmnid="00101",snssai="1000009"} 1
```
- 5.3.1.4 Number of PDU sessions successfully created by the SMF
```
fivegs_smffunction_sm_pdusessioncreationsucc{plmnid="00101",snssai="1000009"} 1
```
- 5.3.1.5 Number of PDU sessions failed to be created by the SMF
```
fivegs_smffunction_sm_pdusessioncreationfail{cause="400"} 1
```
Example for one successful and one failed (during creation processing) PDU session creation:
```
fivegs_smffunction_sm_pdusessioncreationreq{plmnid="",snssai=""} 2
fivegs_smffunction_sm_pdusessioncreationreq{plmnid="00101",snssai="1000009"} 1
fivegs_smffunction_sm_pdusessioncreationsucc{plmnid="00101",snssai="1000009"} 1
fivegs_smffunction_sm_pdusessioncreationfail{cause="400"} 1
```
The Open5GS project takes security vulnerabilities seriously.
If you believe you have discovered a security issue in Open5GS, please report it privately and avoid public disclosure until the issue has been reviewed and addressed.
Please report vulnerabilities privately using GitHub's "Report a vulnerability" button under the Security tab (Security → Advisories → Report a vulnerability). This opens a private advisory visible only to the maintainers.
When reporting a vulnerability, please include:
* Description of the issue
* Affected version(s)
* Steps to reproduce
* Proof of concept, if available
* Potential impact
## Scope
This policy covers security vulnerabilities in the source code of the
open5gs/open5gs repository, including the network function implementations and
the bundled WebUI.
The following are generally considered out of scope:
* Vulnerabilities in third-party software or dependencies
* Issues caused by deployment or configuration choices outside Open5GS
* Reports generated only by automated scanners without demonstrated impact
* Theoretical issues without a realistic threat model or attack scenario
## Supported Versions
Users are encouraged to use the latest stable release of Open5GS.
Security fixes are generally applied to actively maintained versions.
## Responsible Disclosure
Please allow maintainers reasonable time to investigate and address reported vulnerabilities before public disclosure.
The Open5GS project appreciates responsible and coordinated vulnerability disclosure.
@ -27,4 +27,8 @@ If you're contributing through a pull request to Open5GS project on GitHub, plea
## License
- Open5GS Open Source files are made available under the terms of the GNU Affero General Public License ([GNU AGPL v3.0](https://www.gnu.org/licenses/agpl-3.0.html)).
- [Commercial licenses](https://open5gs.org/open5gs/support/) are also available from [NeoPlane](https://neoplane.io/)
- [Commercial licenses](https://open5gs.org/open5gs/support/) are also available from [NewPlane](https://newplane.io/) at [sales@newplane.io](mailto:sales@newplane.io).
## Support
Technical support and customized services for Open5GS are provided by [NewPlane](https://newplane.io/) at [support@newplane.io](mailto:support@newplane.io).