Blob Blame History Raw
From 5b9488612b350180dbd009755fbef287b4961362 Mon Sep 17 00:00:00 2001
From: Ram Pai <linuxram@us.ibm.com>
Date: Thu, 18 Jan 2018 17:50:42 -0800
Subject: [PATCH 40/45] powerpc: Deliver SEGV signal on pkey violation

References: FATE#322447, bsc#1078248
Patch-mainline: v4.16-rc1
Git-commit: 99cd1302327a2ccaedf905e9f6a8d8fd234bd485

The value of the pkey, whose protection got violated,
is made available in si_pkey field of the siginfo structure.

Signed-off-by: Ram Pai <linuxram@us.ibm.com>
Signed-off-by: Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Acked-by: Michal Suchanek <msuchanek@suse.de>
---
 arch/powerpc/include/asm/bug.h |  1 +
 arch/powerpc/kernel/traps.c    | 12 +++++++++++-
 arch/powerpc/mm/fault.c        | 12 ++++++++++--
 3 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/include/asm/bug.h b/arch/powerpc/include/asm/bug.h
index 3c04249bcf39..97c38472b924 100644
--- a/arch/powerpc/include/asm/bug.h
+++ b/arch/powerpc/include/asm/bug.h
@@ -133,6 +133,7 @@ struct pt_regs;
 extern int do_page_fault(struct pt_regs *, unsigned long, unsigned long);
 extern void bad_page_fault(struct pt_regs *, unsigned long, int);
 extern void _exception(int, struct pt_regs *, int, unsigned long);
+extern void _exception_pkey(int, struct pt_regs *, int, unsigned long, int);
 extern void die(const char *, struct pt_regs *, long);
 extern bool die_will_crash(void);
 
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index d139117d3339..4b1a8e2ec023 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -20,6 +20,7 @@
 #include <linux/sched/debug.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/pkeys.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
@@ -266,7 +267,9 @@ void user_single_step_siginfo(struct task_struct *tsk,
 	info->si_addr = (void __user *)regs->nip;
 }
 
-void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
+
+void _exception_pkey(int signr, struct pt_regs *regs, int code,
+		unsigned long addr, int key)
 {
 	siginfo_t info;
 	const char fmt32[] = KERN_INFO "%s[%d]: unhandled signal %d " \
@@ -293,9 +296,16 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
 	info.si_signo = signr;
 	info.si_code = code;
 	info.si_addr = (void __user *) addr;
+	info.si_pkey = key;
+
 	force_sig_info(signr, &info, current);
 }
 
+void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
+{
+	_exception_pkey(signr, regs, code, addr, 0);
+}
+
 void system_reset_exception(struct pt_regs *regs)
 {
 	/*
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index 3eba40e68d2d..05d4befd7166 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -205,6 +205,7 @@ int do_page_fault(struct pt_regs *regs, unsigned long address,
 	int trap = TRAP(regs);
  	int is_exec = trap == 0x400;
 	int is_user = user_mode(regs);
+	int pkey = 0;
 	int fault, major = 0;
 	int rc = 0, store_update_sp = 0;
 
@@ -270,6 +271,7 @@ int do_page_fault(struct pt_regs *regs, unsigned long address,
 
 	if (error_code & DSISR_KEYFAULT) {
 		code = SEGV_PKUERR;
+		pkey = get_mm_addr_key(mm, address);
 		goto bad_area_nosemaphore;
 	}
 
@@ -451,7 +453,13 @@ int do_page_fault(struct pt_regs *regs, unsigned long address,
 	if (unlikely(fault & VM_FAULT_SIGSEGV) &&
 		!arch_vma_access_permitted(vma, flags & FAULT_FLAG_WRITE,
 			is_exec, 0)) {
-		int pkey = vma_pkey(vma);
+		/*
+		 * The PGD-PDT...PMD-PTE tree may not have been fully setup.
+		 * Hence we cannot walk the tree to locate the PTE, to locate
+		 * the key. Hence let's use vma_pkey() to get the key; instead
+		 * of get_mm_addr_key().
+		 */
+		pkey = vma_pkey(vma);
 
 		if (likely(pkey)) {
 			code = SEGV_PKUERR;
@@ -524,7 +532,7 @@ int do_page_fault(struct pt_regs *regs, unsigned long address,
 bad_area_nosemaphore:
 	/* User mode accesses cause a SIGSEGV */
 	if (is_user) {
-		_exception(SIGSEGV, regs, code, address);
+		_exception_pkey(SIGSEGV, regs, code, address, pkey);
 		goto bail;
 	}
 
-- 
2.13.6