[PATCH V8 18/44] x86/fault: Add a PKS test fault hook

ira.weiny
2022-01-27T17:55:29Z

From: Ira Weiny <ira.weiny@intel.com>

The PKS test code is going to purposely create faults when testing
invalid access. It will need a way to flag those faults as invalid and
keep the kernel running properly.

Create a hook in the fault handler to call back into the test code such
that the test code can track when a test it runs results in a fault.

The hook returns if the fault was caused by the test code so the main
handler can consider the fault handled. Also the hook is responsible to
clear up the reason for the fault.

Predicate the hook on CONFIG_PKS_TEST.

Signed-off-by: Ira Weiny <ira.weiny@intel.com>
---
arch/x86/include/asm/pks.h | 14 ++++++++++++++
arch/x86/mm/fault.c | 30 ++++++++++++++++++++----------
lib/pks/pks_test.c | 12 ++++++++++++
3 files changed, 46 insertions(+), 10 deletions(-)

diff --git a/arch/x86/include/asm/pks.h b/arch/x86/include/asm/pks.h
index d211bf36492c..ee9fff5b4b13 100644
--- a/arch/x86/include/asm/pks.h
+++ b/arch/x86/include/asm/pks.h
@@ -14,4 +14,18 @@ static inline void pks_write_current(void) { }

#endif /* CONFIG_ARCH_ENABLE_SUPERVISOR_PKEYS */

+
+#ifdef CONFIG_PKS_TEST
+
+bool pks_test_callback(void);
+
+#else /* !CONFIG_PKS_TEST */
+
+static inline bool pks_test_callback(void)
+{
+ return false;
+}
+
+#endif /* CONFIG_PKS_TEST */
+
#endif /* _ASM_X86_PKS_H */
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 6ed91b632eac..bef879943260 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -33,6 +33,7 @@
#include <asm/kvm_para.h> /* kvm_handle_async_pf */
#include <asm/vdso.h> /* fixup_vdso_exception() */
#include <asm/irq_stack.h>
+#include <asm/pks.h>

#define CREATE_TRACE_POINTS
#include <asm/trace/exceptions.h>
@@ -1147,16 +1148,25 @@ static void
do_kern_addr_fault(struct pt_regs *regs, unsigned long hw_error_code,
unsigned long address)
{
- /*
- * X86_PF_PK (Protection key exceptions) may occur on kernel addresses
- * when PKS (PKeys Supervisor) is enabled.
- *
- * However, if PKS is not enabled WARN if this exception is seen
- * because there are no user pages in the kernel portion of the address
- * space.
- */
- WARN_ON_ONCE(!cpu_feature_enabled(X86_FEATURE_PKS) &&
- (hw_error_code & X86_PF_PK));
+ if (hw_error_code & X86_PF_PK) {
+ /*
+ * X86_PF_PK (Protection key exceptions) may occur on kernel
+ * addresses when PKS (PKeys Supervisor) is enabled.
+ *
+ * However, if PKS is not enabled WARN if this exception is
+ * seen because there are no user pages in the kernel portion
+ * of the address space.
+ */
+ WARN_ON_ONCE(!cpu_feature_enabled(X86_FEATURE_PKS));
+
+ /*
+ * If a protection key exception occurs it could be because a PKS test
+ * is running. If so, pks_test_callback() will clear the protection
+ * mechanism and return true to indicate the fault was handled.
+ */
+ if (pks_test_callback())
+ return;
+ }

#ifdef CONFIG_X86_32
/*
diff --git a/lib/pks/pks_test.c b/lib/pks/pks_test.c
index 159576dda47c..d84ab6e7a09c 100644
--- a/lib/pks/pks_test.c
+++ b/lib/pks/pks_test.c
@@ -47,6 +47,18 @@ struct pks_test_ctx {
char data[64];
};

+/*
+ * pks_test_callback() is called by the fault handler to indicate it saw a PKey
+ * fault.
+ *
+ * NOTE: The callback is responsible for clearing any condition which would
+ * cause the fault to re-trigger.
+ */
+bool pks_test_callback(void)
+{
+ return false;
+}
+
static void *alloc_test_page(int pkey)
{
return __vmalloc_node_range(PKS_TEST_MEM_SIZE, 1, VMALLOC_START, VMALLOC_END,
--
2.31.1