1*c70772afSDeepak Gupta // SPDX-License-Identifier: GPL-2.0 2*c70772afSDeepak Gupta /* 3*c70772afSDeepak Gupta * Copyright (C) 2024 Rivos, Inc. 4*c70772afSDeepak Gupta * Deepak Gupta <debug@rivosinc.com> 5*c70772afSDeepak Gupta */ 6*c70772afSDeepak Gupta 7*c70772afSDeepak Gupta #include <linux/sched.h> 8*c70772afSDeepak Gupta #include <linux/bitops.h> 9*c70772afSDeepak Gupta #include <linux/types.h> 10*c70772afSDeepak Gupta #include <linux/mm.h> 11*c70772afSDeepak Gupta #include <linux/mman.h> 12*c70772afSDeepak Gupta #include <linux/uaccess.h> 13*c70772afSDeepak Gupta #include <linux/sizes.h> 14*c70772afSDeepak Gupta #include <linux/user.h> 15*c70772afSDeepak Gupta #include <linux/syscalls.h> 16*c70772afSDeepak Gupta #include <linux/prctl.h> 17*c70772afSDeepak Gupta #include <asm/csr.h> 18*c70772afSDeepak Gupta #include <asm/usercfi.h> 19*c70772afSDeepak Gupta 20*c70772afSDeepak Gupta #define SHSTK_ENTRY_SIZE sizeof(void *) 21*c70772afSDeepak Gupta 22*c70772afSDeepak Gupta /* 23*c70772afSDeepak Gupta * Writes on shadow stack can either be `sspush` or `ssamoswap`. `sspush` can happen 24*c70772afSDeepak Gupta * implicitly on current shadow stack pointed to by CSR_SSP. `ssamoswap` takes pointer to 25*c70772afSDeepak Gupta * shadow stack. To keep it simple, we plan to use `ssamoswap` to perform writes on shadow 26*c70772afSDeepak Gupta * stack. 27*c70772afSDeepak Gupta */ 28*c70772afSDeepak Gupta static noinline unsigned long amo_user_shstk(unsigned long __user *addr, unsigned long val) 29*c70772afSDeepak Gupta { 30*c70772afSDeepak Gupta /* 31*c70772afSDeepak Gupta * Never expect -1 on shadow stack. Expect return addresses and zero 32*c70772afSDeepak Gupta */ 33*c70772afSDeepak Gupta unsigned long swap = -1; 34*c70772afSDeepak Gupta 35*c70772afSDeepak Gupta __enable_user_access(); 36*c70772afSDeepak Gupta asm goto(".option push\n" 37*c70772afSDeepak Gupta ".option arch, +zicfiss\n" 38*c70772afSDeepak Gupta "1: ssamoswap.d %[swap], %[val], %[addr]\n" 39*c70772afSDeepak Gupta _ASM_EXTABLE(1b, %l[fault]) 40*c70772afSDeepak Gupta ".option pop\n" 41*c70772afSDeepak Gupta : [swap] "=r" (swap), [addr] "+A" (*(__force unsigned long *)addr) 42*c70772afSDeepak Gupta : [val] "r" (val) 43*c70772afSDeepak Gupta : "memory" 44*c70772afSDeepak Gupta : fault 45*c70772afSDeepak Gupta ); 46*c70772afSDeepak Gupta __disable_user_access(); 47*c70772afSDeepak Gupta return swap; 48*c70772afSDeepak Gupta fault: 49*c70772afSDeepak Gupta __disable_user_access(); 50*c70772afSDeepak Gupta return -1; 51*c70772afSDeepak Gupta } 52*c70772afSDeepak Gupta 53*c70772afSDeepak Gupta /* 54*c70772afSDeepak Gupta * Create a restore token on the shadow stack. A token is always XLEN wide 55*c70772afSDeepak Gupta * and aligned to XLEN. 56*c70772afSDeepak Gupta */ 57*c70772afSDeepak Gupta static int create_rstor_token(unsigned long ssp, unsigned long *token_addr) 58*c70772afSDeepak Gupta { 59*c70772afSDeepak Gupta unsigned long addr; 60*c70772afSDeepak Gupta 61*c70772afSDeepak Gupta /* Token must be aligned */ 62*c70772afSDeepak Gupta if (!IS_ALIGNED(ssp, SHSTK_ENTRY_SIZE)) 63*c70772afSDeepak Gupta return -EINVAL; 64*c70772afSDeepak Gupta 65*c70772afSDeepak Gupta /* On RISC-V we're constructing token to be function of address itself */ 66*c70772afSDeepak Gupta addr = ssp - SHSTK_ENTRY_SIZE; 67*c70772afSDeepak Gupta 68*c70772afSDeepak Gupta if (amo_user_shstk((unsigned long __user *)addr, (unsigned long)ssp) == -1) 69*c70772afSDeepak Gupta return -EFAULT; 70*c70772afSDeepak Gupta 71*c70772afSDeepak Gupta if (token_addr) 72*c70772afSDeepak Gupta *token_addr = addr; 73*c70772afSDeepak Gupta 74*c70772afSDeepak Gupta return 0; 75*c70772afSDeepak Gupta } 76*c70772afSDeepak Gupta 77*c70772afSDeepak Gupta static unsigned long allocate_shadow_stack(unsigned long addr, unsigned long size, 78*c70772afSDeepak Gupta unsigned long token_offset, bool set_tok) 79*c70772afSDeepak Gupta { 80*c70772afSDeepak Gupta int flags = MAP_ANONYMOUS | MAP_PRIVATE; 81*c70772afSDeepak Gupta struct mm_struct *mm = current->mm; 82*c70772afSDeepak Gupta unsigned long populate; 83*c70772afSDeepak Gupta 84*c70772afSDeepak Gupta if (addr) 85*c70772afSDeepak Gupta flags |= MAP_FIXED_NOREPLACE; 86*c70772afSDeepak Gupta 87*c70772afSDeepak Gupta mmap_write_lock(mm); 88*c70772afSDeepak Gupta addr = do_mmap(NULL, addr, size, PROT_READ, flags, 89*c70772afSDeepak Gupta VM_SHADOW_STACK | VM_WRITE, 0, &populate, NULL); 90*c70772afSDeepak Gupta mmap_write_unlock(mm); 91*c70772afSDeepak Gupta 92*c70772afSDeepak Gupta if (!set_tok || IS_ERR_VALUE(addr)) 93*c70772afSDeepak Gupta goto out; 94*c70772afSDeepak Gupta 95*c70772afSDeepak Gupta if (create_rstor_token(addr + token_offset, NULL)) { 96*c70772afSDeepak Gupta vm_munmap(addr, size); 97*c70772afSDeepak Gupta return -EINVAL; 98*c70772afSDeepak Gupta } 99*c70772afSDeepak Gupta 100*c70772afSDeepak Gupta out: 101*c70772afSDeepak Gupta return addr; 102*c70772afSDeepak Gupta } 103*c70772afSDeepak Gupta 104*c70772afSDeepak Gupta SYSCALL_DEFINE3(map_shadow_stack, unsigned long, addr, unsigned long, size, unsigned int, flags) 105*c70772afSDeepak Gupta { 106*c70772afSDeepak Gupta bool set_tok = flags & SHADOW_STACK_SET_TOKEN; 107*c70772afSDeepak Gupta unsigned long aligned_size = 0; 108*c70772afSDeepak Gupta 109*c70772afSDeepak Gupta if (!cpu_supports_shadow_stack()) 110*c70772afSDeepak Gupta return -EOPNOTSUPP; 111*c70772afSDeepak Gupta 112*c70772afSDeepak Gupta /* Anything other than set token should result in invalid param */ 113*c70772afSDeepak Gupta if (flags & ~SHADOW_STACK_SET_TOKEN) 114*c70772afSDeepak Gupta return -EINVAL; 115*c70772afSDeepak Gupta 116*c70772afSDeepak Gupta /* 117*c70772afSDeepak Gupta * Unlike other architectures, on RISC-V, SSP pointer is held in CSR_SSP and is an available 118*c70772afSDeepak Gupta * CSR in all modes. CSR accesses are performed using 12bit index programmed in instruction 119*c70772afSDeepak Gupta * itself. This provides static property on register programming and writes to CSR can't 120*c70772afSDeepak Gupta * be unintentional from programmer's perspective. As long as programmer has guarded areas 121*c70772afSDeepak Gupta * which perform writes to CSR_SSP properly, shadow stack pivoting is not possible. Since 122*c70772afSDeepak Gupta * CSR_SSP is writable by user mode, it itself can setup a shadow stack token subsequent 123*c70772afSDeepak Gupta * to allocation. Although in order to provide portablity with other architectures (because 124*c70772afSDeepak Gupta * `map_shadow_stack` is arch agnostic syscall), RISC-V will follow expectation of a token 125*c70772afSDeepak Gupta * flag in flags and if provided in flags, will setup a token at the base. 126*c70772afSDeepak Gupta */ 127*c70772afSDeepak Gupta 128*c70772afSDeepak Gupta /* If there isn't space for a token */ 129*c70772afSDeepak Gupta if (set_tok && size < SHSTK_ENTRY_SIZE) 130*c70772afSDeepak Gupta return -ENOSPC; 131*c70772afSDeepak Gupta 132*c70772afSDeepak Gupta if (addr && (addr & (PAGE_SIZE - 1))) 133*c70772afSDeepak Gupta return -EINVAL; 134*c70772afSDeepak Gupta 135*c70772afSDeepak Gupta aligned_size = PAGE_ALIGN(size); 136*c70772afSDeepak Gupta if (aligned_size < size) 137*c70772afSDeepak Gupta return -EOVERFLOW; 138*c70772afSDeepak Gupta 139*c70772afSDeepak Gupta return allocate_shadow_stack(addr, aligned_size, size, set_tok); 140*c70772afSDeepak Gupta } 141