Signed-off-by: Helge Deller <deller@xxxxxx> --- diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index afc3b8d03572..e4a6ae388eb3 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -47,6 +47,7 @@ config PARISC select HAVE_ARCH_HASH select HAVE_ARCH_JUMP_LABEL select HAVE_ARCH_JUMP_LABEL_RELATIVE + select HAVE_ARCH_KFENCE select HAVE_ARCH_SECCOMP_FILTER select HAVE_ARCH_TRACEHOOK select HAVE_REGS_AND_STACK_ACCESS_API @@ -257,11 +258,11 @@ config PARISC_PAGE_SIZE_4KB config PARISC_PAGE_SIZE_16KB bool "16KB" - depends on PA8X00 && BROKEN + depends on PA8X00 && BROKEN && !KFENCE config PARISC_PAGE_SIZE_64KB bool "64KB" - depends on PA8X00 && BROKEN + depends on PA8X00 && BROKEN && !KFENCE endchoice diff --git a/arch/parisc/include/asm/kfence.h b/arch/parisc/include/asm/kfence.h new file mode 100644 index 000000000000..41982ed5617b --- /dev/null +++ b/arch/parisc/include/asm/kfence.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * PA-RISC KFENCE support. + * + * Copyright (C) 2021, Helge Deller <deller@xxxxxx> + */ + +#ifndef _ASM_PARISC_KFENCE_H +#define _ASM_PARISC_KFENCE_H + +#include <linux/kfence.h> + +#include <asm/pgtable.h> +#include <asm/tlbflush.h> + +static inline bool arch_kfence_init_pool(void) +{ + return true; +} + +/* Protect the given page and flush TLB. */ +static inline bool kfence_protect_page(unsigned long addr, bool protect) +{ + pte_t *pte = virt_to_kpte(addr); + + if (WARN_ON(!pte)) + return false; + + /* + * We need to avoid IPIs, as we may get KFENCE allocations or faults + * with interrupts disabled. + */ + + if (protect) { + set_pte(pte, __pte(pte_val(*pte) & ~_PAGE_PRESENT)); + flush_tlb_kernel_range(addr, addr + PAGE_SIZE); + } + else + set_pte(pte, __pte(pte_val(*pte) | _PAGE_PRESENT)); + + + return true; +} + +#endif /* _ASM_PARISC_KFENCE_H */ diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c index 716960f5d92e..ae4398ba0b7d 100644 --- a/arch/parisc/mm/fault.c +++ b/arch/parisc/mm/fault.c @@ -19,6 +19,7 @@ #include <linux/uaccess.h> #include <linux/hugetlb.h> #include <linux/perf_event.h> +#include <linux/kfence.h> #include <asm/traps.h> @@ -416,6 +417,10 @@ void do_page_fault(struct pt_regs *regs, unsigned long code, return; } + if (!user_mode(regs) && + kfence_handle_page_fault(address, flags & FAULT_FLAG_WRITE, regs)) + return; + parisc_terminate("Bad Address (null pointer deref?)", regs, code, address); out_of_memory: