Fedora Account System
Red Hat Associate
Red Hat Customer
AI_ONLY_REPORT package: krb5-1.21.3-8.el10_0 ------ Summary: Authenticated Memory Exhaustion and Leak in RPCSEC_GSS Unwrapping (`xdr_rpc_gss_unwrap_data`): authenticated RPCSEC_GSS DATA requests can supply oversized XDR lengths that trigger large pre-verification allocations and leave some decode-failure allocations unreleased, enabling repeatable memory exhaustion and denial of service. Requirements to exploit: A remote attacker needs network reachability to a deployed service using this SRPM's GSSRPC unwrap path, a valid RPCSEC_GSS security context accepted by that service, and the ability to send oversized or truncated wrapped RPC arguments. Component affected: `krb5` library code in `src/lib/rpc/authgss_prot.c:xdr_rpc_gss_unwrap_data` via `xdr_rpc_gss_buf`, with the allocation behavior in `src/lib/rpc/xdr.c:xdr_bytes` Version affected: `krb5-1.21.3-8.el10_0` when deployed with a service that accepts authenticated `RPCSEC_GSS_DATA` requests through the GSSRPC unwrap path Patch available: no released package fix established; proposed patch included below Version fixed: unknown Upstream coordination: Not notified. CVSS: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H - 6.5 (MEDIUM) AV:N - The issue is reachable over the network against a service exposing the RPCSEC_GSS unwrap path. AC:L - Once authenticated, the attack is straightforward: send oversized XDR lengths and a malformed or incomplete wrapped body. PR:L - A valid RPCSEC_GSS context is required. UI:N - No user interaction is needed. S:U - The impact is confined to the targeted service process. C:N - No confidentiality impact is established by the available evidence. I:N - No integrity impact is established by the available evidence. A:H - Large allocations plus unreleased buffers on some decode failures can exhaust memory and deny service. Impact: Important. Where this RPCSEC_GSS path is exposed, an authenticated remote client can directly compromise availability by forcing repeated high-memory allocations and leak-driven growth in the service process. This aligns with Red Hat's Important category for remote denial of service; the authentication requirement and lack of demonstrated confidentiality or integrity impact keep it below Critical. Embargo: no Reason: The issue requires valid RPCSEC_GSS credentials and exposure of a vulnerable RPCSEC_GSS service, and the demonstrated impact is denial of service rather than code execution or privilege escalation. Acknowledgement: Aisle Research Vulnerability Details: `xdr_rpc_gss_unwrap_data` decodes attacker-controlled wrapped buffers with `maxsize = (unsigned int)-1` for both integrity and privacy services. That value is then passed into `xdr_bytes`, which allocates memory directly from the wire length before MIC verification or unwrap validation completes. ```c if (svc == RPCSEC_GSS_SVC_INTEGRITY) { /* Decode databody_integ. */ if (!xdr_rpc_gss_buf(xdrs, &databuf, (unsigned int)-1)) { log_debug("xdr decode databody_integ failed"); return (FALSE); } /* Decode checksum. */ if (!xdr_rpc_gss_buf(xdrs, &wrapbuf, (unsigned int)-1)) { gss_release_buffer(&min_stat, &databuf); log_debug("xdr decode checksum failed"); return (FALSE); } /* Verify checksum and QOP. */ maj_stat = gss_verify_mic(&min_stat, ctx, &databuf, &wrapbuf, &qop_state); free(wrapbuf.value); if (maj_stat != GSS_S_COMPLETE || qop_state != qop) { gss_release_buffer(&min_stat, &databuf); log_status("gss_verify_mic", maj_stat, min_stat); return (FALSE); } } else if (svc == RPCSEC_GSS_SVC_PRIVACY) { /* Decode databody_priv. */ if (!xdr_rpc_gss_buf(xdrs, &wrapbuf, (unsigned int)-1)) { log_debug("xdr decode databody_priv failed"); return (FALSE); } ``` ```c if (! xdr_u_int(xdrs, sizep)) { return (FALSE); } nodesize = *sizep; if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) { return (FALSE); } /* now deal with the actual bytes */ switch (xdrs->x_op) { case XDR_DECODE: if (nodesize == 0) { return (TRUE); } if (sp == NULL) { *cpp = sp = (char *)mem_alloc(nodesize); } ``` Because `maxsize` is effectively `UINT_MAX` in this call path, the `nodesize > maxsize` check does not provide a practical bound. The allocation happens before `gss_verify_mic()` or `gss_unwrap()`, and some decode-error exits return `FALSE` without releasing every buffer that may already have been allocated. Repeated malformed or incomplete authenticated requests can therefore grow process RSS over time and deny service. The available evidence supports an availability issue; no direct confidentiality or integrity impact was established. Steps to reproduce: 1. Start a service using this GSSRPC code path with RPCSEC_GSS enabled over TCP, for example an administration service using the GSSRPC server path. 2. Establish a valid RPCSEC_GSS context as an authenticated client. 3. Send an `RPCSEC_GSS_DATA` request with `gc_proc = RPCSEC_GSS_DATA` and `gc_svc = RPCSEC_GSS_SVC_INTEGRITY` or `RPCSEC_GSS_SVC_PRIVACY`. 4. Set the wrapped `databuf` or `wrapbuf` XDR length prefix to a large value, such as `64 MB` or larger. 5. Trigger decode failure after allocation by sending a malformed or incomplete wrapped body and closing the connection, then repeat the request. 6. Observe process RSS increasing over time, followed by service degradation or denial of service. Mitigation: Until a code fix is available, restrict network exposure of services that use this RPCSEC_GSS unwrap path to trusted authenticated principals and apply conservative service memory limits where possible. Existing connection-count controls can reduce concurrent amplification, but they do not prevent serial memory growth because allocation occurs before MIC or unwrap verification. Proposed Fix: A minimal patch is below. It introduces a bounded unwrap size and adds cleanup in decode-failure branches that can leave `wrapbuf` allocated. The bound can also be made configurable or tied to transport policy. ```diff diff --git a/src/lib/rpc/authgss_prot.c b/src/lib/rpc/authgss_prot.c — a/src/lib/rpc/authgss_prot.c +++ b/src/lib/rpc/authgss_prot.c @@ -46,6 +46,9 @@ #include <gssapi/gssapi.h> #endif +/* Upper bound for decoded wrapped RPCSEC_GSS payloads. */ +#define RPCSEC_GSS_MAX_UNWRAP (16U * 1024U * 1024U) + bool_t xdr_rpc_gss_buf(XDR *xdrs, gss_buffer_t buf, u_int maxsize) { @@ -202,13 +205,18 @@ xdr_rpc_gss_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, if (svc == RPCSEC_GSS_SVC_INTEGRITY) { /* Decode databody_integ. */ - if (!xdr_rpc_gss_buf(xdrs, &databuf, (unsigned int)-1)) { + if (!xdr_rpc_gss_buf(xdrs, &databuf, RPCSEC_GSS_MAX_UNWRAP)) { log_debug("xdr decode databody_integ failed"); return (FALSE); } /* Decode checksum. */ - if (!xdr_rpc_gss_buf(xdrs, &wrapbuf, (unsigned int)-1)) { + if (!xdr_rpc_gss_buf(xdrs, &wrapbuf, RPCSEC_GSS_MAX_UNWRAP)) { gss_release_buffer(&min_stat, &databuf); + if (wrapbuf.value != NULL) + free(wrapbuf.value); log_debug("xdr decode checksum failed"); return (FALSE); } @@ -225,7 +233,10 @@ xdr_rpc_gss_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, } else if (svc == RPCSEC_GSS_SVC_PRIVACY) { /* Decode databody_priv. */ - if (!xdr_rpc_gss_buf(xdrs, &wrapbuf, (unsigned int)-1)) { + if (!xdr_rpc_gss_buf(xdrs, &wrapbuf, RPCSEC_GSS_MAX_UNWRAP)) { + if (wrapbuf.value != NULL) + free(wrapbuf.value); log_debug("xdr decode databody_priv failed"); return (FALSE); } ``` ------ This report was generated using AI technology. Always review AI-generated content prior to use
Tracker filed for rhel-10.3: https://issues.redhat.com/browse/RHEL-189011