CVE-2026-99018 in Linuxinfo

Summary

by MITRE • 10/23/2026

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

riscv: entry: gate shadow call stack reload on sstatus.SPP, not tp

Under CONFIG_SHADOW_CALL_STACK, handle_exception() reloads the kernel shadow call stack pointer (gp) only when the trap came from userspace. It made that decision with scs_load_current_if_task_changed, which compares the trap-time tp (read back from sscratch into s5) against the current tp:

beq \prev, tp, _skip_scs scs_load_current _skip_scs:

tp is a user-writable register. A user task that sets tp to the linear-map address of its own task_struct (&current) before trapping makes the comparison succeed (can achieve by brute force with KASLR enable under our test), so the kernel skips scs_load_current and keeps running with the gp that userspace left in place. Under CONFIG_SHADOW_CALL_STACK gp is the shadow call stack pointer and load_global_pointer is a no-op, so the compiler-emitted "sd ra, -8(gp)" / "ld ra, -8(gp)" in every non-leaf function then write to, and return through, an attacker-controlled address -- an unprivileged kernel arbitrary-write and control-flow-hijack primitive. The poisoned gp is saved to task_struct.scs_sp on return, so the reload is skipped on every subsequent entry as well.

Decide "came from userspace" from the hardware sstatus.SPP bit (already in s1 at this point) instead of from tp, mirroring the check that ret_from_exception already uses a few instructions later. SPP is written by hardware on trap entry and cannot be forged from U-mode. Legitimate behaviour is unchanged: user entries (SPP=0) reload the task shadow call stack, nested kernel entries (SPP=1) skip it.

If you want to get the best quality for vulnerability data then you always have to consider VulDB.

Analysis

by VulDB Data Team • 10/23/2026

The Linux kernel for RISC-V architectures contains a critical logic flaw in its exception handling mechanism that allows unprivileged userspace processes to hijack control flow and perform arbitrary memory writes within the kernel. This vulnerability specifically affects systems configured with CONFIG_SHADOW_CALL_STACK, a security feature designed to protect against return-oriented programming attacks by maintaining separate call stacks for user and kernel contexts. The core issue lies in how the kernel determines whether an exception originated from userspace or from another part of the kernel itself. Instead of relying on hardware-enforced state bits that are immutable after trap entry, the implementation incorrectly uses a comparison involving the tp register to decide if it should reload the shadow call stack pointer gp.

The technical flaw stems from the fact that tp is a general-purpose user-writable register in RISC-V architecture. The function handle_exception attempts to determine the origin of the trap by comparing the value of tp captured at the time of the exception against the current task's tp value stored in s5. If these values match, the kernel assumes the trap came from userspace and proceeds to load the appropriate shadow call stack pointer into gp. However, because tp is fully controllable by user applications, a malicious process can deliberately set its tp register to point to the linear-map address of its own task_struct structure before triggering an exception. By doing so, it forces the comparison logic to evaluate as true, causing the kernel to skip the necessary reload of the shadow call stack pointer gp.

When the kernel skips this reload under CONFIG_SHADOW_CALL_STACK, the global pointer register gp retains whatever value was left in place by userspace rather than being reset to a valid kernel-controlled address. In RISC-V calling conventions, functions that are not leaf functions use sd and ld instructions to save and restore return addresses relative to gp. With gp pointing to an attacker-controlled memory region, every non-leaf function executed during the exception handling process will write its return address to this malicious location. This effectively transforms a standard kernel execution path into an arbitrary write primitive, allowing the attacker to overwrite critical data structures or control flow pointers within the kernel space.

The impact of this vulnerability is severe, as it provides unprivileged users with a reliable method for control-flow hijacking and arbitrary memory modification. Once gp is poisoned, subsequent operations rely on corrupted stack frames, potentially leading to code execution with kernel privileges. Furthermore, the damage persists beyond the immediate exception because the poisoned value of gp is saved back into task_struct.scs_sp upon return from the exception handler. This means that any future exceptions handled by this specific task will also skip the shadow call stack reload, maintaining the attacker's control over the global pointer and extending the window for exploitation across multiple system calls or interrupt handlers associated with that process.

Mitigation strategies focus on correcting the logic used to determine trap origin. The resolution involves replacing the comparison of tp registers with a check of the sstatus.SPP bit. This hardware register bit indicates whether the exception occurred in supervisor mode (kernel) or user mode and is written by the CPU during trap entry, making it impossible for userspace applications to forge or manipulate. By mirroring the logic already present in ret_from_exception, which correctly uses SPP to distinguish between nested kernel entries and initial user traps, the kernel ensures that shadow call stack pointers are only reloaded when appropriate. This change eliminates the race condition and logical error without altering legitimate operational behavior for either user-mode or nested kernel exceptions.

From a classification perspective, this vulnerability aligns with CWE-20 Improper Input Validation, as the system fails to properly validate the source of an exception before making critical state changes. It also relates to CWE-94 Code Injection through improper control of execution flow via manipulated registers. In terms of attack vectors, it corresponds to MITRE ATT&CK techniques involving privilege escalation and defense evasion by manipulating runtime environment variables like register states. The fix ensures that the kernel relies on immutable hardware state rather than mutable software-managed registers for security-critical decisions, thereby closing a significant gap in RISC-V kernel hardening mechanisms.

Responsible

Linux

Reservation

09/25/2026

Disclosure

10/23/2026

Moderation

accepted

EPSS

0.00000

KEV

no

Activities

very low

Sources

Do you know our Splunk app?

Download it now for free!