CVE-2026-89551 PUBLISHED

SUNRPC: xdr_buf_trim: clamp buf->len to avoid underflow

Assigner: Linux
Reserved: 11.09.2026 Published: 11.09.2026 Updated: 13.09.2026

In the Linux kernel, the following vulnerability has been resolved:

SUNRPC: xdr_buf_trim: clamp buf->len to avoid underflow

xdr_buf_trim() trims len bytes from the tail of an xdr_buf by walking the tail, pages, and head iovecs. Each per-section step uses min_t() so it never removes more bytes than that section holds, but the final accounting at the fix_len label subtracts the total bytes actually consumed from buf->len without any clamp:

<pre>fix_len: buf->len -= (len - trim); </pre>

When the caller has set buf->len to a value smaller than the sum of the iov_lens, (len - trim) can exceed buf->len and the unsigned subtraction wraps to near UINT_MAX. gss_krb5_unwrap_v2() reaches xdr_buf_trim() in exactly that state:

<pre>buf->head[0].iov_len -= GSS_KRB5_TOK_HDR_LEN + headskip; buf->len = len - (GSS_KRB5_TOK_HDR_LEN + headskip); xdr_buf_trim(buf, ec + GSS_KRB5_TOK_HDR_LEN + tailskip); </pre>

buf->len is a small wire-derived value while the iov_lens are at page scale, so the per-section loops legitimately consume far more bytes than buf->len records. The wrapped buf->len then propagates as the authoritative stream bound into every downstream XDR decoder.

Fix by clamping the decrement so buf->len bottoms out at zero:

<pre>buf->len -= min_t(unsigned int, buf->len, len - trim); </pre>

On the normal path where the iov_lens sum to buf->len, (len - trim) is always <= buf->len and the result is identical to before. No callers change behavior outside the underflow case.

Metrics

CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CVSS Score: 9.8

AV:N - xdr_buf_trim() is reached from nfsd RPCSEC_GSS privacy unwrap on TCP/2049 (svcauth_gss_unwrap_priv → gss_unwrap → gss_krb5_unwrap_v2) and from the NFS client's gss_unwrap_resp_priv() on every krb5p reply, so a remote NFS peer delivers the wrap token over the network. AC:L - A peer holding the GSS session keys can encrypt a RFC 4121 wrap token so that after decrypt, buf->len is a small wire-derived value while iov_lens remain page-scale; xdr_buf_trim() then subtracts more than buf->len and wraps, with no race or layout outside attacker control. PR:N - A malicious or compromised NFS server that already shares a krb5p GSS context needs no account or capability on the victim client; ordinary krb5p replies and NFSv4.0 GSS callbacks are processed without local privileges on that host. UI:N - Once a krb5p NFS mount exists, the client unwraps every privacy-protected reply and NFSv4.0 GSS callback with no further mount, click, or open; idle revalidations and server-driven callbacks are sufficient. S:U - The wrapped buf->len and subsequent XDR decode run in the host kernel that processed the RPC and do not cross a VM, IOMMU, or sandbox boundary. C:H - The underflowed buf->len (~UINT_MAX) becomes the authoritative stream bound, and on nfsd xdr->nwords also underflows via saved_len - buf->len, so later xdr_read_pages/xdr_shrink_bufhead and NFS XDR decoders read far past the receive buffer into adjacent kernel memory. I:H - xdr_shrink_bufhead() calls xdr_buf_head_shift_right() with a near-UINT_MAX length derived from the wrapped buf->len, and garbage xdr_stream_pos values can index the svc pages[] array out of bounds, an out-of-bounds write exploitable for control-flow hijacking. A:H - Those unbounded XDR copies and the inconsistent xdr_buf (wrapped length versus iov_lens) oops or panic nfsd or the NFS client, and the peer can repeat the request at will.

Product Status

Vendor Linux
Product Linux
Versions Default: unaffected
  • affected from 4c190e2f913f038c9c91ee63b59cd037260ba353 to e6267cccd7b05cc514e57f2160aa8db85f5c2701 (excl.)
  • affected from 4c190e2f913f038c9c91ee63b59cd037260ba353 to ad0cce80d4af2f74674e8b635d97aa3880e83da8 (excl.)
  • affected from 4c190e2f913f038c9c91ee63b59cd037260ba353 to 85e9602650e9df07190abe817cee3b4d9bc3df17 (excl.)
  • affected from 4c190e2f913f038c9c91ee63b59cd037260ba353 to 3f491306dcb673ff5e78e1044ba450c58978774e (excl.)
Vendor Linux
Product Linux
Versions Default: affected
  • Version 3.9 is affected
  • unaffected from 0 to 3.9 (excl.)
  • unaffected from 6.12.109 to 6.12.* (incl.)
  • unaffected from 6.18.50 to 6.18.* (incl.)
  • unaffected from 7.2.4 to 7.2.* (incl.)
  • unaffected from 7.3-rc1 to * (incl.)

References