xref: /linux/arch/riscv/kernel/usercfi.c (revision c70772afd5cc93c28f83b53d33ce9fbcd8d015da)
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