---
id: "CVE-2026-99092"
kind: "vulnerability"
aliases: ["CVE-2026-99092"]
title: "Linux kernel RISC-V: BPF JIT patching fails when strict module RWX is off"
severity: "unknown"
cvss: null
epss: null
exploited: false
status: "open"
category: "runtime"
products: []
ecosystems: []
tags: ["bpf", "linux-kernel", "riscv", "runtime"]
not_affected_if: ["bpf-jit-disabled", "non-riscv-architecture", "strict-module-rwx-enabled"]
published_at: "2026-10-26T15:16:48+00:00"
first_seen_at: "2026-10-26T16:02:26+00:00"
updated_at: "2026-10-26T16:04:09+00:00"
sources: [{"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-99092", "first_seen_at": "2026-10-26T16:02:26+00:00"}]
---

# Linux kernel RISC-V: BPF JIT patching fails when strict module RWX is off

On RISC-V kernels built without CONFIG_STRICT_MODULE_RWX, writing BPF JIT code to read-only vmalloc memory faults, so the BPF program is left un-JITed. The sources describe a robustness failure rather than an attacker gaining code execution or data.

_Summary, check and fix written by a model from the sources; labelled as such._

## How to check

- Check whether the running kernel config sets `CONFIG_STRICT_MODULE_RWX` to `n`, for example with `grep STRICT_MODULE_RWX /boot/config-$(uname -r)`
- Confirm the kernel is RISC-V with `uname -m` returning `riscv64`
- Check whether `CONFIG_BPF_JIT` is enabled in the same config file

## Fix

- Update the Linux kernel to a release that includes the upstream commit fixing patch_map() for bpf-jit execmem addresses, referenced as commit 8718e5a3090b follow-up in the NVD entry
- Rebuild or update the kernel package from your distribution vendor once it ships the fix; exact fixed versions are unknown from the sources

## Timeline

- 2026-10-26T16:02:26+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-99092

## From the sources

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

riscv: patch: fix handling of bpf-jit execmem addresses

Commit 8718e5a3090b ("riscv: patch: skip fixmap mapping when kernel text
is already writable") gated the core_kernel_text() branch of patch_map()
on CONFIG_STRICT_KERNEL_RWX, and explicitly left the vmalloc branch
unchanged. That branch has a separate problem.

That branch only creates a temporary writable fixmap alias when
CONFIG_STRICT_MODULE_RWX is enabled, and otherwise assumes the target is
directly writable and returns the address unchanged. That assumption no
longer holds: bpf_prog_pack_alloc calls set_memory_rox() on every pack
unconditionally in alloc_new_pack(), independently of any
CONFIG_STRICT_*_RWX option, so BPF text in the vmalloc area is read-only
regardless of what CONFIG_STRICT_MODULE_RWX says.

With CONFIG_STRICT_MODULE_RWX=n, patch_map() returns the read-only
address directly, the subsequent copy_to_kernel_nofault() takes a
page fault and returns -EFAULT. bpf_arch_text_copy() turns that into
-EINVAL, which propagates through bpf_jit_binary_pack_finalize() to the
WARN_ON() in bpf_int_jit_compile() and leaves the program un-JITed.

Note that BPF cannot be fixed the way kprobes was in
commit bdc46e507b59 ("riscv: mm: make EXECMEM_KPROBES writable without
CONFIG_STRICT_MODULE_RWX"). EXECMEM_BPF is already PAGE_KERNEL, i.e.
writable at allocation time; the read-only mapping is established
afterwards by generic code in alloc_new_pack(), which arch code cannot
influence. The only place this can be handled is patch_map().

This is the same problem that was fixed on arm64 by commit b1480ed230ac
("arm64: patching: fix handling of execmem addresses"), and the fix is
the same: CONFIG_EXECMEM is what actually tracks whether the vmalloc
area can hold executable memory that needs a temporary alias to be
written. CONFIG_BPF_JIT, CONFIG_KPROBES and CONFIG_MODULES all select
it.

Note that this is not limited to CONFIG_MODULES=n. Unlike arm64, riscv
selects CONFIG_ARCH_OPTIONAL_KERNEL_RWX, so CONFIG_STRICT_MODULE_RWX can
be disabled with CONFIG_MODULES=y as well, and the bug is reachable in
that configuration too.

The !CONFIG_MMU build is unaffected: it has its own __patch_insn_set()
and __patch_insn_write() implementations and never calls patch_map().

---

_Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai_
