CVE-2026-31694: Verified Repro With Script Download
CVE-2026-31694: Linux kernel FUSE readdir cache out-of-bounds write
CVE-2026-31694 is verified against the affected target. Vulnerability class: Privilege Escalation. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00221.
What Is CVE-2026-31694?
CVE-2026-31694 is a high-severity out-of-bounds write in the Linux kernel's FUSE readdir cache, in fs/fuse/readdir.c, that lets a malicious FUSE server overflow a page-cache page by 24 bytes. Pruva reproduced it (reproduction REPRO-2026-00221).
CVE-2026-31694 Severity & CVSS Score
CVE-2026-31694 is rated high severity, with a CVSS base score of 7.8 out of 10.
High — serious impact or readily exploitable. Prioritize remediation.
How to Reproduce CVE-2026-31694
pruva-verify REPRO-2026-00221 curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00221/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for CVE-2026-31694
- reached the target end-to-end
- full exploit chain demonstrated
- on the real production code path
- high confidence
- the upstream fix blocks the same trigger
malicious FUSE server READDIR reply with namelen=4095 and payload root::0:0:x:.:\n#######
- uid 1000 FUSE daemon
- getdents64
- fuse_readdir_uncached
- fuse_emit
- fuse_add_dirent_to_cache
- memcpy oversized dirent into readdir cache page
- /etc/passwd page-cache first line changed
reproduction_steps.sh A malicious FUSE daemon can trigger the same oversized-dirent readdir-cache overflow through FUSE_READDIRPLUS by returning a direntplus record whose embedded dirent has namelen=4095. The alternate path reproduces on the vulnerable module but is blocked by the tested sink-level reclen > PAGE_SIZE fix, so it is not a fi…
How the agent worked
Root Cause and Exploit Chain for CVE-2026-31694
CVE-2026-31694 is an out-of-bounds write in the Linux kernel FUSE readdir cache. A malicious userspace FUSE daemon can return a FUSE_READDIR entry with a server-controlled namelen=4095; the kernel serializes this as a 4120-byte directory entry and copies it into a single 4096-byte readdir cache page. The missing reclen > PAGE_SIZE validation lets the final 24 bytes spill into the next physical page. In this run, the vulnerability was reproduced end-to-end in a QEMU guest using the real Linux kernel/FUSE code path, and the exploit chain was extended beyond KASAN-visible corruption: an unprivileged uid 1000 process changed the page-cache contents of a root-owned, read-only /etc/passwd file to a passwordless-root line. A fixed fuse.ko negative control rejected the oversized dirent and left /etc/passwd unchanged.
- Package/component affected: Linux kernel FUSE subsystem, specifically
fs/fuse/readdir.cin the readdir cache path (fuse_add_dirent_to_cache()). - Affected versions: The issue is reachable after the FUSE name length increase to
PATH_MAX - 1/ 4095, reported for Linux v6.16 through v7.0-rc and affected stable branches before the fix. - Risk level and consequences: High. A local attacker able to run a malicious FUSE daemon can obtain a constrained but attacker-controlled 24-byte overwrite into an adjacent physical page. When groomed onto a page-cache page for a privileged file such as
/etc/passwd, the primitive bypasses filesystem write permissions and can produce local privilege escalation semantics.
Impact Parity
- Disclosed/claimed maximum impact: Unprivileged local privilege escalation via page-cache corruption of
/etc/passwd. - Reproduced impact from this run: Full local privilege-escalation primitive. The script boots a non-sanitized kernel in QEMU, uses the real FUSE kernel path, drops the exploit process to uid/gid 1000 before attacker-controlled
READDIRreplies and target corruption, verifies direct writes to/etc/passwdfail withRead-only file system, then shows/etc/passwdpage-cache contents changed fromroot:x:0:0:root:/root:/bin/shtoroot::0:0:x:.:. Two vulnerable attempts succeeded, and two fixed negative-control attempts left/etc/passwdunchanged. - Parity:
full. - Not demonstrated: The proof stops after demonstrating the root-level page-cache corruption effect. It does not spawn an interactive root shell, but the demonstrated primitive is the disclosed LPE mechanism: an unprivileged attacker changes the trusted cached contents of a root-owned passwd file to a passwordless-root entry without write permission.
Root Cause
fuse_add_dirent_to_cache() computes a serialized FUSE dirent size from a FUSE-server-controlled name length and copies that many bytes into a single page-cache page. The vulnerable logic only checks whether the record fits in the remaining space of the current page and, if not, advances to a fresh page with offset zero. It does not reject a record whose serialized length is larger than one page.
Conceptually, the vulnerable flow is:
size_t reclen = FUSE_DIRENT_SIZE(dirent); // 4120 for namelen=4095
...
offset = size & ~PAGE_MASK;
if (offset + reclen > PAGE_SIZE) {
index++;
offset = 0;
}
...
memcpy(addr + offset, dirent, reclen); // copies 4120 bytes into 4096-byte page
For namelen=4095, FUSE_DIRENT_ALIGN(24 + 4095) is 4120. At offset=0, the kernel still performs memcpy(..., 4120) into a 4096-byte page, spilling 24 bytes into the next physical page. The exploit controls those trailing bytes and uses page allocator grooming to place the first page of /etc/passwd in the adjacent page frame.
The fix is to reject oversized dirents before adding them to the readdir cache, e.g. by adding a guard equivalent to:
if (reclen > PAGE_SIZE)
return;
The ticket identifies upstream fix commit 51a8de6c50bf947c8f534cd73da4c8f0a13e7bed (fuse: reject oversized dirents in page cache). The reproduction script builds the vulnerable module without this guard and the fixed module with this guard as the negative control.
Reproduction Steps
- Run
bundle/repro/reproduction_steps.shfrom the repository workspace, or run it withPRUVA_ROOT=/path/to/bundle. - The script:
- Reuses the prepared Linux source/build cache when available.
- Builds a non-sanitized Linux kernel and vulnerable
fuse.kofrom the real source. - Builds a fixed
fuse.kowith thereclen > PAGE_SIZEguard. - Builds
bundle/repro/fuse_passwd_lpefrombundle/repro/fuse_passwd_lpe.c, a public-PoC-derived malicious FUSE daemon that speaks the real FUSE protocol. - Creates a small active ext4 root filesystem containing a root-owned, mode
0444/etc/passwd. - Boots QEMU twice with the vulnerable module and twice with the fixed module.
- In each guest, root performs only setup/module loading; the exploit drops to uid/gid 1000 before attacker-controlled FUSE replies and
/etc/passwdtargeting.
- Expected evidence:
- Vulnerable attempts show
PAGE_CACHE_CORRUPTION_CONFIRMED uid=1000 target=/etc/passwd,Direct write check as uid 1000: Read-only file system, andINIT_AFTER=root::0:0:x:.:. - Fixed attempts show
INIT_RESULT_FIXED_REJECTED_OVERSIZED_DIRENTandINIT_AFTER=root:x:0:0:root:/root:/bin/shwith no page-cache-corruption confirmation.
- Vulnerable attempts show
Evidence
Primary current-run artifacts:
bundle/repro/reproduction_steps.sh— self-contained reproduction script.bundle/repro/runtime_manifest.json— runtime evidence manifest written by the script.bundle/repro/validation_verdict.json— structured verdict written by the script.bundle/logs/reproduction_steps.log— consolidated build and proof log.bundle/logs/qemu_lpe_vuln_attempt1.logbundle/logs/qemu_lpe_vuln_attempt2.logbundle/logs/qemu_lpe_fixed_attempt1.logbundle/logs/qemu_lpe_fixed_attempt2.logbundle/repro/fuse_passwd_lpe.candbundle/repro/fuse_passwd_lpe— malicious FUSE daemon/helper used in the guest.bundle/repro/fuse-nokasan-vuln.koandbundle/repro/fuse-nokasan-fixed.ko— vulnerable and fixed FUSE modules used for comparison.
Key vulnerable evidence from the second verified run in bundle/logs/reproduction_steps.log:
Primary proof build is non-sanitized: CONFIG_KASAN is disabled
INIT_ROLE=vuln
INIT_KERNEL=6.18.18
INIT_ROOTFS_ACTIVE=/dev/vda
INIT_BEFORE=root:x:0:0:root:/root:/bin/sh
[+] Running exploit logic as uid=1000 gid=1000 target=/etc/passwd
[+] Direct write check as uid 1000: Read-only file system
[+] Warmup: 3/5 (60%)
[*] LPE 1/200 ... [+] CORRUPTED /etc/passwd first_line=root::0:0:x:.:
HIT!
[+] PAGE_CACHE_CORRUPTION_CONFIRMED uid=1000 target=/etc/passwd
INIT_EXPLOIT_RC=0
INIT_AFTER=root::0:0:x:.:
INIT_RESULT_PAGE_CACHE_LPE_CONFIRMED
VULNERABLE attempt 1: unprivileged page-cache corruption of /etc/passwd confirmed
The second vulnerable attempt produced the same successful markers:
INIT_ROLE=vuln
INIT_BEFORE=root:x:0:0:root:/root:/bin/sh
[+] Direct write check as uid 1000: Read-only file system
[+] PAGE_CACHE_CORRUPTION_CONFIRMED uid=1000 target=/etc/passwd
INIT_AFTER=root::0:0:x:.:
INIT_RESULT_PAGE_CACHE_LPE_CONFIRMED
VULNERABLE attempt 2: unprivileged page-cache corruption of /etc/passwd confirmed
Fixed negative-control evidence:
INIT_ROLE=fixed
INIT_BEFORE=root:x:0:0:root:/root:/bin/sh
[+] Running exploit logic as uid=1000 gid=1000 target=/etc/passwd
[+] Direct write check as uid 1000: Read-only file system
[+] Warmup: 0/5 (0%)
[-] No warmup hits.
INIT_EXPLOIT_RC=1
INIT_AFTER=root:x:0:0:root:/root:/bin/sh
INIT_RESULT_FIXED_REJECTED_OVERSIZED_DIRENT
FIXED attempt 1: oversized dirent failed closed; /etc/passwd unchanged
The second fixed attempt also failed closed and left /etc/passwd unchanged. The script summary was:
Vulnerable page-cache-corruption attempts: 2/2
Fixed negative-control attempts: 2/2
CVE-2026-31694 CONFIRMED: non-sanitized vulnerable kernel permits uid 1000 to corrupt the page-cache contents of root-owned read-only /etc/passwd; fixed module blocks it.
Recommendations / Next Steps
- Apply the upstream fix that rejects dirents whose serialized length exceeds
PAGE_SIZEbefore caching them. - Backport the
reclen > PAGE_SIZEguard to all supported kernels that include the FUSE name length increase and have vulnerable readdir cache logic. - Add regression tests for FUSE
READDIRreplies with maximum name lengths, including records that exceed a page after alignment. - Consider hardening and auditing other page-cache or direct-map write paths where attacker-controlled data can cross a page boundary into an adjacent physical page.
- Treat KASAN-only testing as insufficient for this exploit class: the primary exploit target is a page-cache page and the important observable impact is privileged file-content corruption in the kernel page cache.
Additional Notes
- Idempotency confirmation:
bundle/repro/reproduction_steps.shwas executed twice consecutively after the shell bug was fixed. Both runs exited 0 and produced the same 2/2 vulnerable and 2/2 fixed outcomes. - Primary proof mode: The proof is intentionally non-sanitized (
CONFIG_KASANdisabled) and uses product/runtime kernel execution through QEMU and the real FUSE boundary. - Privilege boundary: The process opens
/dev/fuseand mounts during privileged harness setup, then callssetresgid(1000,1000,1000)andsetresuid(1000,1000,1000)before sending malicious FUSEREADDIRreplies and grooming/etc/passwd. - Scope: The proof demonstrates the disclosed LPE primitive by changing the trusted page-cache contents of root-owned
/etc/passwd. It does not persist the change to disk or spawn an interactive root shell, to keep the run deterministic and self-contained.
Variant Analysis & Alternative Triggers for CVE-2026-31694
A materially distinct alternate trigger was confirmed on the vulnerable kernel: a malicious FUSE daemon can negotiate FUSE_DO_READDIRPLUS and return a FUSE_READDIRPLUS response containing a struct fuse_direntplus whose embedded struct fuse_dirent has namelen=4095. The kernel parses this through parse_dirplusfile(), then calls the same fuse_emit() and fuse_add_dirent_to_cache() sink used by ordinary FUSE_READDIR, producing the same 4120-byte copy into a 4096-byte readdir cache page and the same unprivileged /etc/passwd page-cache corruption primitive. This is not a bypass of the tested fix: the fixed fuse.ko adds a sink-level reclen > PAGE_SIZE guard in fuse_add_dirent_to_cache(), so it blocks both the original FUSE_READDIR path and the FUSE_READDIRPLUS alternate parser path.
Fix Coverage / Assumptions
The effective fix relies on the invariant that no serialized directory entry larger than one page may be copied into the FUSE readdir cache. It enforces that invariant at the common sink, fs/fuse/readdir.c:fuse_add_dirent_to_cache(), immediately after computing:
size_t reclen = FUSE_DIRENT_SIZE(dirent);
The tested fixed module adds the equivalent of:
if (reclen > PAGE_SIZE)
return;
This explicitly covers every caller that reaches the cache insertion sink through fuse_emit(), including:
parse_dirfile()forFUSE_READDIRreplies, andparse_dirplusfile()forFUSE_READDIRPLUSreplies.
The fix does not validate FUSE_DIRENTPLUS_SIZE() itself against PAGE_SIZE; however, the overflow root cause is not the larger wire-format direntplus record. The overflow occurs when the embedded struct fuse_dirent is passed to fuse_add_dirent_to_cache() and copied as FUSE_DIRENT_SIZE(dirent). Because the guard is at that common sink, it closes this alternate path. The fix assumption appears complete for this specific root cause: all readdir-cache insertions flow through fuse_add_dirent_to_cache().
Variant / Alternate Trigger
The tested alternate trigger is FUSE_READDIRPLUS instead of ordinary FUSE_READDIR.
Exact runtime entry/message path:
- A local attacker-controlled FUSE daemon opens
/dev/fuseand mounts a FUSE filesystem in the VM harness. - During
FUSE_INIT, the daemon advertisesFUSE_DO_READDIRPLUS. - During
getdents64()on a trigger directory, the kernel issuesFUSE_READDIRPLUS. - The malicious daemon replies with a
struct fuse_direntpluswhose embeddeddirent.namelenis4095. - The kernel parses the response in
parse_dirplusfile()and callsfuse_emit(). fuse_emit()callsfuse_add_dirent_to_cache()becauseFOPEN_CACHE_DIRis set.- Vulnerable
fuse_add_dirent_to_cache()copiesFUSE_DIRENT_SIZE(dirent) == 4120bytes into one 4096-byte page.
Specific code anchors:
fs/fuse/readdir.c:32-88—fuse_add_dirent_to_cache()computesreclen, advances to a new page ifoffset + reclen > PAGE_SIZE, then performsmemcpy(addr + offset, dirent, reclen).fs/fuse/readdir.c:114-123—fuse_emit()callsfuse_add_dirent_to_cache()whenFOPEN_CACHE_DIRis set.fs/fuse/readdir.c:293-326—parse_dirplusfile()parsesFUSE_READDIRPLUSrecords and invokesfuse_emit()with the embeddedstruct fuse_dirent.fs/fuse/readdir.c:334-377—fuse_readdir_uncached()selectsFUSE_READDIRPLUSwhenfuse_use_readdirplus()is true.
The stage-specific reproducer is bundle/vuln_variant/fuse_readdirplus_lpe.c. It differs from the prior FUSE_READDIR proof by advertising FUSE_DO_READDIRPLUS, handling opcode FUSE_READDIRPLUS, building a struct fuse_direntplus response, and treating any fallback ordinary FUSE_READDIR as an error for evidence clarity.
- Package/component affected: Linux kernel FUSE subsystem,
fs/fuse/readdir.creaddir cache path. - Affected versions as tested: vulnerable module built from the prepared Linux 6.18.18 source snapshot without the
reclen > PAGE_SIZEguard; fixed negative-control module built from the same source/config with the guard inserted. - Risk level and consequences: High on vulnerable builds. The alternate
FUSE_READDIRPLUSpath gives the same local privilege-escalation primitive as the parent issue: an unprivileged attacker-controlled FUSE daemon can corrupt the page-cache contents of a root-owned, read-only/etc/passwdfile.
Impact Parity
- Disclosed/claimed maximum impact for the parent: unprivileged local privilege escalation via page-cache corruption of
/etc/passwd. - Reproduced impact from this variant run: full LPE primitive on the vulnerable module through
FUSE_READDIRPLUS: the exploit drops to uid/gid 1000 before malicious replies and target corruption, direct append to/etc/passwdfails withRead-only file system, and/etc/passwdpage-cache contents change toroot::0:0:x:.:. - Parity:
fullon the vulnerable alternate trigger;noneon the fixed module because the tested fix blocks the alternate trigger. - Not demonstrated: an interactive root shell was not spawned. The proof stops at deterministic page-cache corruption of
/etc/passwd, matching the parent LPE primitive.
Root Cause
The same underlying bug can be reached because FUSE_READDIRPLUS eventually reuses the same cache insertion function as ordinary FUSE_READDIR. parse_dirplusfile() computes the wire record length using FUSE_DIRENTPLUS_SIZE(direntplus) to parse a struct fuse_direntplus, but when it emits a directory entry it passes the embedded struct fuse_dirent to fuse_emit(). fuse_emit() then calls fuse_add_dirent_to_cache(), which computes FUSE_DIRENT_SIZE(dirent) from the embedded attacker-controlled namelen and performs the vulnerable copy.
For namelen=4095, FUSE_DIRENT_SIZE(dirent) is 4120. In the vulnerable sink, the existing check only moves the insertion offset to the start of the next page when offset + reclen > PAGE_SIZE; it does not reject reclen > PAGE_SIZE. A 4120-byte memcpy() therefore writes 24 bytes beyond the end of the target cache page.
The ticket identifies the upstream fix as 51a8de6c50bf947c8f534cd73da4c8f0a13e7bed (fuse: reject oversized dirents in page cache). The tested fixed module applies the same sink-level guard, and runtime evidence shows that this guard blocks the FUSE_READDIRPLUS alternate trigger.
Reproduction Steps
- Run
bundle/vuln_variant/reproduction_steps.shfrom the workspace, or setPRUVA_ROOT=/path/to/bundleand run it from any directory. - The script:
- builds
bundle/vuln_variant/fuse_readdirplus_lpefrom the stage-specific source, - boots the prepared non-KASAN kernel in QEMU,
- tests the
FUSE_READDIRPLUSvariant against the vulnerablefuse.ko, - tests the same variant against the fixed
fuse.ko, and - writes logs under
bundle/logs/vuln_variant/.
- builds
- Expected evidence:
- Vulnerable run:
received FUSE_READDIRPLUS,PAGE_CACHE_CORRUPTION_CONFIRMED uid=1000 target=/etc/passwd,VARIANT_AFTER=root::0:0:x:.:, andVARIANT_RESULT_READDIRPLUS_LPE_CONFIRMED. - Fixed run:
received FUSE_READDIRPLUS,VARIANT_AFTER=root:x:0:0:root:/root:/bin/sh, andVARIANT_RESULT_FIXED_REJECTED_READDIRPLUS_OVERSIZED_DIRENT, with noPAGE_CACHE_CORRUPTION_CONFIRMED.
- Vulnerable run:
Evidence
Current-run artifacts:
bundle/vuln_variant/reproduction_steps.sh— stage-specific vulnerable/fixed variant test.bundle/vuln_variant/fuse_readdirplus_lpe.c— malicious READDIRPLUS FUSE daemon/helper.bundle/vuln_variant/runtime_manifest.json— runtime stack and proof artifact manifest.bundle/logs/vuln_variant/readdirplus_variant.log— consolidated current-run evidence.bundle/logs/vuln_variant/qemu_readdirplus_vuln.log— vulnerable QEMU evidence.bundle/logs/vuln_variant/qemu_readdirplus_fixed.log— fixed negative-control evidence.
Key vulnerable evidence from the idempotency run:
VARIANT_ROLE=vuln
VARIANT_KERNEL=6.18.18
VARIANT_BEFORE=root:x:0:0:root:/root:/bin/sh
[fuse] INIT: advertising FUSE_DO_READDIRPLUS for variant path
[fuse] received FUSE_READDIRPLUS offset=0; holding reply for grooming
[fuse] replying to FUSE_READDIRPLUS with namelen=4095 plus_reclen=4248 embedded_dirent_reclen=4120
[+] Direct write check as uid 1000: Read-only file system
[+] CORRUPTED /etc/passwd first_line=root::0:0:x:.:
[+] PAGE_CACHE_CORRUPTION_CONFIRMED uid=1000 target=/etc/passwd
VARIANT_EXPLOIT_RC=0
VARIANT_AFTER=root::0:0:x:.:
VARIANT_RESULT_READDIRPLUS_LPE_CONFIRMED
Key fixed evidence:
VARIANT_ROLE=fixed
VARIANT_KERNEL=6.18.18
VARIANT_BEFORE=root:x:0:0:root:/root:/bin/sh
[fuse] INIT: advertising FUSE_DO_READDIRPLUS for variant path
[fuse] received FUSE_READDIRPLUS offset=0; holding reply for grooming
[fuse] replying to FUSE_READDIRPLUS with namelen=4095 plus_reclen=4248 embedded_dirent_reclen=4120
[+] Warmup: 0/5 (0%)
[-] No warmup hits.
VARIANT_EXPLOIT_RC=1
VARIANT_AFTER=root:x:0:0:root:/root:/bin/sh
VARIANT_RESULT_FIXED_REJECTED_READDIRPLUS_OVERSIZED_DIRENT
Both mandatory verification runs completed without crashing. Both returned script exit code 1, which is the designed outcome for “alternate trigger on vulnerable module, no fixed-version bypass.”
Recommendations / Next Steps
- Keep the fix at the common cache insertion sink (
fuse_add_dirent_to_cache()), not only in the ordinaryFUSE_READDIRparser, becauseFUSE_READDIRPLUSand any future parser that callsfuse_emit()share the same sink. - Add regression coverage for both
FUSE_READDIRandFUSE_READDIRPLUSreplies withnamelen=4095andFOPEN_CACHE_DIRenabled. - Consider adding a defensive WARN/test assertion that every readdir-cache insertion satisfies
FUSE_DIRENT_SIZE(dirent) <= PAGE_SIZEbefore copying. - Audit future FUSE directory-entry emitters for direct calls to
fuse_add_dirent_to_cache()or equivalent page-cache serialization logic.
Additional Notes
- Idempotency confirmation:
bundle/vuln_variant/reproduction_steps.shwas executed twice consecutively. Both runs completed cleanly, reproduced theFUSE_READDIRPLUSalternate trigger on the vulnerable module, and showed the fixed module blocking it. - Threat model scope: The Linux kernel documentation treats exploitable kernel bugs as security bugs and routes them to
security@kernel.org. This variant crosses the same local kernel trust boundary as the parent: an unprivileged local process controls a FUSE server response that is consumed by privileged kernel code. - Conclusion: This is a validated alternate vulnerable-version trigger, not a patch bypass. The tested sink-level fix is complete for the discovered
FUSE_READDIRPLUSpath.
CVE-2026-31694 Reproduction Transcript
The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.
Full session Replay every step — scrub the timeline or play it back.
ls -la /data/pruva/project-cache/6cba72b6-b104-4ebf-be7b-01f748e87ccf/.pruva/ 2>/dev/null; echo "---KERNELS---"; ls -la /data/pruva/project-cache/6cba72b6-b104-4ebf-be7b-01f748e87ccf/kernels/ 2>/dev/null; ls -la /data/pruva/project-cache/6cba72b6-b104-4ebf-be7b-01f748e87ccf/kernels/*/ 2>/dev/null; echo "---QEMU---"; which qemu-system-x86_64 2>/dev/null; echo "---REPRO---"; cat /data/pruva/project-cache/6cba72b6-b104-4ebf-be7b-01f748e87ccf/repro.c{"cwd":"/data/pruva/runs/faf1cf12-e2da-4977-9356-d1d6c2a36dfd","duration_ms":11,"exit_code":0,"stderr":"","stdout":"total 0\ndrwxr-xr-x 1 vscode vscode 22 Jul 2 21:46 .\ndrwxr-xr-x 1 vscode vscode 1370 Jul 3 10:05 ..\ndrwxr-xr-x 1 vscode vscode 60 Jul 3 13:05 proof-carry\n---KERNELS---\ntotal 0\ndrwxr-xr-x 1 vscode vscode 50 Jul 3 09:29 .\ndrwxr-xr-x 1 vscode vscode 1370 Jul 3 10:05 ..\ndrwxr-xr-x 1 vscode vscode 100 Jul 3 09:23 bond\ndrwxr-xr-x 1 vscode vscode 210 Jul 3 10:05 bond7rc2\ndrwxr-xr-x 1 vscode vscode 470 Jul 2 21:40 v7.0.10\ndrwxr-xr-x 1 vscode vscode 462 Jul 2 21:40 v7.0.9\n/data/pruva/project-cache/6cba72b6-b104-4ebf-be7b-01f748e87ccf/kernels/bond/:\ntotal 333696\ndrwxr-xr-x 1 vscode vscode 100 Jul 3 09:23 .\ndrwxr-xr-x 1 vscode vscode 50 Jul 3 09:29 ..\n-rw-r--r-- 1 vscode vscode 219 Jul 3 09:12 BUILT_MARKER\n-rw-r--r-- 1 vscode vscode 21840896 Jul 3 09:11 bzImage\n-rw-r--r-- 1 vscode vscode 208920576 Jul 3 09:11 fixed-rootfs.img\n-rw-r--r-- 1 vscode vscode 208969728 Jul 3 09:23 vuln-rootfs.img\n\n/data/pruva/project-cache/6cba72b6-b104-4ebf-be7b-01f748e87ccf/kernels/bond7rc2/:\ntotal 801532\ndrwxr-xr-x 1 vscode vscode … [truncated]echo "=== linux-src version ==="; head -5 /data/pruva/project-cache/6cba72b6-b104-4ebf-be7b-01f748e87ccf/linux-src/Makefile 2>/dev/null; echo "=== linux-src-7rc2 version ==="; head -5 /data/pruva/project-cache/6cba72b6-b104-4ebf-be7b-01f748e87ccf/linux-src-7rc2/Makefile 2>/dev/null; echo "=== proof-carry ==="; find /data/pruva/project-cache/6cba72b6-b104-4ebf-be7b-01f748e87ccf/.pruva/proof-carry -type f 2>/dev/null; echo "=== QEMU check ==="; which qemu-system-x86_64 2>/dev/null || echo "no qemu"; dpkg -l | grep -i qemu 2>/dev/null | head -5; echo "=== KVM ==="; ls -la /dev/kvm 2>/dev/null || echo "no /dev/kvm"{"cwd":"/data/pruva/runs/faf1cf12-e2da-4977-9356-d1d6c2a36dfd","duration_ms":14,"exit_code":0,"stderr":"","stdout":"=== linux-src version ===\n# SPDX-License-Identifier: GPL-2.0\nVERSION = 6\nPATCHLEVEL = 18\nSUBLEVEL = 18\nEXTRAVERSION =\n=== linux-src-7rc2 version ===\n# SPDX-License-Identifier: GPL-2.0\nVERSION = 7\nPATCHLEVEL = 0\nSUBLEVEL = 0\nEXTRAVERSION = -rc2\n=== proof-carry ===\n/data/pruva/project-cache/6cba72b6-b104-4ebf-be7b-01f748e87ccf/.pruva/proof-carry/latest_confirmed/repro/reproduction_steps.sh\n/data/pruva/project-cache/6cba72b6-b104-4ebf-be7b-01f748e87ccf/.pruva/proof-carry/latest_confirmed/repro/runtime_manifest.json\n/data/pruva/project-cache/6cba72b6-b104-4ebf-be7b-01f748e87ccf/.pruva/proof-carry/latest_confirmed/repro/validation_verdict.json\n/data/pruva/project-cache/6cba72b6-b104-4ebf-be7b-01f748e87ccf/.pruva/proof-carry/latest_confirmed/repro/rca_report.md\n/data/pruva/project-cache/6cba72b6-b104-4ebf-be7b-01f748e87ccf/.pruva/proof-carry/latest_confirmed/logs/reproduction_steps.log\n/data/pruva/project-cache/6cba72b6-b104-4ebf-be7b-01f748e87ccf/.pruva/proof-carry/latest_confirmed/logs/qemu_var_vuln.log\n/data/pruva/project-cache/6cba72b6-b104-4ebf-be7b-… [truncated]echo "=== FUSE readdir.c in linux-src ==="; cat /data/pruva/project-cache/6cba72b6-b104-4ebf-be7b-01f748e87ccf/linux-src/fs/fuse/readdir.c 2>/dev/null | head -200; echo "=== FUSE_NAME_MAX in linux-src ==="; grep -rn "FUSE_NAME_MAX" /data/pruva/project-cache/6cba72b6-b104-4ebf-be7b-01f748e87ccf/linux-src/include/ 2>/dev/null | head -20{"cwd":"/data/pruva/runs/faf1cf12-e2da-4977-9356-d1d6c2a36dfd","duration_ms":684,"exit_code":0,"stderr":"","stdout":"=== FUSE readdir.c in linux-src ===\n/*\n FUSE: Filesystem in Userspace\n Copyright (C) 2001-2018 Miklos Szeredi <miklos@szeredi.hu>\n\n This program can be distributed under the terms of the GNU GPL.\n See the file COPYING.\n*/\n\n\n#include \"fuse_i.h\"\n#include <linux/iversion.h>\n#include <linux/posix_acl.h>\n#include <linux/pagemap.h>\n#include <linux/highmem.h>\n\nstatic bool fuse_use_readdirplus(struct inode *dir, struct dir_context *ctx)\n{\n\tstruct fuse_conn *fc = get_fuse_conn(dir);\n\tstruct fuse_inode *fi = get_fuse_inode(dir);\n\n\tif (!fc->do_readdirplus)\n\t\treturn false;\n\tif (!fc->readdirplus_auto)\n\t\treturn true;\n\tif (test_and_clear_bit(FUSE_I_ADVISE_RDPLUS, &fi->state))\n\t\treturn true;\n\tif (ctx->pos == 0)\n\t\treturn true;\n\treturn false;\n}\n\nstatic void fuse_add_dirent_to_cache(struct file *file,\n\t\t\t\t struct fuse_dirent *dirent, loff_t pos)\n{\n\tstruct fuse_inode *fi = get_fuse_inode(file_inode(file));\n\tsize_t reclen = FUSE_DIRENT_SIZE(dirent);\n\tpgoff_t index;\n\tstruct page *page;\n\tloff_t size;\n\tu64 version;\… [truncated]Artifacts and Evidence for CVE-2026-31694
Scripts, logs, diffs, and output captured during the reproduction.
How to Fix CVE-2026-31694
FAQ: CVE-2026-31694
Does CVE-2026-31694 require remote access to exploit?
How severe is CVE-2026-31694?
How can I reproduce CVE-2026-31694?
References for CVE-2026-31694
Authoritative sources for CVE-2026-31694 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.