Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

riscv: add documentation for shadow stack

Add documentation on shadow stack for user mode on riscv and the kernel
interfaces exposed for user tasks to enable it.

Reviewed-by: Zong Li <zong.li@sifive.com>
Signed-off-by: Deepak Gupta <debug@rivosinc.com>
Link: https://patch.msgid.link/20251112-v5_user_cfi_series-v23-27-b55691eacf4f@rivosinc.com
[pjw@kernel.org: cleaned up the documentation, patch description]
Signed-off-by: Paul Walmsley <pjw@kernel.org>

authored by

Deepak Gupta and committed by
Paul Walmsley
c8350aa2 f6eeb67b

+195
+1
Documentation/arch/riscv/index.rst
··· 15 15 vector 16 16 cmodx 17 17 zicfilp 18 + zicfiss 18 19 19 20 features 20 21
+194
Documentation/arch/riscv/zicfiss.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0 2 + 3 + :Author: Deepak Gupta <debug@rivosinc.com> 4 + :Date: 12 January 2024 5 + 6 + ========================================================= 7 + Shadow stack to protect function returns on RISC-V Linux 8 + ========================================================= 9 + 10 + This document briefly describes the interface provided to userspace by Linux 11 + to enable shadow stacks for user mode applications on RISC-V. 12 + 13 + 1. Feature Overview 14 + -------------------- 15 + 16 + Memory corruption issues usually result in crashes. However, in the 17 + hands of a creative adversary, these issues can result in a variety of 18 + security problems. 19 + 20 + Some of those security issues can be code re-use attacks on programs 21 + where an adversary can use corrupt return addresses present on the 22 + stack. chaining them together to perform return oriented programming 23 + (ROP) and thus compromising the control flow integrity (CFI) of the 24 + program. 25 + 26 + Return addresses live on the stack in read-write memory. Therefore 27 + they are susceptible to corruption, which allows an adversary to 28 + control the program counter. On RISC-V, the ``zicfiss`` extension 29 + provides an alternate stack (the "shadow stack") on which return 30 + addresses can be safely placed in the prologue of the function and 31 + retrieved in the epilogue. The ``zicfiss`` extension makes the 32 + following changes: 33 + 34 + - PTE encodings for shadow stack virtual memory 35 + An earlier reserved encoding in first stage translation i.e. 36 + PTE.R=0, PTE.W=1, PTE.X=0 becomes the PTE encoding for shadow stack pages. 37 + 38 + - The ``sspush x1/x5`` instruction pushes (stores) ``x1/x5`` to shadow stack. 39 + 40 + - The ``sspopchk x1/x5`` instruction pops (loads) from shadow stack and compares 41 + with ``x1/x5`` and if not equal, the CPU raises a ``software check exception`` 42 + with ``*tval = 3`` 43 + 44 + The compiler toolchain ensures that function prologues have ``sspush 45 + x1/x5`` to save the return address on shadow stack in addition to the 46 + regular stack. Similarly, function epilogues have ``ld x5, 47 + offset(x2)`` followed by ``sspopchk x5`` to ensure that a popped value 48 + from the regular stack matches with the popped value from the shadow 49 + stack. 50 + 51 + 2. Shadow stack protections and linux memory manager 52 + ----------------------------------------------------- 53 + 54 + As mentioned earlier, shadow stacks get new page table encodings that 55 + have some special properties assigned to them, along with instructions 56 + that operate on the shadow stacks: 57 + 58 + - Regular stores to shadow stack memory raise store access faults. This 59 + protects shadow stack memory from stray writes. 60 + 61 + - Regular loads from shadow stack memory are allowed. This allows 62 + stack trace utilities or backtrace functions to read the true call 63 + stack and ensure that it has not been tampered with. 64 + 65 + - Only shadow stack instructions can generate shadow stack loads or 66 + shadow stack stores. 67 + 68 + - Shadow stack loads and stores on read-only memory raise AMO/store 69 + page faults. Thus both ``sspush x1/x5`` and ``sspopchk x1/x5`` will 70 + raise AMO/store page fault. This simplies COW handling in kernel 71 + during fork(). The kernel can convert shadow stack pages into 72 + read-only memory (as it does for regular read-write memory). As 73 + soon as subsequent ``sspush`` or ``sspopchk`` instructions in 74 + userspace are encountered, the kernel can perform COW. 75 + 76 + - Shadow stack loads and stores on read-write or read-write-execute 77 + memory raise an access fault. This is a fatal condition because 78 + shadow stack loads and stores should never be operating on 79 + read-write or read-write-execute memory. 80 + 81 + 3. ELF and psABI 82 + ----------------- 83 + 84 + The toolchain sets up :c:macro:`GNU_PROPERTY_RISCV_FEATURE_1_BCFI` for 85 + property :c:macro:`GNU_PROPERTY_RISCV_FEATURE_1_AND` in the notes 86 + section of the object file. 87 + 88 + 4. Linux enabling 89 + ------------------ 90 + 91 + User space programs can have multiple shared objects loaded in their 92 + address space. It's a difficult task to make sure all the 93 + dependencies have been compiled with shadow stack support. Thus 94 + it's left to the dynamic loader to enable shadow stacks for the 95 + program. 96 + 97 + 5. prctl() enabling 98 + -------------------- 99 + 100 + :c:macro:`PR_SET_SHADOW_STACK_STATUS` / :c:macro:`PR_GET_SHADOW_STACK_STATUS` / 101 + :c:macro:`PR_LOCK_SHADOW_STACK_STATUS` are three prctls added to manage shadow 102 + stack enabling for tasks. These prctls are architecture-agnostic and return 103 + -EINVAL if not implemented. 104 + 105 + * prctl(PR_SET_SHADOW_STACK_STATUS, unsigned long arg) 106 + 107 + If arg = :c:macro:`PR_SHADOW_STACK_ENABLE` and if CPU supports 108 + ``zicfiss`` then the kernel will enable shadow stacks for the task. 109 + The dynamic loader can issue this :c:macro:`prctl` once it has 110 + determined that all the objects loaded in address space have support 111 + for shadow stacks. Additionally, if there is a :c:macro:`dlopen` to 112 + an object which wasn't compiled with ``zicfiss``, the dynamic loader 113 + can issue this prctl with arg set to 0 (i.e. 114 + :c:macro:`PR_SHADOW_STACK_ENABLE` being clear) 115 + 116 + * prctl(PR_GET_SHADOW_STACK_STATUS, unsigned long * arg) 117 + 118 + Returns the current status of indirect branch tracking. If enabled 119 + it'll return :c:macro:`PR_SHADOW_STACK_ENABLE`. 120 + 121 + * prctl(PR_LOCK_SHADOW_STACK_STATUS, unsigned long arg) 122 + 123 + Locks the current status of shadow stack enabling on the 124 + task. Userspace may want to run with a strict security posture and 125 + wouldn't want loading of objects without ``zicfiss`` support. In this 126 + case userspace can use this prctl to disallow disabling of shadow 127 + stacks on the current task. 128 + 129 + 5. violations related to returns with shadow stack enabled 130 + ----------------------------------------------------------- 131 + 132 + Pertaining to shadow stacks, the CPU raises a ``software check 133 + exception`` upon executing ``sspopchk x1/x5`` if ``x1/x5`` doesn't 134 + match the top of shadow stack. If a mismatch happens, then the CPU 135 + sets ``*tval = 3`` and raises the exception. 136 + 137 + The Linux kernel will treat this as a :c:macro:`SIGSEGV` with code = 138 + :c:macro:`SEGV_CPERR` and follow the normal course of signal delivery. 139 + 140 + 6. Shadow stack tokens 141 + ----------------------- 142 + 143 + Regular stores on shadow stacks are not allowed and thus can't be 144 + tampered with via arbitrary stray writes. However, one method of 145 + pivoting / switching to a shadow stack is simply writing to the CSR 146 + ``CSR_SSP``. This will change the active shadow stack for the 147 + program. Writes to ``CSR_SSP`` in the program should be mostly 148 + limited to context switches, stack unwinds, or longjmp or similar 149 + mechanisms (like context switching of Green Threads) in languages like 150 + Go and Rust. CSR_SSP writes can be problematic because an attacker can 151 + use memory corruption bugs and leverage context switching routines to 152 + pivot to any shadow stack. Shadow stack tokens can help mitigate this 153 + problem by making sure that: 154 + 155 + - When software is switching away from a shadow stack, the shadow 156 + stack pointer should be saved on the shadow stack itself (this is 157 + called the ``shadow stack token``). 158 + 159 + - When software is switching to a shadow stack, it should read the 160 + ``shadow stack token`` from the shadow stack pointer and verify that 161 + the ``shadow stack token`` itself is a pointer to the shadow stack 162 + itself. 163 + 164 + - Once the token verification is done, software can perform the write 165 + to ``CSR_SSP`` to switch shadow stacks. 166 + 167 + Here "software" could refer to the user mode task runtime itself, 168 + managing various contexts as part of a single thread. Or "software" 169 + could refer to the kernel, when the kernel has to deliver a signal to 170 + a user task and must save the shadow stack pointer. The kernel can 171 + perform similar procedure itself by saving a token on the user mode 172 + task's shadow stack. This way, whenever :c:macro:`sigreturn` happens, 173 + the kernel can read and verify the token and then switch to the shadow 174 + stack. Using this mechanism, the kernel helps the user task so that 175 + any corruption issue in the user task is not exploited by adversaries 176 + arbitrarily using :c:macro:`sigreturn`. Adversaries will have to make 177 + sure that there is a valid ``shadow stack token`` in addition to 178 + invoking :c:macro:`sigreturn`. 179 + 180 + 7. Signal shadow stack 181 + ----------------------- 182 + The following structure has been added to sigcontext for RISC-V:: 183 + 184 + struct __sc_riscv_cfi_state { 185 + unsigned long ss_ptr; 186 + }; 187 + 188 + As part of signal delivery, the shadow stack token is saved on the 189 + current shadow stack itself. The updated pointer is saved away in the 190 + :c:macro:`ss_ptr` field in :c:macro:`__sc_riscv_cfi_state` under 191 + :c:macro:`sigcontext`. The existing shadow stack allocation is used 192 + for signal delivery. During :c:macro:`sigreturn`, kernel will obtain 193 + :c:macro:`ss_ptr` from :c:macro:`sigcontext`, verify the saved 194 + token on the shadow stack, and switch the shadow stack.