Bug 2478986 (CVE-2026-90996)
| Summary: | CVE-2026-90996 sssd: sssd: Denial of Service in NSS responder via crafted zero-length requests | ||
|---|---|---|---|
| Product: | [Other] Security Response | Reporter: | OSIDB Bzimport <bzimport> |
| Component: | vulnerability | Assignee: | Product Security DevOps Team <prodsec-dev> |
| Status: | NEW --- | QA Contact: | |
| Severity: | medium | Docs Contact: | |
| Priority: | medium | ||
| Version: | unspecified | CC: | akhatavk, aos-team-art-private, asdas, dpaolell, jdelft, jupierce, lgarciaa, mbiarnes, ppalepu, ppostler, prdhamdh, rhel-process-autobot, security-response-team, sghai, sidsharm, suppawar, vlaad, watson-tool-maintainers |
| Target Milestone: | --- | Keywords: | Security |
| Target Release: | --- | ||
| Hardware: | All | ||
| OS: | Linux | ||
| Whiteboard: | |||
| Fixed In Version: | Doc Type: | --- | |
| Doc Text: |
A flaw was found in sssd. A local unprivileged user could send a specially crafted request with a zero-length body to the Network Security Services (NSS) responder. This could lead to a denial-of-service condition, causing the NSS responder to become unstable or terminate. This vulnerability affects the availability of the system responder.
|
Story Points: | --- |
| Clone Of: | Environment: | ||
| Last Closed: | Type: | --- | |
| Regression: | --- | Mount Type: | --- |
| Documentation: | --- | CRM: | |
| Verified Versions: | Category: | --- | |
| oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |
| Cloudforms Team: | --- | Target Upstream Version: | |
| Embargoed: | |||
AI_ONLY_REPORT package: sssd-2.12.0-1.el10 ------ Summary: Local DoS Risk in NSS Responder Due to Zero-Length Request Body Underflow: crafted header-only NSS requests can force `blen == 0` in parsers that inspect `body[blen - 1]`, and if the final header byte is `'\0'` the path can continue into `sss_utf8_check(body, SIZE_MAX)`, creating a local denial-of-service condition in the NSS responder. Requirements to exploit: Ability to run code as a local unprivileged user on a system where the NSS responder is enabled and reachable through its UNIX socket, and to send a crafted 16-byte request to an affected parser such as `SSS_NSS_GETPWNAM`. Component affected: `sssd-2.12.0-1.el10`; NSS responder request parsing in `src/responder/nss/nss_protocol.c` (`sss_nss_protocol_parse_name`, `sss_nss_protocol_parse_svc_name`, `sss_nss_protocol_parse_svc_port`, `sss_nss_protocol_parse_cert`, and `sss_nss_protocol_parse_sid`) Version affected: `sssd-2.12.0-1.el10` when the NSS responder is enabled and reachable through its local UNIX socket Patch available: no released package fix established; proposed patch included below Version fixed: unknown Upstream coordination: Not yet established. CVSS: CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L - 3.9 (LOW) AV:L - Exploitation requires local access to the host and the NSS responder UNIX socket. AC:L - A single crafted 16-byte header-only request is sufficient to reach the vulnerable parsing path. PR:N - No prior privileges are required if the local user can connect to the responder socket. UI:N - No user interaction is needed. S:U - The impact is limited to the NSS responder within the same security scope. C:N - No confidentiality impact was demonstrated. I:N - No integrity impact was demonstrated. A:L - The demonstrated outcome is local responder instability or termination; broader or reliably repeatable impact was not established from the available evidence. Impact: Moderate. A local unprivileged user can affect availability of a system responder with a simple malformed request, which fits Red Hat's Moderate category for flaws that can still cause some availability compromise under constrained conditions. It does not fit Important or Critical because no remote attack path, privilege gain, confidentiality impact, or integrity impact was established. Embargo: no Reason: The issue is local-only, the demonstrated impact is limited to denial of service in the NSS responder, and the fix is a small validation change. Acknowledgement: Aisle Research Vulnerability Details: In `src/responder/nss/nss_protocol.c`, multiple NSS request parsers obtain the request body and immediately test `body[blen - 1]` without first ensuring that `blen` is non-zero. The `SSS_NSS_GETPWNAM` path reaches `sss_nss_protocol_parse_name()`, and similar logic appears in `sss_nss_protocol_parse_svc_name()`, `sss_nss_protocol_parse_svc_port()`, `sss_nss_protocol_parse_cert()`, and `sss_nss_protocol_parse_sid()`. ```c ... sss_packet_get_body(pctx->creq->in, &body, &blen); /* If not terminated fail. */ if (body[blen - 1] != '\0') { DEBUG(SSSDBG_CRIT_FAILURE, "Body is not null terminated!\n"); return EINVAL; } /* If the body isn't valid UTF-8, fail */ if (!sss_utf8_check(body, blen - 1)) { DEBUG(SSSDBG_CRIT_FAILURE, "Body is not UTF-8 string!\n"); return EINVAL; } ... ``` `sss_packet_get_body()` derives the body length directly from the packet length: ```c void sss_packet_get_body(struct sss_packet *packet, uint8_t **body, size_t *blen) { *body = packet->buffer + SSS_PACKET_BODY_OFFSET; *blen = sss_packet_get_len(packet) - SSS_NSS_HEADER_SIZE; } ``` A header-only request with `len == SSS_NSS_HEADER_SIZE` therefore yields `blen == 0`. In that case, the first `body[blen - 1]` access reads the last byte of the packet header rather than necessarily moving outside the packet allocation. However, if that header byte is `'\0'`, `sss_nss_protocol_parse_name()` continues into `sss_utf8_check(body, blen - 1)` with `blen - 1 == SIZE_MAX`, creating an effectively unbounded UTF-8 validation read. Based on the available evidence, that is sufficient for a realistic local denial of service against the NSS responder, while broader memory corruption or confidentiality/integrity impact was not established. Steps to reproduce: 1. Ensure SSSD is running with the NSS responder enabled and identify the NSS socket, commonly `/var/lib/sss/pipes/nss`. 2. Connect to that UNIX socket as an unprivileged local user. 3. Send a 16-byte header-only request using a command that reaches `sss_nss_protocol_parse_name()`, such as `SSS_NSS_GETPWNAM (0x0011)`, with `len = 16`, `status = 0`, and `reserved = 0`. 4. Observe the responder under ASan, Valgrind, or equivalent crash monitoring. The parse path reaches `body[blen - 1]` with `blen == 0` and may continue into large-length UTF-8 validation. 5. Repeating the crafted request can destabilize or terminate the NSS responder process. ```python import socket, struct sock = "/var/lib/sss/pipes/nss" # adjust if needed hdr = struct.pack("<IIII", 16, 0x0011, 0, 0) # len, cmd, status, reserved s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) s.connect(sock) s.sendall(hdr) try: print(s.recv(4096)) except Exception as e: print("recv error:", e) s.close() ``` Mitigation: The demonstrated attack path requires local access to the NSS responder UNIX socket. Environments that do not expose that socket to untrusted local users are not exposed to the demonstrated path. Where operationally acceptable, disabling the NSS responder until a fixed package is available removes the vulnerable surface. Proposed Fix: Add an explicit `blen == 0` check before any `body[blen - 1]` access in the affected NSS parsers. ```diff diff --git a/src/responder/nss/nss_protocol.c b/src/responder/nss/nss_protocol.c index 0000000..0000000 100644 — a/src/responder/nss/nss_protocol.c +++ b/src/responder/nss/nss_protocol.c @@ -112,6 +112,11 @@ sss_nss_protocol_parse_name(struct cli_ctx *cli_ctx, const char **_rawname) sss_packet_get_body(pctx->creq->in, &body, &blen); + if (blen == 0) { + DEBUG(SSSDBG_CRIT_FAILURE, "Body is empty!\n"); + return EINVAL; + } + if (body[blen - 1] != '\0') { DEBUG(SSSDBG_CRIT_FAILURE, "Body is not null terminated!\n"); return EINVAL; @@ -270,6 +275,11 @@ sss_nss_protocol_parse_svc_name(struct cli_ctx *cli_ctx, sss_packet_get_body(pctx->creq->in, &body, &blen); + if (blen == 0) { + DEBUG(SSSDBG_CRIT_FAILURE, "Body is empty!\n"); + return EINVAL; + } + if (body[blen - 1] != '\0') { DEBUG(SSSDBG_CRIT_FAILURE, "Body is not null terminated\n"); return EINVAL; @@ -326,6 +336,11 @@ sss_nss_protocol_parse_svc_port(struct cli_ctx *cli_ctx, sss_packet_get_body(pctx->creq->in, &body, &blen); + if (blen == 0) { + DEBUG(SSSDBG_CRIT_FAILURE, "Body is empty!\n"); + return EINVAL; + } + if (body[blen - 1] != '\0') { DEBUG(SSSDBG_CRIT_FAILURE, "Body is not null terminated\n"); return EINVAL; @@ -372,6 +387,11 @@ sss_nss_protocol_parse_cert(struct cli_ctx *cli_ctx, sss_packet_get_body(pctx->creq->in, &body, &blen); + if (blen == 0) { + DEBUG(SSSDBG_CRIT_FAILURE, "Body is empty!\n"); + return EINVAL; + } + if (body[blen - 1] != '\0') { DEBUG(SSSDBG_CRIT_FAILURE, "Body is not null terminated\n"); return EINVAL; @@ -416,6 +436,11 @@ sss_nss_protocol_parse_sid(struct cli_ctx *cli_ctx, sss_packet_get_body(pctx->creq->in, &body, &blen); + if (blen == 0) { + DEBUG(SSSDBG_CRIT_FAILURE, "Body is empty!\n"); + return EINVAL; + } + if (body[blen - 1] != '\0') { DEBUG(SSSDBG_CRIT_FAILURE, "Body is not null terminated\n"); return EINVAL; ``` ------ This report was generated using AI technology. Always review AI-generated content prior to use