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/mm: ensure PROT_WRITE leads to VM_READ | VM_WRITE

'arch_calc_vm_prot_bits' is implemented on risc-v to return VM_READ |
VM_WRITE if PROT_WRITE is specified. Similarly 'riscv_sys_mmap' is
updated to convert all incoming PROT_WRITE to (PROT_WRITE | PROT_READ).
This is to make sure that any existing apps using PROT_WRITE still work.

Earlier 'protection_map[VM_WRITE]' used to pick read-write PTE encodings.
Now 'protection_map[VM_WRITE]' will always pick PAGE_SHADOWSTACK PTE
encodings for shadow stack. The above changes ensure that existing apps
continue to work because underneath, the kernel will be picking
'protection_map[VM_WRITE|VM_READ]' PTE encodings.

Reviewed-by: Zong Li <zong.li@sifive.com>
Reviewed-by: Alexandre Ghiti <alexghiti@rivosinc.com>
Signed-off-by: Deepak Gupta <debug@rivosinc.com>
Tested-by: Andreas Korb <andreas.korb@aisec.fraunhofer.de> # QEMU, custom CVA6
Tested-by: Valentin Haudiquet <valentin.haudiquet@canonical.com>
Link: https://patch.msgid.link/20251112-v5_user_cfi_series-v23-6-b55691eacf4f@rivosinc.com
Signed-off-by: Paul Walmsley <pjw@kernel.org>

authored by

Deepak Gupta and committed by
Paul Walmsley
6c7559f2 79dd4f2f

+38 -1
+26
arch/riscv/include/asm/mman.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef __ASM_MMAN_H__ 3 + #define __ASM_MMAN_H__ 4 + 5 + #include <linux/compiler.h> 6 + #include <linux/types.h> 7 + #include <linux/mm.h> 8 + #include <uapi/asm/mman.h> 9 + 10 + static inline unsigned long arch_calc_vm_prot_bits(unsigned long prot, 11 + unsigned long pkey __always_unused) 12 + { 13 + unsigned long ret = 0; 14 + 15 + /* 16 + * If PROT_WRITE was specified, force it to VM_READ | VM_WRITE. 17 + * Only VM_WRITE means shadow stack. 18 + */ 19 + if (prot & PROT_WRITE) 20 + ret = (VM_READ | VM_WRITE); 21 + return ret; 22 + } 23 + 24 + #define arch_calc_vm_prot_bits(prot, pkey) arch_calc_vm_prot_bits(prot, pkey) 25 + 26 + #endif /* ! __ASM_MMAN_H__ */
+1
arch/riscv/include/asm/pgtable.h
··· 178 178 #define PAGE_READ_EXEC __pgprot(_PAGE_BASE | _PAGE_READ | _PAGE_EXEC) 179 179 #define PAGE_WRITE_EXEC __pgprot(_PAGE_BASE | _PAGE_READ | \ 180 180 _PAGE_EXEC | _PAGE_WRITE) 181 + #define PAGE_SHADOWSTACK __pgprot(_PAGE_BASE | _PAGE_WRITE) 181 182 182 183 #define PAGE_COPY PAGE_READ 183 184 #define PAGE_COPY_EXEC PAGE_READ_EXEC
+10
arch/riscv/kernel/sys_riscv.c
··· 7 7 8 8 #include <linux/syscalls.h> 9 9 #include <asm/cacheflush.h> 10 + #include <asm-generic/mman-common.h> 10 11 11 12 static long riscv_sys_mmap(unsigned long addr, unsigned long len, 12 13 unsigned long prot, unsigned long flags, ··· 16 15 { 17 16 if (unlikely(offset & (~PAGE_MASK >> page_shift_offset))) 18 17 return -EINVAL; 18 + 19 + /* 20 + * If PROT_WRITE is specified then extend that to PROT_READ 21 + * protection_map[VM_WRITE] is now going to select shadow stack encodings. 22 + * So specifying PROT_WRITE actually should select protection_map [VM_WRITE | VM_READ] 23 + * If user wants to create shadow stack then they should use `map_shadow_stack` syscall. 24 + */ 25 + if (unlikely((prot & PROT_WRITE) && !(prot & PROT_READ))) 26 + prot |= PROT_READ; 19 27 20 28 return ksys_mmap_pgoff(addr, len, prot, flags, fd, 21 29 offset >> (PAGE_SHIFT - page_shift_offset));
+1 -1
arch/riscv/mm/init.c
··· 376 376 static const pgprot_t protection_map[16] = { 377 377 [VM_NONE] = PAGE_NONE, 378 378 [VM_READ] = PAGE_READ, 379 - [VM_WRITE] = PAGE_COPY, 379 + [VM_WRITE] = PAGE_SHADOWSTACK, 380 380 [VM_WRITE | VM_READ] = PAGE_COPY, 381 381 [VM_EXEC] = PAGE_EXEC, 382 382 [VM_EXEC | VM_READ] = PAGE_READ_EXEC,