PT-2026-121995

CVE-2026-99018

·

Published

2026-10-23

·

Updated

2026-10-23

Description by

Score
N/A
Not available

No severity ratings or metrics are available. When they are, we'll update the corresponding info on the page.

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.
Vendors
Affected products
Related identifiers
Found an issue in the description? Have something to add? Feel free to write us 👾