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 landing pad / indirect branch tracking

Add documentation on landing pad aka indirect branch tracking 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-26-b55691eacf4f@rivosinc.com
[pjw@kernel.org: cleaned up the documentation]
Signed-off-by: Paul Walmsley <pjw@kernel.org>

authored by

Deepak Gupta and committed by
Paul Walmsley
f6eeb67b 22c1e263

+123
+1
Documentation/arch/riscv/index.rst
··· 14 14 uabi 15 15 vector 16 16 cmodx 17 + zicfilp 17 18 18 19 features 19 20
+122
Documentation/arch/riscv/zicfilp.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0 2 + 3 + :Author: Deepak Gupta <debug@rivosinc.com> 4 + :Date: 12 January 2024 5 + 6 + ==================================================== 7 + Tracking indirect control transfers on RISC-V Linux 8 + ==================================================== 9 + 10 + This document briefly describes the interface provided to userspace by Linux 11 + to enable indirect branch tracking 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 can result in a variety of 18 + security issues. 19 + 20 + Some of those security issues can be code re-use attacks, where an 21 + adversary can use corrupt function pointers, chaining them together to 22 + perform jump oriented programming (JOP) or call oriented programming 23 + (COP) and thus compromise control flow integrity (CFI) of the program. 24 + 25 + Function pointers live in read-write memory and thus are susceptible 26 + to corruption. This can allow an adversary to control the program 27 + counter (PC) value. On RISC-V, the zicfilp extension enforces a 28 + restriction on such indirect control transfers: 29 + 30 + - Indirect control transfers must land on a landing pad instruction ``lpad``. 31 + There are two exceptions to this rule: 32 + 33 + - rs1 = x1 or rs1 = x5, i.e. a return from a function and returns are 34 + protected using shadow stack (see zicfiss.rst) 35 + 36 + - rs1 = x7. On RISC-V, the compiler usually does the following to reach a 37 + function which is beyond the offset of possible J-type instruction:: 38 + 39 + auipc x7, <imm> 40 + jalr (x7) 41 + 42 + This form of indirect control transfer is immutable and doesn't 43 + rely on memory. Thus rs1=x7 is exempted from tracking and 44 + these are considered software guarded jumps. 45 + 46 + The ``lpad`` instruction is a pseudo-op of ``auipc rd, <imm_20bit>`` 47 + with ``rd=x0``. This is a HINT op. The ``lpad`` instruction must be 48 + aligned on a 4 byte boundary. It compares the 20 bit immediate with 49 + x7. If ``imm_20bit`` == 0, the CPU doesn't perform any comparison with 50 + ``x7``. If ``imm_20bit`` != 0, then ``imm_20bit`` must match ``x7`` 51 + else CPU will raise ``software check exception`` (``cause=18``) with 52 + ``*tval = 2``. 53 + 54 + The compiler can generate a hash over function signatures and set them 55 + up (truncated to 20 bits) in x7 at callsites. Function prologues can 56 + have ``lpad`` instructions encoded with the same function hash. This 57 + further reduces the number of valid program counter addresses a call 58 + site can reach. 59 + 60 + 2. ELF and psABI 61 + ----------------- 62 + 63 + The toolchain sets up :c:macro:`GNU_PROPERTY_RISCV_FEATURE_1_FCFI` for 64 + property :c:macro:`GNU_PROPERTY_RISCV_FEATURE_1_AND` in the notes 65 + section of the object file. 66 + 67 + 3. Linux enabling 68 + ------------------ 69 + 70 + User space programs can have multiple shared objects loaded in their 71 + address spaces. It's a difficult task to make sure all the 72 + dependencies have been compiled with indirect branch support. Thus 73 + it's left to the dynamic loader to enable indirect branch tracking for 74 + the program. 75 + 76 + 4. prctl() enabling 77 + -------------------- 78 + 79 + :c:macro:`PR_SET_INDIR_BR_LP_STATUS` / :c:macro:`PR_GET_INDIR_BR_LP_STATUS` / 80 + :c:macro:`PR_LOCK_INDIR_BR_LP_STATUS` are three prctls added to manage indirect 81 + branch tracking. These prctls are architecture-agnostic and return -EINVAL if 82 + the underlying functionality is not supported. 83 + 84 + * prctl(PR_SET_INDIR_BR_LP_STATUS, unsigned long arg) 85 + 86 + If arg1 is :c:macro:`PR_INDIR_BR_LP_ENABLE` and if CPU supports 87 + ``zicfilp`` then the kernel will enable indirect branch tracking for the 88 + task. The dynamic loader can issue this :c:macro:`prctl` once it has 89 + determined that all the objects loaded in the address space support 90 + indirect branch tracking. Additionally, if there is a `dlopen` to an 91 + object which wasn't compiled with ``zicfilp``, the dynamic loader can 92 + issue this prctl with arg1 set to 0 (i.e. :c:macro:`PR_INDIR_BR_LP_ENABLE` 93 + cleared). 94 + 95 + * prctl(PR_GET_INDIR_BR_LP_STATUS, unsigned long * arg) 96 + 97 + Returns the current status of indirect branch tracking. If enabled 98 + it'll return :c:macro:`PR_INDIR_BR_LP_ENABLE` 99 + 100 + * prctl(PR_LOCK_INDIR_BR_LP_STATUS, unsigned long arg) 101 + 102 + Locks the current status of indirect branch tracking on the task. User 103 + space may want to run with a strict security posture and wouldn't want 104 + loading of objects without ``zicfilp`` support in them, to disallow 105 + disabling of indirect branch tracking. In this case, user space can 106 + use this prctl to lock the current settings. 107 + 108 + 5. violations related to indirect branch tracking 109 + -------------------------------------------------- 110 + 111 + Pertaining to indirect branch tracking, the CPU raises a software 112 + check exception in the following conditions: 113 + 114 + - missing ``lpad`` after indirect call / jmp 115 + - ``lpad`` not on 4 byte boundary 116 + - ``imm_20bit`` embedded in ``lpad`` instruction doesn't match with ``x7`` 117 + 118 + In all 3 cases, ``*tval = 2`` is captured and software check exception is 119 + raised (``cause=18``). 120 + 121 + The kernel will treat this as :c:macro:`SIGSEGV` with code = 122 + :c:macro:`SEGV_CPERR` and follow the normal course of signal delivery.