Skip to content

[LTS 8.6] nfsd: CVE-2026-31402#1223

Open
pvts-mat wants to merge 1 commit into
ctrliq:ciqlts8_6from
pvts-mat:CVE-2026-31402_ciqlts8_6
Open

[LTS 8.6] nfsd: CVE-2026-31402#1223
pvts-mat wants to merge 1 commit into
ctrliq:ciqlts8_6from
pvts-mat:CVE-2026-31402_ciqlts8_6

Conversation

@pvts-mat
Copy link
Copy Markdown
Contributor

[LTS 8.6]

CVE-2026-31402 VULN-180161

Commits

nfsd: fix heap overflow in NFSv4.0 LOCK replay cache

jira VULN-180161
cve CVE-2026-31402
commit-author Jeff Layton <jlayton@kernel.org>
commit 5133b61aaf437e5f25b1b396b14242a6bb0508e2
upstream-diff Used `post_err_offset' instead of `op_status_offset +
  XDR_UNIT' in the `read_bytes_from_xdr_buf()' call, as the LTS 8.6
  version is missing ef3675b45bcb6c17cabbbde620c6cea52ffb21ac ("NFSD:
  Encode COMPOUND operation status on page boundaries")

The changes are the same as in rocky8_10 for the buildable kernel 9b906d0, compare with

git log --pretty=oneline --patch-with-stat -n 1 9b906d0e7b3e34897f09fe4dcb3f4a439510cabe -- fs/nfsd/nfs4xdr.c fs/nfsd/state.h

They are the same, in turn, as the solutions for LTS 9.2 and and LTS 9.4. Unlike in the LTS 9.2 solution the fixes for CVE-2025-40324 and CVE-2023-53241 were not included because they don't apply cleanly - too high hanging fruits to get for their worth.

kABI check: passed

[0/1] kabi_check_kernel	Check ABI of kernel [ciqlts8_6-CVE-2026-31402]	_kabi_check_kernel__x86_64--test--ciqlts8_6-CVE-2026-31402
ninja explain: output state/kernels/ciqlts8_6-CVE-2026-31402/x86_64/kabi_checked doesn't exist
ninja explain: state/kernels/ciqlts8_6-CVE-2026-31402/x86_64/kabi_checked is dirty
+ dist_git_version=el-8.6
+ local_version=ciqlts8_6-CVE-2026-31402
+ arch=x86_64
+ user=pvts
+ buildmachine=x86_64--build--ciqlts8_6
+ virsh_timeout=600
+ ssh_daemon_wait=20
+ src_dir=/mnt/code/kernel-dist-git-el-8.6
+ build_dir=/mnt/build_files/kernel-src-tree-ciqlts8_6-CVE-2026-31402
+ sudo chmod +x /data/src/ctrliq-github-haskell/kernel-dist-git-el-8.6/SOURCES/check-kabi
+ ninja-back/virssh.xsh --max 8 --shutdown-on-success --shutdown-on-failure --timeout 600 --ssh-daemon-wait 20 pvts x86_64--build--ciqlts8_6 ''\''/mnt/code/kernel-dist-git-el-8.6/SOURCES/check-kabi'\'' -k '\''/mnt/code/kernel-dist-git-el-8.6/SOURCES/Module.kabi_x86_64'\'' -s '\''/mnt/build_files/kernel-src-tree-ciqlts8_6-CVE-2026-31402/Module.symvers'\'''
kABI check passed
+ touch state/kernels/ciqlts8_6-CVE-2026-31402/x86_64/kabi_checked

Boot test: passed

boot-test.log

Kselftests: passed relative

Reference

kselftests–ciqlts8_6–run1.log
kselftests–ciqlts8_6–run2.log

Patch

kselftests–ciqlts8_6-CVE-2026-31402–run1.log
kselftests–ciqlts8_6-CVE-2026-31402–run2.log

Comparison

The tests results for the reference and the patch are the same.

$ ktests.xsh diff -d kselftests*.log

Column    File
--------  ----------------------------------------------
Status0   kselftests--ciqlts9_2--run1.log
Status1   kselftests--ciqlts9_2--run2.log
Status2   kselftests--ciqlts9_2-CVE-2026-31402--run1.log
Status3   kselftests--ciqlts9_2-CVE-2026-31402--run2.log

tests-comparison.txt

jira VULN-180161
cve CVE-2026-31402
commit-author Jeff Layton <jlayton@kernel.org>
commit 5133b61
upstream-diff Used `post_err_offset' instead of `op_status_offset +
  XDR_UNIT' in the `read_bytes_from_xdr_buf()' call, as the LTS 8.6
  version is missing ef3675b ("NFSD:
  Encode COMPOUND operation status on page boundaries")

The NFSv4.0 replay cache uses a fixed 112-byte inline buffer
(rp_ibuf[NFSD4_REPLAY_ISIZE]) to store encoded operation responses.
This size was calculated based on OPEN responses and does not account
for LOCK denied responses, which include the conflicting lock owner as
a variable-length field up to 1024 bytes (NFS4_OPAQUE_LIMIT).

When a LOCK operation is denied due to a conflict with an existing lock
that has a large owner, nfsd4_encode_operation() copies the full encoded
response into the undersized replay buffer via read_bytes_from_xdr_buf()
with no bounds check. This results in a slab-out-of-bounds write of up
to 944 bytes past the end of the buffer, corrupting adjacent heap memory.

This can be triggered remotely by an unauthenticated attacker with two
cooperating NFSv4.0 clients: one sets a lock with a large owner string,
then the other requests a conflicting lock to provoke the denial.

We could fix this by increasing NFSD4_REPLAY_ISIZE to allow for a full
opaque, but that would increase the size of every stateowner, when most
lockowners are not that large.

Instead, fix this by checking the encoded response length against
NFSD4_REPLAY_ISIZE before copying into the replay buffer. If the
response is too large, set rp_buflen to 0 to skip caching the replay
payload. The status is still cached, and the client already received the
correct response on the original request.

Fixes: 1da177e ("Linux-2.6.12-rc2")
	Cc: stable@kernel.org
	Reported-by: Nicholas Carlini <npc@anthropic.com>
	Tested-by: Nicholas Carlini <npc@anthropic.com>
	Signed-off-by: Jeff Layton <jlayton@kernel.org>
	Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
(cherry picked from commit 5133b61)
	Signed-off-by: Marcin Wcisło <marcin.wcislo@conclusive.pl>
@pvts-mat pvts-mat force-pushed the CVE-2026-31402_ciqlts8_6 branch from 142428d to 0efc019 Compare May 13, 2026 21:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant