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
```
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
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.
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).
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.
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.
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