Messages in this thread Patch in this message | | | From | Deepak Gupta <> | Subject | [PATCH v1 RFC Zisslpcfi 06/20] riscv: Implementing "PROT_SHADOWSTACK" on riscv | Date | Sun, 12 Feb 2023 20:53:35 -0800 |
| |
This patchimplements new mmap protection flag "PROT_SHADOWSTACK" on riscv
Zisslpcfi extension on riscv uses R=0, W=1, X=0 as shadow stack PTE encoding. This encoding is reserved if Zisslpcfi is not implemented or backward cfi is not enabled for the respective mode.
Signed-off-by: Deepak Gupta <debug@rivosinc.com> --- arch/riscv/include/asm/mman.h | 19 +++++++++++++++++++ arch/riscv/include/asm/pgtable.h | 1 + arch/riscv/kernel/sys_riscv.c | 22 ++++++++++++++++++++++ arch/riscv/mm/init.c | 2 +- 4 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 arch/riscv/include/asm/mman.h
diff --git a/arch/riscv/include/asm/mman.h b/arch/riscv/include/asm/mman.h new file mode 100644 index 000000000000..9c8499294a60 --- /dev/null +++ b/arch/riscv/include/asm/mman.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_MMAN_H__ +#define __ASM_MMAN_H__ + +#include <linux/compiler.h> +#include <linux/types.h> +#include <uapi/asm/mman.h> + +static inline unsigned long arch_calc_vm_prot_bits(unsigned long prot, + unsigned long pkey __always_unused) +{ + unsigned long ret = 0; + + ret = (prot & PROT_SHADOWSTACK)?VM_WRITE:0; + return ret; +} +#define arch_calc_vm_prot_bits(prot, pkey) arch_calc_vm_prot_bits(prot, pkey) + +#endif /* ! __ASM_MMAN_H__ */ diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h index 4eba9a98d0e3..74dbe122f2fa 100644 --- a/arch/riscv/include/asm/pgtable.h +++ b/arch/riscv/include/asm/pgtable.h @@ -159,6 +159,7 @@ extern struct pt_alloc_ops pt_ops __initdata; #define PAGE_READ_EXEC __pgprot(_PAGE_BASE | _PAGE_READ | _PAGE_EXEC) #define PAGE_WRITE_EXEC __pgprot(_PAGE_BASE | _PAGE_READ | \ _PAGE_EXEC | _PAGE_WRITE) +#define PAGE_SHADOWSTACK __pgprot(_PAGE_BASE | _PAGE_WRITE) #define PAGE_COPY PAGE_READ #define PAGE_COPY_EXEC PAGE_EXEC diff --git a/arch/riscv/kernel/sys_riscv.c b/arch/riscv/kernel/sys_riscv.c index 5d3f2fbeb33c..c3cf6b94c710 100644 --- a/arch/riscv/kernel/sys_riscv.c +++ b/arch/riscv/kernel/sys_riscv.c @@ -18,6 +18,28 @@ static long riscv_sys_mmap(unsigned long addr, unsigned long len, if (unlikely(offset & (~PAGE_MASK >> page_shift_offset))) return -EINVAL; + /* + * If only PROT_WRITE is specified then extend that to PROT_READ + * protection_map[VM_WRITE] is now going to select shadow stack encodings. + * So specifying PROT_WRITE actually should select protection_map [VM_WRITE | VM_READ] + * If user wants to create shadow stack then they should specify PROT_SHADOWSTACK + * protection + */ + if (unlikely((prot & PROT_WRITE) && !(prot & PROT_READ))) + prot |= PROT_READ; + + /* + * PROT_SHADOWSTACK is new protection flag. If specified with other like PROT_WRITE or + * PROT_READ PROT_SHADOWSTACK takes precedence. We can do either of following + * - ensure no other protection flags are specified along with it and return EINVAL + * OR + * - ensure we clear other protection flags. + * Choosing to follow former, if any other bit is set in prot, we return EINVAL + * Other architectures can treat different combinations for PROT_SHADOWSTACK + */ + if (unlikely((prot & PROT_SHADOWSTACK) && (prot & ~PROT_SHADOWSTACK))) + return -EINVAL; + return ksys_mmap_pgoff(addr, len, prot, flags, fd, offset >> (PAGE_SHIFT - page_shift_offset)); } diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c index 478d6763a01a..ba8138c90450 100644 --- a/arch/riscv/mm/init.c +++ b/arch/riscv/mm/init.c @@ -294,7 +294,7 @@ static pmd_t __maybe_unused early_dtb_pmd[PTRS_PER_PMD] __initdata __aligned(PAG static const pgprot_t protection_map[16] = { [VM_NONE] = PAGE_NONE, [VM_READ] = PAGE_READ, - [VM_WRITE] = PAGE_COPY, + [VM_WRITE] = PAGE_SHADOWSTACK, [VM_WRITE | VM_READ] = PAGE_COPY, [VM_EXEC] = PAGE_EXEC, [VM_EXEC | VM_READ] = PAGE_READ_EXEC, -- 2.25.1
| |