{"id":"CVE-2026-99018","kind":"vulnerability","aliases":["CVE-2026-99018"],"related":[],"title":"Linux kernel RISC-V: unprivileged user can hijack kernel shadow call stack","description":"In the Linux kernel, the following vulnerability has been resolved:\n\nriscv: entry: gate shadow call stack reload on sstatus.SPP, not tp\n\nUnder CONFIG_SHADOW_CALL_STACK, handle_exception() reloads the kernel\nshadow call stack pointer (gp) only when the trap came from userspace.\nIt made that decision with scs_load_current_if_task_changed, which\ncompares the trap-time tp (read back from sscratch into s5) against the\ncurrent tp:\n\n\tbeq\t\\prev, tp, _skip_scs\n\tscs_load_current\n_skip_scs:\n\ntp is a user-writable register.  A user task that sets tp to the\nlinear-map address of its own task_struct (&current) before trapping\nmakes the comparison succeed (can achieve by brute force with KASLR\nenable under our test), so the kernel skips scs_load_current and\nkeeps running with the gp that userspace left in place.  Under\nCONFIG_SHADOW_CALL_STACK gp is the shadow call stack pointer and\nload_global_pointer is a no-op, so the compiler-emitted\n\"sd ra, -8(gp)\" / \"ld ra, -8(gp)\" in every non-leaf function then write\nto, and return through, an attacker-controlled address -- an\nunprivileged kernel arbitrary-write and control-flow-hijack primitive.\nThe poisoned gp is saved to task_struct.scs_sp on return, so the reload\nis skipped on every subsequent entry as well.\n\nDecide \"came from userspace\" from the hardware sstatus.SPP bit (already\nin s1 at this point) instead of from tp, mirroring the check that\nret_from_exception already uses a few instructions later.  SPP is\nwritten by hardware on trap entry and cannot be forged from U-mode.\nLegitimate behaviour is unchanged: user entries (SPP=0) reload the task\nshadow call stack, nested kernel entries (SPP=1) skip it.","summary":"On RISC-V kernels built with shadow call stack, a user task can set its tp register to match its task_struct address so the kernel skips reloading the shadow call stack pointer. The kernel then runs with an attacker-controlled gp, giving an unprivileged arbitrary kernel write and control-flow hijack.","severity":"high","cvss":null,"epss":0.00209,"exploited":false,"exploited_at":null,"products":[{"name":"linux-kernel","fixed":["commit 4d0697f19297"],"affected":"RISC-V builds with CONFIG_SHADOW_CALL_STACK, from commit d1584d791a29 until 4d0697f19297; release versions unknown","ecosystem":"linux"}],"ecosystems":["linux"],"tags":["kernel","linux","local-privilege-escalation","riscv","runtime","self-hosted"],"not_affected_if":["non-riscv","shadow-call-stack-disabled"],"how_to_check":"Only RISC-V kernels are affected. Check the build config: grep CONFIG_SHADOW_CALL_STACK /boot/config-$(uname -r) (or zcat /proc/config.gz); '=y' means exposed. Check uname -m shows riscv64. Then confirm your distro kernel includes commit 4d0697f19297 (check the changelog); on a source tree, check that arch/riscv/kernel/entry.S uses scs_load_current_if_from_user s1, s5 rather than scs_load_current_if_task_changed.","fix":"Update to a kernel release that contains upstream commit 4d0697f192975dab5985e921989be1d85cf580e9 ('riscv: entry: gate shadow call stack reload on sstatus.SPP, not tp'). Stable backports to 6.18 and 7.2 were in review; the exact released versions were not found, so check your distro or kernel.org changelog. Until then, build without CONFIG_SHADOW_CALL_STACK on RISC-V.","status":"open","published_at":"2026-10-23T13:17:24+00:00","first_seen_at":"2026-10-23T21:57:33+00:00","triaged_at":"2026-10-25T04:55:40+00:00","updated_at":"2026-10-25T12:38:50+00:00","category":"runtime","confidence":0.7,"triage":{"at":"2026-10-25T04:55:40Z","model":"claude-haiku-5-5","output":{"fix":"- Update the Linux kernel to a release containing the upstream commit 'riscv: entry: gate shadow call stack reload on sstatus.SPP, not tp'.\n- Check whether the kernel was built with CONFIG_SHADOW_CALL_STACK enabled on RISC-V.","reach":"local","title":"Linux kernel RISC-V: unprivileged user can hijack kernel shadow call stack","impact":"high","summary":"On RISC-V kernels built with shadow call stack, a user task can set its tp register to match its task_struct address so the kernel skips reloading the shadow call stack pointer. The kernel then runs with an attacker-controlled gp, giving an unprivileged arbitrary kernel write and control-flow hijack.","category":"runtime","nicknames":[],"who_cares":["linux","riscv","kernel","self-hosted"],"confidence":0.6,"needs_auth":"yes","worst_case":"local user gains kernel arbitrary write and control-flow hijack","analyst_note":"Sources give no affected version range or fixed kernel release; check the upstream kernel commit and stable backports for exact versions and how_to_check steps.","how_to_check":"unknown","needs_analyst":true,"not_affected_if":["non-riscv","shadow-call-stack-disabled"],"who_is_affected":"Systems running a RISC-V Linux kernel built with CONFIG_SHADOW_CALL_STACK, where any local unprivileged user can run code. The sources do not say which kernel versions are affected or whether the default config enables shadow call stack, so the exact exposure is unknown.","user_interaction":"no","needs_special_setup":"yes","severity_if_unknown":"high"},"cost_usd":0.00068,"input_tokens":3862,"output_tokens":587,"severity_before":"unknown"},"analyst_status":"done","analyst_note":"Sources give no affected version range or fixed kernel release; check the upstream kernel commit and stable backports for exact versions and how_to_check steps.","search":"'-2026':15A,18A '-8':258C,262C '-99018':16A,19A '0':369C '1':380C 'achiev':202C 'address':57B,188C,280C 'alreadi':323C,340C 'arbitrari':81B,285C 'arbitrary-writ':284C 'attack':75B,278C 'attacker-control':74B,277C 'back':151C 'behaviour':363C 'beq':160C 'bit':322C 'brute':204C 'built':39B 'call':12A,42B,65B,103C,113C,121C,233C,239C,374C 'came':129C,315C 'cannot':355C 'chang':142C 'check':335C 'compar':144C 'comparison':199C 'compil':254C 'compiler-emit':253C 'config':111C,231C 'control':76B,86B,279C,289C 'control-flow':85B 'control-flow-hijack':288C 'current':139C,158C,167C,194C,218C 'cve':14A,17A 'decid':314C 'decis':135C 'emit':255C 'enabl':208C 'entri':100C,311C,353C,367C,378C 'escal':28B 'everi':265C,309C 'except':116C,339C 'flow':87B,290C 'follow':94C 'forc':205C 'forg':357C 'function':269C 'gate':101C 'give':78B 'global':244C 'gp':77B,124C,224C,235C,259C,263C,295C 'handl':115C 'hardwar':320C,350C 'hijack':9A,88B,291C 'host':33B 'instead':329C 'instruct':344C 'kaslr':207C 'keep':220C 'kernel':2A,10A,22A,23B,38B,60B,69B,82B,92C,119C,214C,283C,377C 'later':345C 'ld':260C 'leaf':268C 'left':227C 'legitim':362C 'linear':186C 'linear-map':185C 'linux':1A,21A,24B,91C 'linux-kernel':20A 'load':138C,166C,217C,243C 'local':26B 'local-privilege-escal':25B 'made':133C 'make':197C 'map':187C 'match':53B 'mirror':333C 'mode':361C 'nest':376C 'no-op':248C 'non':267C 'non-leaf':266C 'op':250C 'place':229C 'point':328C 'pointer':67B,123C,241C,245C 'poison':294C 'prev':161C 'primit':292C 'privileg':27B 'ra':257C,261C 'read':150C 'regist':51B,176C 'reload':62B,105C,117C,305C,370C 'resolv':98C 'ret':337C 'return':274C,302C 'risc':4A,36B 'risc-v':3A,35B 'riscv':29B,99C 'run':71B,221C 'runtim':30B 's1':325C 's5':155C 'save':297C 'scs':137C,164C,165C,169C,216C 'sd':256C 'self':32B 'self-host':31B 'set':48B,181C 'shadow':11A,41B,64B,102C,112C,120C,232C,238C,373C 'skip':61B,163C,168C,215C,307C,381C 'sp':300C 'spp':346C,368C,379C 'sscratch':153C 'sstatus.spp':107C,321C 'stack':13A,43B,66B,104C,114C,122C,234C,240C,375C 'struct':56B,193C 'subsequ':310C 'succeed':200C 'task':46B,55B,141C,179C,192C,372C 'task_struct.scs':299C 'test':211C 'time':148C 'tp':50B,109C,149C,159C,162C,170C,182C,332C 'trap':128C,147C,196C,352C 'trap-tim':146C 'u':360C 'u-mod':359C 'unchang':365C 'unprivileg':6A,80B,282C 'use':341C 'user':7A,45B,174C,178C,366C 'user-writ':173C 'userspac':131C,226C,317C 'v':5A,37B 'vulner':95C 'well':313C 'writabl':175C 'write':83B,271C,286C 'written':348C","nicknames":[],"mitigations":[],"who_affected":"Systems running a RISC-V Linux kernel built with CONFIG_SHADOW_CALL_STACK, where any local unprivileged user can run code. The sources do not say which kernel versions are affected or whether the default config enables shadow call stack, so the exact exposure is unknown.","tier":"B","verified":{},"analyst_revisit_at":null,"first_public_at":"2026-10-23T13:17:24+00:00","kev":null,"cvss_vector":null,"cvss_by":null,"poc_count":0,"sources":[{"source":"nvd","external_id":"CVE-2026-99018","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-99018","severity":null,"published_at":"2026-10-23T13:17:24+00:00","modified_at":"2026-10-23T13:17:24+00:00","first_seen_at":"2026-10-23T21:57:33+00:00","fetched_at":"2026-10-23T22:29:03+00:00","note":null},{"source":"analyst","external_id":"CVE-2026-99018:817","url":null,"severity":null,"published_at":"2026-10-25T04:57:10+00:00","modified_at":"2026-10-25T04:57:10+00:00","first_seen_at":"2026-10-25T04:57:10+00:00","fetched_at":"2026-10-25T04:57:10+00:00","note":"Read kernel patch thread: fix is upstream commit 4d0697f19297 (riscv fixes tree, applied 2026-10-08, Fixes d1584d791a29 'riscv: Implement Shadow Call Stack'); 6.18 and 7.2 stable backports at review stage only. No released fixed version read, so left unknown. No PoC link or exploitation reports found."},{"source":"epss","external_id":"CVE-2026-99018","url":"https://api.first.org/data/v1/epss?cve=CVE-2026-99018","severity":null,"published_at":null,"modified_at":null,"first_seen_at":"2026-10-25T12:38:50+00:00","fetched_at":"2026-10-25T12:38:50+00:00","note":null}],"documents":[{"id":3407,"url":"https://lore.landau.one/lkml/179142720833.3779518.9095154686634071421.git-patchwork-notify@kernel.org/T/","title":"[PATCH] riscv: entry: gate shadow call stack reload on sstatus.SPP, not tp (thread: review, applied to riscv fixes)","kind":"advisory","source":"analyst","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":null},{"id":3408,"url":"https://ci.syzbot.org/patches/843257b7-dd98-4314-87b6-0394f4c429ed","title":"6.18-stable review patch: commit 4d0697f19297 upstream","kind":"release","source":"analyst","text":null,"published_at":null,"relation":"fix","confidence":null,"note":null},{"id":3409,"url":"https://github.com/torvalds/linux/commit/d1584d791a297aa8ed93503382a682a6ecfc4218","title":"d1584d7 riscv: Implement Shadow Call Stack (introducing commit)","kind":"other","source":"analyst","text":null,"published_at":null,"relation":"describes","confidence":null,"note":null}],"notice":"Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai"}