Bug 2478979 (CVE-2026-85977) - CVE-2026-85977 libtirpc: libtirpc: Denial of Service via unbounded memory allocation during portmapper response decoding
Summary: CVE-2026-85977 libtirpc: libtirpc: Denial of Service via unbounded memory all...
Keywords:
Status: NEW
Alias: CVE-2026-85977
Product: Security Response
Classification: Other
Component: vulnerability
Version: unspecified
Hardware: All
OS: Linux
medium
medium
Target Milestone: ---
Assignee: Product Security DevOps Team
QA Contact:
URL:
Whiteboard:
Depends On: 2554146
Blocks:
TreeView+ depends on / blocked
 
Reported: 2026-05-18 03:51 UTC by OSIDB Bzimport
Modified: 2026-10-16 15:10 UTC (History)
18 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed:
Embargoed:


Attachments (Terms of Use)

Description OSIDB Bzimport 2026-05-18 03:51:35 UTC
AI_ONLY_REPORT
package: libtirpc-1.3.7-2.1.hum1
------
Summary: Unbounded pmaplist decoding can cause memory exhaustion (DoS):  
attacker-controlled `PMAPPROC_DUMP` replies can drive unbounded decode-time  
allocation in `xdr_pmaplist()` and exhaust memory or CPU in the client  
process.
Requirements to exploit: An attacker must be able to make a libtirpc  
consumer call `pmap_getmaps()` against an attacker-controlled host, or  
otherwise supply the `PMAPPROC_DUMP` response on that path. No  
authentication or post-request user interaction is required, but the  
vulnerable client-side portmapper path must be used by the consuming  
application.
Component affected: `libtirpc-1.3.7-2.1.hum1` portmapper/XDR decode path in  
`src/pmap_prot2.c` (`xdr_pmaplist()`), reachable from `src/pmap_getmaps.c`  
(`pmap_getmaps()`)
Version affected: `libtirpc-1.3.7-2.1.hum1`, when the `pmap_getmaps()` /  
`PMAPPROC_DUMP` client decode path is exercised
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:H/PR:N/UI:N/S:U/C:N/I:N/A:H - 5.9 (MEDIUM)
AV:N - The malicious `PMAPPROC_DUMP` response is delivered over the  
network to a client using `pmap_getmaps()`.
AC:H - Exploitation depends on the victim using this specific client  
path against an attacker-controlled or spoofed endpoint; once that  
precondition holds, the payload is straightforward.
PR:N - No authentication is required.
UI:N - No additional user interaction is required after the vulnerable  
request is made.
S:U - The impact is limited to the vulnerable client process and its  
resources.
C:N - No confidentiality impact is established by the available evidence.
I:N - No integrity impact is established by the available evidence.
A:H - A long attacker-controlled list can consume substantial memory and  
CPU, causing the client to hang, fail allocation, or be terminated.
Impact: Moderate. This is a real availability issue, but the available  
evidence supports a usage-dependent client-side path rather than a broadly  
exposed server path in the package itself. Under Red Hat's severity  
guidance, that makes the issue less broadly exploitable than the typical  
remote DoS cases rated Important, and there is no evidence of  
confidentiality, integrity, or system-compromise impact.
Embargo: no
Reason: This is an availability-only flaw in a client-side,  
usage-dependent path with straightforward short-term mitigations, so  
immediate public handling appears appropriate.
Acknowledgement: Aisle Research
Vulnerability Details: `pmap_getmaps()` uses `xdr_pmaplist()` to decode  
`PMAPPROC_DUMP` replies. In `xdr_pmaplist()`, loop termination depends  
entirely on the decoded `more_elements` value, and no maximum node count or  
byte budget is enforced:
```c
for (; {
more_elements = (bool_t)(*rp != NULL);
if (! xdr_bool(xdrs, &more_elements))
return (FALSE);
if (! more_elements)
return (TRUE);
if (! xdr_reference(xdrs, (caddr_t *)rp,
(u_int)sizeof(struct pmaplist), (xdrproc_t)xdr_pmap))
return (FALSE);
rp = (freeing) ? next : &((*rp)->pml_next);
}
```
During `XDR_DECODE`, `xdr_reference()` allocates a new `struct pmaplist`  
node whenever the pointer is `NULL`:
```c
case XDR_DECODE:
*pp = loc = (caddr_t) mem_alloc(size);
if (loc == NULL) {
warnx("xdr_reference: out of memory");
return (FALSE);
}
memset(loc, 0, size);
break;
```
This makes both allocation count and decode work peer-controlled. A  
responder that keeps sending `more_elements=TRUE` with additional `struct  
pmap` records can force repeated allocations until the client slows  
significantly, fails allocation, or is killed for resource exhaustion. The  
available transport code does not show a total decode budget in this path;  
the receive timeout is applied per read/poll cycle, so continued input can  
continue to drive work.
Steps to reproduce:
1. Build or use a libtirpc consumer with the portmapper client path enabled  
and create a small client that calls `pmap_getmaps()` against a host you  
control.
2. Run a malicious or mock rpcbind/portmapper service on TCP/111 that  
returns a valid `PMAPPROC_DUMP` reply body containing many repetitions of  
`bool TRUE` followed by one `struct pmap` record, with a final `bool FALSE`  
only after a very long list or not until resource exhaustion is reached.
3. Observe client memory and CPU consumption while the reply is decoded  
through `xdr_pmaplist()`.
4. Increase the number of returned elements; the client eventually becomes  
slow, fails allocation, or is terminated by the OOM killer.
5. As a validation step, add a local decode cap and confirm the same  
payload is rejected quickly.
Mitigation: Until a fix is available, avoid calling `pmap_getmaps()`  
against untrusted or attacker-influenced endpoints. If this functionality  
is required, add a local maximum node or allocation budget for  
`xdr_pmaplist()` decoding, or isolate the caller so failure only affects a  
constrained helper process.
Proposed Fix: Add an explicit decode-time limit for the number of  
`pmaplist` nodes accepted by `xdr_pmaplist()`, and fail decoding once the  
limit is exceeded.
```diff
diff --git a/src/pmap_prot2.c b/src/pmap_prot2.c
— a/src/pmap_prot2.c
+++ b/src/pmap_prot2.c
@@ -38,6 +38,10 @@
#include <rpc/xdr.h>
#include <rpc/pmap_prot.h>
+#ifndef PMAPLIST_DECODE_MAX_NODES
+#define PMAPLIST_DECODE_MAX_NODES 1024U
+#endif
+
bool_t
xdr_pmaplist(XDR *xdrs, struct pmaplist **rp)
{
@@ -53,6 +57,7 @@ xdr_pmaplist(XDR *xdrs, struct pmaplist **rp)
bool_t more_elements;
int freeing;
struct pmaplist *next = NULL; / pacify gcc */
+       u_int decoded_nodes = 0;
freeing = (xdrs->x_op == XDR_FREE);
@@ -67,6 +72,12 @@ xdr_pmaplist(XDR *xdrs, struct pmaplist **rp)
if (! more_elements)
return (TRUE);
+               if (xdrs->x_op == XDR_DECODE) {
+                       if (++decoded_nodes > PMAPLIST_DECODE_MAX_NODES) {
+                               return (FALSE);
+                       }
+               }
+
if (freeing)
next = &((*rp)->pml_next);
if (! xdr_reference(xdrs, (caddr_t *)rp,
```
------
This report was generated using AI technology. Always review AI-generated  
content prior to use


Note You need to log in before you can comment on or make changes to this bug.