Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1303164 > unrolled thread
| Started by | Dave Hansen <dave@sr71.net> |
|---|---|
| First post | 2016-01-07 01:10 +0100 |
| Last post | 2016-01-07 01:20 +0100 |
| Articles | 20 on this page of 42 — 5 participants |
Back to article view | Back to linux.kernel
[PATCH 00/31] x86: Memory Protection Keys (v8) Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 22/31] x86, pkeys: dump pkey from VMA in /proc/pid/smaps Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 28/31] x86, fpu: allow setting of XSAVE state Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 06/31] x86, pkeys: add PKRU xsave fields and data structure(s) Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 07/31] x86, pkeys: PTE bits for storing protection key Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 01/31] mm, gup: introduce concept of "foreign" get_user_pages() Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
Re: [PATCH 01/31] mm, gup: introduce concept of "foreign" get_user_pages() Vlastimil Babka <vbabka@suse.cz> - 2016-01-13 20:10 +0100
Re: [PATCH 01/31] mm, gup: introduce concept of "foreign" get_user_pages() Dave Hansen <dave@sr71.net> - 2016-01-13 20:20 +0100
[PATCH 17/31] x86, pkeys: check VMAs and PTEs for protection keys Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 03/31] x86, pkeys: Add Kconfig option Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 29/31] x86, pkeys: allow kernel to modify user pkey rights register Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 21/31] x86, pkeys: dump PKRU with other kernel registers Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 11/31] x86, pkeys: pass VMA down in to fault signal generation code Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 10/31] x86, pkeys: arch-specific protection bits Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 19/31] x86, pkeys: optimize fault handling in access_error() Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 05/31] x86, pkeys: define new CR4 bit Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 09/31] x86, pkeys: store protection in high VMA flags Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 16/31] x86, mm: simplify get_user_pages() PTE bit handling Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 27/31] x86: separate out LDT init from context init Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 14/31] x86, pkeys: add functions to fetch PKRU Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
Re: [PATCH 14/31] x86, pkeys: add functions to fetch PKRU Thomas Gleixner <tglx@linutronix.de> - 2016-01-08 20:40 +0100
[PATCH 31/31] x86, pkeys: execute-only support Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
Re: [PATCH 31/31] x86, pkeys: execute-only support Kees Cook <keescook@google.com> - 2016-01-07 22:10 +0100
Re: [PATCH 31/31] x86, pkeys: execute-only support Dave Hansen <dave@sr71.net> - 2016-01-07 23:30 +0100
Re: [PATCH 31/31] x86, pkeys: execute-only support Andy Lutomirski <luto@amacapital.net> - 2016-01-07 22:20 +0100
Re: [PATCH 31/31] x86, pkeys: execute-only support Dave Hansen <dave@sr71.net> - 2016-01-07 23:20 +0100
Re: [PATCH 31/31] x86, pkeys: execute-only support Andy Lutomirski <luto@amacapital.net> - 2016-01-07 23:50 +0100
Re: [PATCH 31/31] x86, pkeys: execute-only support Thomas Gleixner <tglx@linutronix.de> - 2016-01-08 21:00 +0100
[PATCH 24/31] x86, pkeys: actually enable Memory Protection Keys in CPU Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 30/31] x86, pkeys: create an x86 arch_calc_vm_prot_bits() for VMA flags Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 18/31] mm: add gup flag to indicate "foreign" mm access Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 26/31] x86, pkeys: add arch_validate_pkey() Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
Re: [PATCH 26/31] x86, pkeys: add arch_validate_pkey() Thomas Gleixner <tglx@linutronix.de> - 2016-01-08 20:40 +0100
[PATCH 08/31] x86, pkeys: new page fault error code bit: PF_PK Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 13/31] x86, pkeys: fill in pkey field in siginfo Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 12/31] signals, pkeys: notify userspace about protection key faults Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 23/31] x86, pkeys: add Kconfig prompt to existing config option Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 15/31] mm: factor out VMA fault permission checking Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 04/31] x86, pkeys: cpuid bit definition Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 20/31] x86, pkeys: differentiate instruction fetches Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 25/31] mm, multi-arch: pass a protection key in to calc_vm_flag_bits() Dave Hansen <dave@sr71.net> - 2016-01-07 01:10 +0100
[PATCH 02/31] x86, fpu: add placeholder for Processor Trace XSAVE state Dave Hansen <dave@sr71.net> - 2016-01-07 01:20 +0100
Page 2 of 3 — ← Prev page 1 [2] 3 Next page →
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2016-01-08 20:40 +0100 |
| Subject | Re: [PATCH 14/31] x86, pkeys: add functions to fetch PKRU |
| Message-ID | <qOL3c-2Tb-5@gated-at.bofh.it> |
| In reply to | #1303183 |
On Wed, 6 Jan 2016, Dave Hansen wrote: > > From: Dave Hansen <dave.hansen@linux.intel.com> > > This adds the raw instruction to access PKRU as well as some > accessor functions that correctly handle when the CPU does not > support the instruction. We don't use it here, but we will use > read_pkru() in the next patch. > > Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2016-01-07 01:10 +0100 |
| Subject | [PATCH 31/31] x86, pkeys: execute-only support |
| Message-ID | <qO6jq-8sH-49@gated-at.bofh.it> |
| In reply to | #1303164 |
From: Dave Hansen <dave.hansen@linux.intel.com>
Protection keys provide new page-based protection in hardware.
But, they have an interesting attribute: they only affect data
accesses and never affect instruction fetches. That means that
if we set up some memory which is set as "access-disabled" via
protection keys, we can still execute from it.
This patch uses protection keys to set up mappings to do just that.
If a user calls:
mmap(..., PROT_EXEC);
or
mprotect(ptr, sz, PROT_EXEC);
(note PROT_EXEC-only without PROT_READ/WRITE), the kernel will
notice this, and set a special protection key on the memory. It
also sets the appropriate bits in the Protection Keys User Rights
(PKRU) register so that the memory becomes unreadable and
unwritable.
I haven't found any userspace that does this today. With this
facility in place, we expect userspace to move to use it
eventually.
The security provided by this approach is not comprehensive. The
PKRU register which controls access permissions is a normal
user register writable from unprivileged userspace. An attacker
who can execute the 'wrpkru' instruction can easily disable the
protection provided by this feature.
The protection key that is used for execute-only support is
permanently dedicated at compile time. This is fine for now
because there is currently no API to set a protection key other
than this one.
Despite there being a constant PKRU value across the entire
system, we do not set it unless this feature is in use in a
process. That is to preserve the PKRU XSAVE 'init state',
which can lead to faster context switches.
PKRU *is* a user register and the kernel is modifying it. That
means that code doing:
pkru = rdpkru()
pkru |= 0x100;
mmap(..., PROT_EXEC);
wrpkru(pkru);
could lose the bits in PKRU that enforce execute-only
permissions. To avoid this, we suggest avoiding ever calling
mmap() or mprotect() when the PKRU value is expected to be
stable.
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Cc: LKML <linux-kernel@vger.kernel.org>
Cc: x86@kernel.org
Cc: torvalds@linux-foundation.org
Cc: akpm@linux-foundation.org
Cc: linux-mm@kvack.org
Cc: keescook@google.com
Cc: luto@amacapital.net
---
b/arch/x86/include/asm/pkeys.h | 25 ++++++++++
b/arch/x86/kernel/fpu/xstate.c | 2
b/arch/x86/mm/Makefile | 2
b/arch/x86/mm/fault.c | 13 +++++
b/arch/x86/mm/pkeys.c | 101 +++++++++++++++++++++++++++++++++++++++++
b/include/linux/pkeys.h | 3 +
b/mm/mmap.c | 10 +++-
b/mm/mprotect.c | 8 +--
8 files changed, 157 insertions(+), 7 deletions(-)
diff -puN arch/x86/include/asm/pkeys.h~pkeys-79-xonly arch/x86/include/asm/pkeys.h
--- a/arch/x86/include/asm/pkeys.h~pkeys-79-xonly 2016-01-06 15:50:16.796660318 -0800
+++ b/arch/x86/include/asm/pkeys.h 2016-01-06 15:50:16.809660904 -0800
@@ -6,4 +6,29 @@
extern int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
unsigned long init_val);
+/*
+ * Try to dedicate one of the protection keys to be used as an
+ * execute-only protection key.
+ */
+#define PKEY_DEDICATED_EXECUTE_ONLY 15
+extern int __execute_only_pkey(struct mm_struct *mm);
+static inline int execute_only_pkey(struct mm_struct *mm)
+{
+ if (!boot_cpu_has(X86_FEATURE_OSPKE))
+ return 0;
+
+ return __execute_only_pkey(mm);
+}
+
+extern int __arch_override_mprotect_pkey(struct vm_area_struct *vma,
+ int prot, int pkey);
+static inline int arch_override_mprotect_pkey(struct vm_area_struct *vma,
+ int prot, int pkey)
+{
+ if (!boot_cpu_has(X86_FEATURE_OSPKE))
+ return 0;
+
+ return __arch_override_mprotect_pkey(vma, prot, pkey);
+}
+
#endif /*_ASM_X86_PKEYS_H */
diff -puN arch/x86/kernel/fpu/xstate.c~pkeys-79-xonly arch/x86/kernel/fpu/xstate.c
--- a/arch/x86/kernel/fpu/xstate.c~pkeys-79-xonly 2016-01-06 15:50:16.797660363 -0800
+++ b/arch/x86/kernel/fpu/xstate.c 2016-01-06 15:50:16.809660904 -0800
@@ -878,8 +878,6 @@ int arch_set_user_pkey_access(struct tas
int pkey_shift = (pkey * PKRU_BITS_PER_PKEY);
u32 new_pkru_bits = 0;
- if (!validate_pkey(pkey))
- return -EINVAL;
/*
* This check implies XSAVE support. OSPKE only gets
* set if we enable XSAVE and we enable PKU in XCR0.
diff -puN arch/x86/mm/fault.c~pkeys-79-xonly arch/x86/mm/fault.c
--- a/arch/x86/mm/fault.c~pkeys-79-xonly 2016-01-06 15:50:16.799660453 -0800
+++ b/arch/x86/mm/fault.c 2016-01-06 15:50:16.810660949 -0800
@@ -14,6 +14,8 @@
#include <linux/prefetch.h> /* prefetchw */
#include <linux/context_tracking.h> /* exception_enter(), ... */
#include <linux/uaccess.h> /* faulthandler_disabled() */
+#include <linux/pkeys.h> /* PKEY_* */
+#include <uapi/asm-generic/mman-common.h>
#include <asm/cpufeature.h> /* boot_cpu_has, ... */
#include <asm/traps.h> /* dotraplinkage, ... */
@@ -23,6 +25,7 @@
#include <asm/vsyscall.h> /* emulate_vsyscall */
#include <asm/vm86.h> /* struct vm86 */
#include <asm/mmu_context.h> /* vma_pkey() */
+#include <asm/fpu/internal.h> /* fpregs_active() */
#define CREATE_TRACE_POINTS
#include <asm/trace/exceptions.h>
@@ -1108,6 +1111,16 @@ access_error(unsigned long error_code, s
*/
if (error_code & PF_PK)
return 1;
+
+ if (!(error_code & PF_INSTR)) {
+ /*
+ * Assume all accesses require either read or execute
+ * permissions. This is not an instruction access, so
+ * it requires read permissions.
+ */
+ if (!(vma->vm_flags & VM_READ))
+ return 1;
+ }
/*
* Make sure to check the VMA so that we do not perform
* faults just to hit a PF_PK as soon as we fill in a
diff -puN arch/x86/mm/Makefile~pkeys-79-xonly arch/x86/mm/Makefile
--- a/arch/x86/mm/Makefile~pkeys-79-xonly 2016-01-06 15:50:16.800660498 -0800
+++ b/arch/x86/mm/Makefile 2016-01-06 15:50:16.810660949 -0800
@@ -33,3 +33,5 @@ obj-$(CONFIG_ACPI_NUMA) += srat.o
obj-$(CONFIG_NUMA_EMU) += numa_emulation.o
obj-$(CONFIG_X86_INTEL_MPX) += mpx.o
+obj-$(CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS) += pkeys.o
+
diff -puN /dev/null arch/x86/mm/pkeys.c
--- /dev/null 2015-12-10 15:28:13.322405854 -0800
+++ b/arch/x86/mm/pkeys.c 2016-01-06 15:50:16.810660949 -0800
@@ -0,0 +1,101 @@
+/*
+ * Intel Memory Protection Keys management
+ * Copyright (c) 2015, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+#include <linux/mm_types.h> /* mm_struct, vma, etc... */
+#include <linux/pkeys.h> /* PKEY_* */
+#include <uapi/asm-generic/mman-common.h>
+
+#include <asm/cpufeature.h> /* boot_cpu_has, ... */
+#include <asm/mmu_context.h> /* vma_pkey() */
+#include <asm/fpu/internal.h> /* fpregs_active() */
+
+int __execute_only_pkey(struct mm_struct *mm)
+{
+ int ret;
+
+ /*
+ * We do not want to go through the relatively costly
+ * dance to set PKRU if we do not need to. Check it
+ * first and assume that if the execute-only pkey is
+ * write-disabled that we do not have to set it
+ * ourselves. We need preempt off so that nobody
+ * can make fpregs inactive.
+ */
+ preempt_disable();
+ if (fpregs_active() &&
+ !__pkru_allows_read(read_pkru(), PKEY_DEDICATED_EXECUTE_ONLY)) {
+ preempt_enable();
+ return PKEY_DEDICATED_EXECUTE_ONLY;
+ }
+ preempt_enable();
+ ret = arch_set_user_pkey_access(current, PKEY_DEDICATED_EXECUTE_ONLY,
+ PKEY_DISABLE_ACCESS);
+ /*
+ * If the PKRU-set operation failed somehow, just return
+ * 0 and effectively disable execute-only support.
+ */
+ if (ret)
+ return 0;
+
+ return PKEY_DEDICATED_EXECUTE_ONLY;
+}
+
+static inline bool vma_is_pkey_exec_only(struct vm_area_struct *vma)
+{
+ /* Do this check first since the vm_flags should be hot */
+ if ((vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC)) != VM_EXEC)
+ return false;
+ if (vma_pkey(vma) != PKEY_DEDICATED_EXECUTE_ONLY)
+ return false;
+
+ return true;
+}
+
+/*
+ * This is only called for *plain* mprotect calls.
+ */
+int __arch_override_mprotect_pkey(struct vm_area_struct *vma, int prot, int pkey)
+{
+ /*
+ * Is this an mprotect_pkey() call? If so, never
+ * override the value that came from the user.
+ */
+ if (pkey != -1)
+ return pkey;
+ /*
+ * Look for a protection-key-drive execute-only mapping
+ * which is now being given permissions that are not
+ * execute-only. Move it back to the default pkey.
+ */
+ if (vma_is_pkey_exec_only(vma) &&
+ (prot & (PROT_READ|PROT_WRITE))) {
+ return 0;
+ }
+ /*
+ * The mapping is execute-only. Go try to get the
+ * execute-only protection key. If we fail to do that,
+ * fall through as if we do not have execute-only
+ * support.
+ */
+ if (prot == PROT_EXEC) {
+ pkey = execute_only_pkey(vma->vm_mm);
+ if (pkey > 0)
+ return pkey;
+ }
+ /*
+ * This is a vanilla, non-pkey mprotect (or we failed to
+ * setup execute-only), inherit the pkey from the VMA we
+ * are working on.
+ */
+ return vma_pkey(vma);
+}
diff -puN include/linux/pkeys.h~pkeys-79-xonly include/linux/pkeys.h
--- a/include/linux/pkeys.h~pkeys-79-xonly 2016-01-06 15:50:16.802660588 -0800
+++ b/include/linux/pkeys.h 2016-01-06 15:50:16.810660949 -0800
@@ -13,6 +13,9 @@
#include <asm/pkeys.h>
#else /* ! CONFIG_ARCH_HAS_PKEYS */
#define arch_max_pkey() (1)
+#define execute_only_pkey(mm) (0)
+#define arch_override_mprotect_pkey(vma, prot, pkey) (0)
+#define PKEY_DEDICATED_EXECUTE_ONLY 0
#endif /* ! CONFIG_ARCH_HAS_PKEYS */
/*
diff -puN mm/mmap.c~pkeys-79-xonly mm/mmap.c
--- a/mm/mmap.c~pkeys-79-xonly 2016-01-06 15:50:16.804660678 -0800
+++ b/mm/mmap.c 2016-01-06 15:50:16.812661039 -0800
@@ -42,6 +42,7 @@
#include <linux/memory.h>
#include <linux/printk.h>
#include <linux/userfaultfd_k.h>
+#include <linux/pkeys.h>
#include <asm/uaccess.h>
#include <asm/cacheflush.h>
@@ -1266,6 +1267,7 @@ unsigned long do_mmap(struct file *file,
unsigned long pgoff, unsigned long *populate)
{
struct mm_struct *mm = current->mm;
+ int pkey = 0;
*populate = 0;
@@ -1305,11 +1307,17 @@ unsigned long do_mmap(struct file *file,
if (offset_in_page(addr))
return addr;
+ if (prot == PROT_EXEC) {
+ pkey = execute_only_pkey(mm);
+ if (pkey < 0)
+ pkey = 0;
+ }
+
/* Do simple checking here so the lower-level routines won't have
* to. we assume access permissions have been handled by the open
* of the memory object, so we don't do any here.
*/
- vm_flags |= calc_vm_prot_bits(prot, 0) | calc_vm_flag_bits(flags) |
+ vm_flags |= calc_vm_prot_bits(prot, pkey) | calc_vm_flag_bits(flags) |
mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
if (flags & MAP_LOCKED)
diff -puN mm/mprotect.c~pkeys-79-xonly mm/mprotect.c
--- a/mm/mprotect.c~pkeys-79-xonly 2016-01-06 15:50:16.805660723 -0800
+++ b/mm/mprotect.c 2016-01-06 15:50:16.812661039 -0800
@@ -24,6 +24,7 @@
#include <linux/migrate.h>
#include <linux/perf_event.h>
#include <linux/ksm.h>
+#include <linux/pkeys.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/cacheflush.h>
@@ -347,7 +348,7 @@ fail:
SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,
unsigned long, prot)
{
- unsigned long vm_flags, nstart, end, tmp, reqprot;
+ unsigned long nstart, end, tmp, reqprot;
struct vm_area_struct *vma, *prev;
int error = -EINVAL;
const int grows = prot & (PROT_GROWSDOWN|PROT_GROWSUP);
@@ -373,8 +374,6 @@ SYSCALL_DEFINE3(mprotect, unsigned long,
if ((prot & PROT_READ) && (current->personality & READ_IMPLIES_EXEC))
prot |= PROT_EXEC;
- vm_flags = calc_vm_prot_bits(prot, 0);
-
down_write(¤t->mm->mmap_sem);
vma = find_vma(current->mm, start);
@@ -404,10 +403,11 @@ SYSCALL_DEFINE3(mprotect, unsigned long,
for (nstart = start ; ; ) {
unsigned long newflags;
+ int pkey = arch_override_mprotect_pkey(vma, prot, -1);
/* Here we know that vma->vm_start <= nstart < vma->vm_end. */
- newflags = vm_flags;
+ newflags = calc_vm_prot_bits(prot, pkey);
newflags |= (vma->vm_flags & ~(VM_READ | VM_WRITE | VM_EXEC));
/* newflags >> 4 shift VM_MAY% in place of VM_% */
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Kees Cook <keescook@google.com> |
|---|---|
| Date | 2016-01-07 22:10 +0100 |
| Subject | Re: [PATCH 31/31] x86, pkeys: execute-only support |
| Message-ID | <qOpYK-5eu-5@gated-at.bofh.it> |
| In reply to | #1303184 |
On Wed, Jan 6, 2016 at 4:01 PM, Dave Hansen <dave@sr71.net> wrote:
>
> From: Dave Hansen <dave.hansen@linux.intel.com>
>
> Protection keys provide new page-based protection in hardware.
> But, they have an interesting attribute: they only affect data
> accesses and never affect instruction fetches. That means that
> if we set up some memory which is set as "access-disabled" via
> protection keys, we can still execute from it.
>
> This patch uses protection keys to set up mappings to do just that.
> If a user calls:
>
> mmap(..., PROT_EXEC);
> or
> mprotect(ptr, sz, PROT_EXEC);
>
> (note PROT_EXEC-only without PROT_READ/WRITE), the kernel will
> notice this, and set a special protection key on the memory. It
> also sets the appropriate bits in the Protection Keys User Rights
> (PKRU) register so that the memory becomes unreadable and
> unwritable.
>
> I haven't found any userspace that does this today. With this
> facility in place, we expect userspace to move to use it
> eventually.
And the magic benefit here is that linker/loaders can switch to just
PROT_EXEC without PROT_READ, and everything that doesn't support this
protection will silently include PROT_READ, so no runtime detection by
the loader is needed.
> The security provided by this approach is not comprehensive. The
Perhaps specifically mention what it does provide, which would be
protection against leaking executable memory contents, as generally
done by attackers who are attempting to find ROP gadgets on the fly.
-Kees
> PKRU register which controls access permissions is a normal
> user register writable from unprivileged userspace. An attacker
> who can execute the 'wrpkru' instruction can easily disable the
> protection provided by this feature.
>
> The protection key that is used for execute-only support is
> permanently dedicated at compile time. This is fine for now
> because there is currently no API to set a protection key other
> than this one.
>
> Despite there being a constant PKRU value across the entire
> system, we do not set it unless this feature is in use in a
> process. That is to preserve the PKRU XSAVE 'init state',
> which can lead to faster context switches.
>
> PKRU *is* a user register and the kernel is modifying it. That
> means that code doing:
>
> pkru = rdpkru()
> pkru |= 0x100;
> mmap(..., PROT_EXEC);
> wrpkru(pkru);
>
> could lose the bits in PKRU that enforce execute-only
> permissions. To avoid this, we suggest avoiding ever calling
> mmap() or mprotect() when the PKRU value is expected to be
> stable.
>
> Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
> Cc: LKML <linux-kernel@vger.kernel.org>
> Cc: x86@kernel.org
> Cc: torvalds@linux-foundation.org
> Cc: akpm@linux-foundation.org
> Cc: linux-mm@kvack.org
> Cc: keescook@google.com
> Cc: luto@amacapital.net
> ---
>
> b/arch/x86/include/asm/pkeys.h | 25 ++++++++++
> b/arch/x86/kernel/fpu/xstate.c | 2
> b/arch/x86/mm/Makefile | 2
> b/arch/x86/mm/fault.c | 13 +++++
> b/arch/x86/mm/pkeys.c | 101 +++++++++++++++++++++++++++++++++++++++++
> b/include/linux/pkeys.h | 3 +
> b/mm/mmap.c | 10 +++-
> b/mm/mprotect.c | 8 +--
> 8 files changed, 157 insertions(+), 7 deletions(-)
>
> diff -puN arch/x86/include/asm/pkeys.h~pkeys-79-xonly arch/x86/include/asm/pkeys.h
> --- a/arch/x86/include/asm/pkeys.h~pkeys-79-xonly 2016-01-06 15:50:16.796660318 -0800
> +++ b/arch/x86/include/asm/pkeys.h 2016-01-06 15:50:16.809660904 -0800
> @@ -6,4 +6,29 @@
> extern int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
> unsigned long init_val);
>
> +/*
> + * Try to dedicate one of the protection keys to be used as an
> + * execute-only protection key.
> + */
> +#define PKEY_DEDICATED_EXECUTE_ONLY 15
> +extern int __execute_only_pkey(struct mm_struct *mm);
> +static inline int execute_only_pkey(struct mm_struct *mm)
> +{
> + if (!boot_cpu_has(X86_FEATURE_OSPKE))
> + return 0;
> +
> + return __execute_only_pkey(mm);
> +}
> +
> +extern int __arch_override_mprotect_pkey(struct vm_area_struct *vma,
> + int prot, int pkey);
> +static inline int arch_override_mprotect_pkey(struct vm_area_struct *vma,
> + int prot, int pkey)
> +{
> + if (!boot_cpu_has(X86_FEATURE_OSPKE))
> + return 0;
> +
> + return __arch_override_mprotect_pkey(vma, prot, pkey);
> +}
> +
> #endif /*_ASM_X86_PKEYS_H */
> diff -puN arch/x86/kernel/fpu/xstate.c~pkeys-79-xonly arch/x86/kernel/fpu/xstate.c
> --- a/arch/x86/kernel/fpu/xstate.c~pkeys-79-xonly 2016-01-06 15:50:16.797660363 -0800
> +++ b/arch/x86/kernel/fpu/xstate.c 2016-01-06 15:50:16.809660904 -0800
> @@ -878,8 +878,6 @@ int arch_set_user_pkey_access(struct tas
> int pkey_shift = (pkey * PKRU_BITS_PER_PKEY);
> u32 new_pkru_bits = 0;
>
> - if (!validate_pkey(pkey))
> - return -EINVAL;
> /*
> * This check implies XSAVE support. OSPKE only gets
> * set if we enable XSAVE and we enable PKU in XCR0.
> diff -puN arch/x86/mm/fault.c~pkeys-79-xonly arch/x86/mm/fault.c
> --- a/arch/x86/mm/fault.c~pkeys-79-xonly 2016-01-06 15:50:16.799660453 -0800
> +++ b/arch/x86/mm/fault.c 2016-01-06 15:50:16.810660949 -0800
> @@ -14,6 +14,8 @@
> #include <linux/prefetch.h> /* prefetchw */
> #include <linux/context_tracking.h> /* exception_enter(), ... */
> #include <linux/uaccess.h> /* faulthandler_disabled() */
> +#include <linux/pkeys.h> /* PKEY_* */
> +#include <uapi/asm-generic/mman-common.h>
>
> #include <asm/cpufeature.h> /* boot_cpu_has, ... */
> #include <asm/traps.h> /* dotraplinkage, ... */
> @@ -23,6 +25,7 @@
> #include <asm/vsyscall.h> /* emulate_vsyscall */
> #include <asm/vm86.h> /* struct vm86 */
> #include <asm/mmu_context.h> /* vma_pkey() */
> +#include <asm/fpu/internal.h> /* fpregs_active() */
>
> #define CREATE_TRACE_POINTS
> #include <asm/trace/exceptions.h>
> @@ -1108,6 +1111,16 @@ access_error(unsigned long error_code, s
> */
> if (error_code & PF_PK)
> return 1;
> +
> + if (!(error_code & PF_INSTR)) {
> + /*
> + * Assume all accesses require either read or execute
> + * permissions. This is not an instruction access, so
> + * it requires read permissions.
> + */
> + if (!(vma->vm_flags & VM_READ))
> + return 1;
> + }
> /*
> * Make sure to check the VMA so that we do not perform
> * faults just to hit a PF_PK as soon as we fill in a
> diff -puN arch/x86/mm/Makefile~pkeys-79-xonly arch/x86/mm/Makefile
> --- a/arch/x86/mm/Makefile~pkeys-79-xonly 2016-01-06 15:50:16.800660498 -0800
> +++ b/arch/x86/mm/Makefile 2016-01-06 15:50:16.810660949 -0800
> @@ -33,3 +33,5 @@ obj-$(CONFIG_ACPI_NUMA) += srat.o
> obj-$(CONFIG_NUMA_EMU) += numa_emulation.o
>
> obj-$(CONFIG_X86_INTEL_MPX) += mpx.o
> +obj-$(CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS) += pkeys.o
> +
> diff -puN /dev/null arch/x86/mm/pkeys.c
> --- /dev/null 2015-12-10 15:28:13.322405854 -0800
> +++ b/arch/x86/mm/pkeys.c 2016-01-06 15:50:16.810660949 -0800
> @@ -0,0 +1,101 @@
> +/*
> + * Intel Memory Protection Keys management
> + * Copyright (c) 2015, Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + * more details.
> + */
> +#include <linux/mm_types.h> /* mm_struct, vma, etc... */
> +#include <linux/pkeys.h> /* PKEY_* */
> +#include <uapi/asm-generic/mman-common.h>
> +
> +#include <asm/cpufeature.h> /* boot_cpu_has, ... */
> +#include <asm/mmu_context.h> /* vma_pkey() */
> +#include <asm/fpu/internal.h> /* fpregs_active() */
> +
> +int __execute_only_pkey(struct mm_struct *mm)
> +{
> + int ret;
> +
> + /*
> + * We do not want to go through the relatively costly
> + * dance to set PKRU if we do not need to. Check it
> + * first and assume that if the execute-only pkey is
> + * write-disabled that we do not have to set it
> + * ourselves. We need preempt off so that nobody
> + * can make fpregs inactive.
> + */
> + preempt_disable();
> + if (fpregs_active() &&
> + !__pkru_allows_read(read_pkru(), PKEY_DEDICATED_EXECUTE_ONLY)) {
> + preempt_enable();
> + return PKEY_DEDICATED_EXECUTE_ONLY;
> + }
> + preempt_enable();
> + ret = arch_set_user_pkey_access(current, PKEY_DEDICATED_EXECUTE_ONLY,
> + PKEY_DISABLE_ACCESS);
> + /*
> + * If the PKRU-set operation failed somehow, just return
> + * 0 and effectively disable execute-only support.
> + */
> + if (ret)
> + return 0;
> +
> + return PKEY_DEDICATED_EXECUTE_ONLY;
> +}
> +
> +static inline bool vma_is_pkey_exec_only(struct vm_area_struct *vma)
> +{
> + /* Do this check first since the vm_flags should be hot */
> + if ((vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC)) != VM_EXEC)
> + return false;
> + if (vma_pkey(vma) != PKEY_DEDICATED_EXECUTE_ONLY)
> + return false;
> +
> + return true;
> +}
> +
> +/*
> + * This is only called for *plain* mprotect calls.
> + */
> +int __arch_override_mprotect_pkey(struct vm_area_struct *vma, int prot, int pkey)
> +{
> + /*
> + * Is this an mprotect_pkey() call? If so, never
> + * override the value that came from the user.
> + */
> + if (pkey != -1)
> + return pkey;
> + /*
> + * Look for a protection-key-drive execute-only mapping
> + * which is now being given permissions that are not
> + * execute-only. Move it back to the default pkey.
> + */
> + if (vma_is_pkey_exec_only(vma) &&
> + (prot & (PROT_READ|PROT_WRITE))) {
> + return 0;
> + }
> + /*
> + * The mapping is execute-only. Go try to get the
> + * execute-only protection key. If we fail to do that,
> + * fall through as if we do not have execute-only
> + * support.
> + */
> + if (prot == PROT_EXEC) {
> + pkey = execute_only_pkey(vma->vm_mm);
> + if (pkey > 0)
> + return pkey;
> + }
> + /*
> + * This is a vanilla, non-pkey mprotect (or we failed to
> + * setup execute-only), inherit the pkey from the VMA we
> + * are working on.
> + */
> + return vma_pkey(vma);
> +}
> diff -puN include/linux/pkeys.h~pkeys-79-xonly include/linux/pkeys.h
> --- a/include/linux/pkeys.h~pkeys-79-xonly 2016-01-06 15:50:16.802660588 -0800
> +++ b/include/linux/pkeys.h 2016-01-06 15:50:16.810660949 -0800
> @@ -13,6 +13,9 @@
> #include <asm/pkeys.h>
> #else /* ! CONFIG_ARCH_HAS_PKEYS */
> #define arch_max_pkey() (1)
> +#define execute_only_pkey(mm) (0)
> +#define arch_override_mprotect_pkey(vma, prot, pkey) (0)
> +#define PKEY_DEDICATED_EXECUTE_ONLY 0
> #endif /* ! CONFIG_ARCH_HAS_PKEYS */
>
> /*
> diff -puN mm/mmap.c~pkeys-79-xonly mm/mmap.c
> --- a/mm/mmap.c~pkeys-79-xonly 2016-01-06 15:50:16.804660678 -0800
> +++ b/mm/mmap.c 2016-01-06 15:50:16.812661039 -0800
> @@ -42,6 +42,7 @@
> #include <linux/memory.h>
> #include <linux/printk.h>
> #include <linux/userfaultfd_k.h>
> +#include <linux/pkeys.h>
>
> #include <asm/uaccess.h>
> #include <asm/cacheflush.h>
> @@ -1266,6 +1267,7 @@ unsigned long do_mmap(struct file *file,
> unsigned long pgoff, unsigned long *populate)
> {
> struct mm_struct *mm = current->mm;
> + int pkey = 0;
>
> *populate = 0;
>
> @@ -1305,11 +1307,17 @@ unsigned long do_mmap(struct file *file,
> if (offset_in_page(addr))
> return addr;
>
> + if (prot == PROT_EXEC) {
> + pkey = execute_only_pkey(mm);
> + if (pkey < 0)
> + pkey = 0;
> + }
> +
> /* Do simple checking here so the lower-level routines won't have
> * to. we assume access permissions have been handled by the open
> * of the memory object, so we don't do any here.
> */
> - vm_flags |= calc_vm_prot_bits(prot, 0) | calc_vm_flag_bits(flags) |
> + vm_flags |= calc_vm_prot_bits(prot, pkey) | calc_vm_flag_bits(flags) |
> mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
>
> if (flags & MAP_LOCKED)
> diff -puN mm/mprotect.c~pkeys-79-xonly mm/mprotect.c
> --- a/mm/mprotect.c~pkeys-79-xonly 2016-01-06 15:50:16.805660723 -0800
> +++ b/mm/mprotect.c 2016-01-06 15:50:16.812661039 -0800
> @@ -24,6 +24,7 @@
> #include <linux/migrate.h>
> #include <linux/perf_event.h>
> #include <linux/ksm.h>
> +#include <linux/pkeys.h>
> #include <asm/uaccess.h>
> #include <asm/pgtable.h>
> #include <asm/cacheflush.h>
> @@ -347,7 +348,7 @@ fail:
> SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,
> unsigned long, prot)
> {
> - unsigned long vm_flags, nstart, end, tmp, reqprot;
> + unsigned long nstart, end, tmp, reqprot;
> struct vm_area_struct *vma, *prev;
> int error = -EINVAL;
> const int grows = prot & (PROT_GROWSDOWN|PROT_GROWSUP);
> @@ -373,8 +374,6 @@ SYSCALL_DEFINE3(mprotect, unsigned long,
> if ((prot & PROT_READ) && (current->personality & READ_IMPLIES_EXEC))
> prot |= PROT_EXEC;
>
> - vm_flags = calc_vm_prot_bits(prot, 0);
> -
> down_write(¤t->mm->mmap_sem);
>
> vma = find_vma(current->mm, start);
> @@ -404,10 +403,11 @@ SYSCALL_DEFINE3(mprotect, unsigned long,
>
> for (nstart = start ; ; ) {
> unsigned long newflags;
> + int pkey = arch_override_mprotect_pkey(vma, prot, -1);
>
> /* Here we know that vma->vm_start <= nstart < vma->vm_end. */
>
> - newflags = vm_flags;
> + newflags = calc_vm_prot_bits(prot, pkey);
> newflags |= (vma->vm_flags & ~(VM_READ | VM_WRITE | VM_EXEC));
>
> /* newflags >> 4 shift VM_MAY% in place of VM_% */
> _
--
Kees Cook
Chrome OS & Brillo Security
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2016-01-07 23:30 +0100 |
| Subject | Re: [PATCH 31/31] x86, pkeys: execute-only support |
| Message-ID | <qOrea-5ZC-15@gated-at.bofh.it> |
| In reply to | #1303905 |
On 01/07/2016 01:02 PM, Kees Cook wrote: >> > I haven't found any userspace that does this today. With this >> > facility in place, we expect userspace to move to use it >> > eventually. > And the magic benefit here is that linker/loaders can switch to just > PROT_EXEC without PROT_READ, and everything that doesn't support this > protection will silently include PROT_READ, so no runtime detection by > the loader is needed. Yep, completely agree. I'll update the description. >> > The security provided by this approach is not comprehensive. The > Perhaps specifically mention what it does provide, which would be > protection against leaking executable memory contents, as generally > done by attackers who are attempting to find ROP gadgets on the fly. Good point.
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@amacapital.net> |
|---|---|
| Date | 2016-01-07 22:20 +0100 |
| Subject | Re: [PATCH 31/31] x86, pkeys: execute-only support |
| Message-ID | <qOq8p-5ia-11@gated-at.bofh.it> |
| In reply to | #1303184 |
On Wed, Jan 6, 2016 at 4:01 PM, Dave Hansen <dave@sr71.net> wrote: > > From: Dave Hansen <dave.hansen@linux.intel.com> > > Protection keys provide new page-based protection in hardware. > But, they have an interesting attribute: they only affect data > accesses and never affect instruction fetches. That means that > if we set up some memory which is set as "access-disabled" via > protection keys, we can still execute from it. > could lose the bits in PKRU that enforce execute-only > permissions. To avoid this, we suggest avoiding ever calling > mmap() or mprotect() when the PKRU value is expected to be > stable. s/stable/unstable/ This may be a bit unfortunate for people who call mmap from signal handlers. Admittedly, the failure mode isn't that bad. Out of curiosity, do you have timing information for WRPKRU and RDPKRU? If they're fast and if anyone ever implements my deferred xstate restore idea, then the performance issue goes away and we can stop caring about whether PKRU is in the init state. --Andy
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2016-01-07 23:20 +0100 |
| Subject | Re: [PATCH 31/31] x86, pkeys: execute-only support |
| Message-ID | <qOr4t-5VS-1@gated-at.bofh.it> |
| In reply to | #1303916 |
On 01/07/2016 01:10 PM, Andy Lutomirski wrote: > On Wed, Jan 6, 2016 at 4:01 PM, Dave Hansen <dave@sr71.net> wrote: >> From: Dave Hansen <dave.hansen@linux.intel.com> >> Protection keys provide new page-based protection in hardware. >> But, they have an interesting attribute: they only affect data >> accesses and never affect instruction fetches. That means that >> if we set up some memory which is set as "access-disabled" via >> protection keys, we can still execute from it. >> could lose the bits in PKRU that enforce execute-only >> permissions. To avoid this, we suggest avoiding ever calling >> mmap() or mprotect() when the PKRU value is expected to be >> stable. > > This may be a bit unfortunate for people who call mmap from signal > handlers. Admittedly, the failure mode isn't that bad. mmap() isn't in the list of async-signal-safe functions, so it's bad already. > Out of curiosity, do you have timing information for WRPKRU and > RDPKRU? If they're fast and if anyone ever implements my deferred > xstate restore idea, then the performance issue goes away and we can > stop caring about whether PKRU is in the init state. I don't have timing information that I can share. From my perspective, they're pretty fast, *not* like an MSR write or something. I think they're fast enough to use in the context switch path. I'd say PKRU is in XSAVE for consistency more than for performance.
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@amacapital.net> |
|---|---|
| Date | 2016-01-07 23:50 +0100 |
| Subject | Re: [PATCH 31/31] x86, pkeys: execute-only support |
| Message-ID | <qOrxw-67X-19@gated-at.bofh.it> |
| In reply to | #1303945 |
On Thu, Jan 7, 2016 at 2:13 PM, Dave Hansen <dave@sr71.net> wrote: > On 01/07/2016 01:10 PM, Andy Lutomirski wrote: >> On Wed, Jan 6, 2016 at 4:01 PM, Dave Hansen <dave@sr71.net> wrote: >>> From: Dave Hansen <dave.hansen@linux.intel.com> >>> Protection keys provide new page-based protection in hardware. >>> But, they have an interesting attribute: they only affect data >>> accesses and never affect instruction fetches. That means that >>> if we set up some memory which is set as "access-disabled" via >>> protection keys, we can still execute from it. >>> could lose the bits in PKRU that enforce execute-only >>> permissions. To avoid this, we suggest avoiding ever calling >>> mmap() or mprotect() when the PKRU value is expected to be >>> stable. >> >> This may be a bit unfortunate for people who call mmap from signal >> handlers. Admittedly, the failure mode isn't that bad. > > mmap() isn't in the list of async-signal-safe functions, so it's bad > already. mmap the POSIX function may not be, but mmap the syscall is just a syscall. Also, I'm moderately confident that there are synchronous signals, too. If not, there should be (e.g. raise with an unblocked signal). > >> Out of curiosity, do you have timing information for WRPKRU and >> RDPKRU? If they're fast and if anyone ever implements my deferred >> xstate restore idea, then the performance issue goes away and we can >> stop caring about whether PKRU is in the init state. > > I don't have timing information that I can share. From my perspective, > they're pretty fast, *not* like an MSR write or something. I think > they're fast enough to use in the context switch path. I'd say PKRU is > in XSAVE for consistency more than for performance. > I'll play with this at some point. Probably not until I get the right hardware. --Andy
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2016-01-08 21:00 +0100 |
| Subject | Re: [PATCH 31/31] x86, pkeys: execute-only support |
| Message-ID | <qOLmz-32e-47@gated-at.bofh.it> |
| In reply to | #1303184 |
On Wed, 6 Jan 2016, Dave Hansen wrote:
>
> Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
> diff -puN arch/x86/mm/fault.c~pkeys-79-xonly arch/x86/mm/fault.c
> --- a/arch/x86/mm/fault.c~pkeys-79-xonly 2016-01-06 15:50:16.799660453 -0800
> +++ b/arch/x86/mm/fault.c 2016-01-06 15:50:16.810660949 -0800
> @@ -14,6 +14,8 @@
> #include <linux/prefetch.h> /* prefetchw */
> #include <linux/context_tracking.h> /* exception_enter(), ... */
> #include <linux/uaccess.h> /* faulthandler_disabled() */
> +#include <linux/pkeys.h> /* PKEY_* */
> +#include <uapi/asm-generic/mman-common.h>
>
> #include <asm/cpufeature.h> /* boot_cpu_has, ... */
> #include <asm/traps.h> /* dotraplinkage, ... */
> @@ -23,6 +25,7 @@
> #include <asm/vsyscall.h> /* emulate_vsyscall */
> #include <asm/vm86.h> /* struct vm86 */
> #include <asm/mmu_context.h> /* vma_pkey() */
> +#include <asm/fpu/internal.h> /* fpregs_active() */
These include changes are presumably leftovers from an earlier version. At
least I can't see a reason why we would need them for the change below.
> #define CREATE_TRACE_POINTS
> #include <asm/trace/exceptions.h>
> @@ -1108,6 +1111,16 @@ access_error(unsigned long error_code, s
> */
> if (error_code & PF_PK)
> return 1;
> +
> + if (!(error_code & PF_INSTR)) {
> + /*
> + * Assume all accesses require either read or execute
> + * permissions. This is not an instruction access, so
> + * it requires read permissions.
> + */
> + if (!(vma->vm_flags & VM_READ))
> + return 1;
> + }
Except for the above nit: Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2016-01-07 01:10 +0100 |
| Subject | [PATCH 24/31] x86, pkeys: actually enable Memory Protection Keys in CPU |
| Message-ID | <qO6jq-8sH-51@gated-at.bofh.it> |
| In reply to | #1303164 |
From: Dave Hansen <dave.hansen@linux.intel.com>
This sets the bit in 'cr4' to actually enable the protection
keys feature. We also include a boot-time disable for the
feature "nopku".
Seting X86_CR4_PKE will cause the X86_FEATURE_OSPKE cpuid
bit to appear set. At this point in boot, identify_cpu()
has already run the actual CPUID instructions and populated
the "cpu features" structures. We need to go back and
re-run identify_cpu() to make sure it gets updated values.
We *could* simply re-populate the 11th word of the cpuid
data, but this is probably quick enough.
Also note that with the cpu_has() check and X86_FEATURE_PKU
present in disabled-features.h, we do not need an #ifdef
for setup_pku().
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
---
b/Documentation/kernel-parameters.txt | 3 ++
b/arch/x86/kernel/cpu/common.c | 41 ++++++++++++++++++++++++++++++++++
2 files changed, 44 insertions(+)
diff -puN arch/x86/kernel/cpu/common.c~pkeys-50-should-be-last-patch arch/x86/kernel/cpu/common.c
--- a/arch/x86/kernel/cpu/common.c~pkeys-50-should-be-last-patch 2016-01-06 15:50:13.522512707 -0800
+++ b/arch/x86/kernel/cpu/common.c 2016-01-06 15:50:13.528512977 -0800
@@ -289,6 +289,46 @@ static __always_inline void setup_smap(s
}
/*
+ * Protection Keys are not available in 32-bit mode.
+ */
+static bool pku_disabled;
+static __always_inline void setup_pku(struct cpuinfo_x86 *c)
+{
+ if (!cpu_has(c, X86_FEATURE_PKU))
+ return;
+ if (pku_disabled)
+ return;
+
+ cr4_set_bits(X86_CR4_PKE);
+ /*
+ * Seting X86_CR4_PKE will cause the X86_FEATURE_OSPKE
+ * cpuid bit to be set. We need to ensure that we
+ * update that bit in this CPU's "cpu_info".
+ */
+ get_cpu_cap(c);
+}
+#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
+static __init int setup_disable_pku(char *arg)
+{
+ /*
+ * Do not clear the X86_FEATURE_PKU bit. All of the
+ * runtime checks are against OSPKE so clearing the
+ * bit does nothing.
+ *
+ * This way, we will see "pku" in cpuinfo, but not
+ * "ospke", which is exactly what we want. It shows
+ * that the CPU has PKU, but the OS has not enabled it.
+ * This happens to be exactly how a system would look
+ * if we disabled the config option.
+ */
+ pr_info("x86: 'nopku' specified, disabling Memory Protection Keys\n");
+ pku_disabled = true;
+ return 1;
+}
+__setup("nopku", setup_disable_pku);
+#endif /* CONFIG_X86_64 */
+
+/*
* Some CPU features depend on higher CPUID levels, which may not always
* be available due to CPUID level capping or broken virtualization
* software. Add those features to this table to auto-disable them.
@@ -948,6 +988,7 @@ static void identify_cpu(struct cpuinfo_
init_hypervisor(c);
x86_init_rdrand(c);
x86_init_cache_qos(c);
+ setup_pku(c);
/*
* Clear/Set all flags overriden by options, need do it
diff -puN Documentation/kernel-parameters.txt~pkeys-50-should-be-last-patch Documentation/kernel-parameters.txt
--- a/Documentation/kernel-parameters.txt~pkeys-50-should-be-last-patch 2016-01-06 15:50:13.524512797 -0800
+++ b/Documentation/kernel-parameters.txt 2016-01-06 15:50:13.529513023 -0800
@@ -958,6 +958,9 @@ bytes respectively. Such letter suffixes
See Documentation/x86/intel_mpx.txt for more
information about the feature.
+ nopku [X86] Disable Memory Protection Keys CPU feature found
+ in some Intel CPUs.
+
eagerfpu= [X86]
on enable eager fpu restore
off disable eager fpu restore
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2016-01-07 01:10 +0100 |
| Subject | [PATCH 30/31] x86, pkeys: create an x86 arch_calc_vm_prot_bits() for VMA flags |
| Message-ID | <qO6jq-8sH-53@gated-at.bofh.it> |
| In reply to | #1303164 |
From: Dave Hansen <dave.hansen@linux.intel.com>
calc_vm_prot_bits() takes PROT_{READ,WRITE,EXECUTE} bits and
turns them in to the vma->vm_flags/VM_* bits. We need to do a
similar thing for protection keys.
We take a protection key (4 bits) and encode it in to the 4
VM_PKEY_* bits.
Note: this code is not new. It was simply a part of the
mprotect_pkey() patch in the past. I broke it out for use
in the execute-only support.
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
---
b/arch/x86/include/uapi/asm/mman.h | 6 ++++++
1 file changed, 6 insertions(+)
diff -puN arch/x86/include/uapi/asm/mman.h~pkeys-78-arch_calc_vm_prot_bits arch/x86/include/uapi/asm/mman.h
--- a/arch/x86/include/uapi/asm/mman.h~pkeys-78-arch_calc_vm_prot_bits 2016-01-06 15:50:16.387641877 -0800
+++ b/arch/x86/include/uapi/asm/mman.h 2016-01-06 15:50:16.390642013 -0800
@@ -20,6 +20,12 @@
((vm_flags) & VM_PKEY_BIT1 ? _PAGE_PKEY_BIT1 : 0) | \
((vm_flags) & VM_PKEY_BIT2 ? _PAGE_PKEY_BIT2 : 0) | \
((vm_flags) & VM_PKEY_BIT3 ? _PAGE_PKEY_BIT3 : 0))
+
+#define arch_calc_vm_prot_bits(prot, key) ( \
+ ((key) & 0x1 ? VM_PKEY_BIT0 : 0) | \
+ ((key) & 0x2 ? VM_PKEY_BIT1 : 0) | \
+ ((key) & 0x4 ? VM_PKEY_BIT2 : 0) | \
+ ((key) & 0x8 ? VM_PKEY_BIT3 : 0))
#endif
#include <asm-generic/mman.h>
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2016-01-07 01:10 +0100 |
| Subject | [PATCH 18/31] mm: add gup flag to indicate "foreign" mm access |
| Message-ID | <qO6jq-8sH-59@gated-at.bofh.it> |
| In reply to | #1303164 |
From: Dave Hansen <dave.hansen@linux.intel.com>
We try to enforce protection keys in software the same way that we
do in hardware. (See long example below).
But, we only want to do this when accessing our *own* process's
memory. If GDB set PKRU[6].AD=1 (disable access to PKEY 6), then
tried to PTRACE_POKE a target process which just happened to have
some mprotect_pkey(pkey=6) memory, we do *not* want to deny the
debugger access to that memory. PKRU is fundamentally a
thread-local structure and we do not want to enforce it on access
to _another_ thread's data.
This gets especially tricky when we have workqueues or other
delayed-work mechanisms that might run in a random process's context.
We can check that we only enforce pkeys when operating on our *own* mm,
but delayed work gets performed when a random user context is active.
We might end up with a situation where a delayed-work gup fails when
running randomly under its "own" task but succeeds when running under
another process. We want to avoid that.
To avoid that, we add a GUP flag: FOLL_FOREIGN and a fault flag:
FAULT_FLAG_FOREIGN. They indicate that we are walking an mm
which is not guranteed to be the same as current->mm and should
not be subject to protection key enforcement.
Thanks to Jerome Glisse for pointing out this scenario.
*** Why do we enforce protection keys in software?? ***
Imagine that we disabled access to the memory pointer to by 'buf'.
The, we implemented sys_write() like this:
sys_read(fd, buf, len...)
{
struct page *page = follow_page(buf);
void *buf_mapped = kmap(page);
memcpy(buf_mapped, fd_data, len);
...
}
This writes to 'buf' via a *kernel* mapping, without a protection
key. While this implementation does the same thing:
sys_read(fd, buf, len...)
{
copy_to_user(buf, fd_data, len);
...
}
but would hit a protection key fault because the userspace 'buf'
mapping has a protection key set.
To provide consistency, and to make key-protected memory work
as much like mprotect()ed memory as possible, we try to enforce
the same protections as the hardware would when the *kernel* walks
the page tables (and other mm structures).
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Cc: linux-arch@vger.kernel.org
---
b/arch/powerpc/include/asm/mmu_context.h | 3 ++-
b/arch/s390/include/asm/mmu_context.h | 3 ++-
b/arch/unicore32/include/asm/mmu_context.h | 3 ++-
b/arch/x86/include/asm/mmu_context.h | 5 +++--
b/drivers/iommu/amd_iommu_v2.c | 8 +++++---
b/include/asm-generic/mm_hooks.h | 3 ++-
b/include/linux/mm.h | 2 ++
b/mm/gup.c | 15 ++++++++++-----
b/mm/ksm.c | 10 ++++++++--
b/mm/memory.c | 3 ++-
10 files changed, 38 insertions(+), 17 deletions(-)
diff -puN arch/powerpc/include/asm/mmu_context.h~pkeys-14-gup-fault-foreign-flag arch/powerpc/include/asm/mmu_context.h
--- a/arch/powerpc/include/asm/mmu_context.h~pkeys-14-gup-fault-foreign-flag 2016-01-06 15:50:10.622381958 -0800
+++ b/arch/powerpc/include/asm/mmu_context.h 2016-01-06 15:50:10.640382770 -0800
@@ -148,7 +148,8 @@ static inline void arch_bprm_mm_init(str
{
}
-static inline bool arch_vma_access_permitted(struct vm_area_struct *vma, bool write)
+static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,
+ bool write, bool foreign)
{
/* by default, allow everything */
return true;
diff -puN arch/s390/include/asm/mmu_context.h~pkeys-14-gup-fault-foreign-flag arch/s390/include/asm/mmu_context.h
--- a/arch/s390/include/asm/mmu_context.h~pkeys-14-gup-fault-foreign-flag 2016-01-06 15:50:10.624382049 -0800
+++ b/arch/s390/include/asm/mmu_context.h 2016-01-06 15:50:10.641382815 -0800
@@ -130,7 +130,8 @@ static inline void arch_bprm_mm_init(str
{
}
-static inline bool arch_vma_access_permitted(struct vm_area_struct *vma, bool write)
+static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,
+ bool write, bool foreign)
{
/* by default, allow everything */
return true;
diff -puN arch/unicore32/include/asm/mmu_context.h~pkeys-14-gup-fault-foreign-flag arch/unicore32/include/asm/mmu_context.h
--- a/arch/unicore32/include/asm/mmu_context.h~pkeys-14-gup-fault-foreign-flag 2016-01-06 15:50:10.625382094 -0800
+++ b/arch/unicore32/include/asm/mmu_context.h 2016-01-06 15:50:10.641382815 -0800
@@ -97,7 +97,8 @@ static inline void arch_bprm_mm_init(str
{
}
-static inline bool arch_vma_access_permitted(struct vm_area_struct *vma, bool write)
+static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,
+ bool write, bool foreign)
{
/* by default, allow everything */
return true;
diff -puN arch/x86/include/asm/mmu_context.h~pkeys-14-gup-fault-foreign-flag arch/x86/include/asm/mmu_context.h
--- a/arch/x86/include/asm/mmu_context.h~pkeys-14-gup-fault-foreign-flag 2016-01-06 15:50:10.627382184 -0800
+++ b/arch/x86/include/asm/mmu_context.h 2016-01-06 15:50:10.641382815 -0800
@@ -290,10 +290,11 @@ static inline bool vma_is_foreign(struct
return false;
}
-static inline bool arch_vma_access_permitted(struct vm_area_struct *vma, bool write)
+static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,
+ bool write, bool foreign)
{
/* allow access if the VMA is not one from this process */
- if (vma_is_foreign(vma))
+ if (foreign || vma_is_foreign(vma))
return true;
return __pkru_allows_pkey(vma_pkey(vma), write);
}
diff -puN drivers/iommu/amd_iommu_v2.c~pkeys-14-gup-fault-foreign-flag drivers/iommu/amd_iommu_v2.c
--- a/drivers/iommu/amd_iommu_v2.c~pkeys-14-gup-fault-foreign-flag 2016-01-06 15:50:10.629382274 -0800
+++ b/drivers/iommu/amd_iommu_v2.c 2016-01-06 15:50:10.642382860 -0800
@@ -500,9 +500,11 @@ static void do_fault(struct work_struct
struct mm_struct *mm;
struct vm_area_struct *vma;
u64 address;
- int ret, write;
+ int ret, flags;
- write = !!(fault->flags & PPR_FAULT_WRITE);
+ if (fault->flags & PPR_FAULT_WRITE)
+ flags = FAULT_FLAG_WRITE;
+ flags |= FAULT_FLAG_FOREIGN;
mm = fault->state->mm;
address = fault->address;
@@ -523,7 +525,7 @@ static void do_fault(struct work_struct
goto out;
}
- ret = handle_mm_fault(mm, vma, address, write);
+ ret = handle_mm_fault(mm, vma, address, flags);
if (ret & VM_FAULT_ERROR) {
/* failed to service fault */
up_read(&mm->mmap_sem);
diff -puN include/asm-generic/mm_hooks.h~pkeys-14-gup-fault-foreign-flag include/asm-generic/mm_hooks.h
--- a/include/asm-generic/mm_hooks.h~pkeys-14-gup-fault-foreign-flag 2016-01-06 15:50:10.630382319 -0800
+++ b/include/asm-generic/mm_hooks.h 2016-01-06 15:50:10.642382860 -0800
@@ -26,7 +26,8 @@ static inline void arch_bprm_mm_init(str
{
}
-static inline bool arch_vma_access_permitted(struct vm_area_struct *vma, bool write)
+static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,
+ bool write, bool foreign)
{
/* by default, allow everything */
return true;
diff -puN include/linux/mm.h~pkeys-14-gup-fault-foreign-flag include/linux/mm.h
--- a/include/linux/mm.h~pkeys-14-gup-fault-foreign-flag 2016-01-06 15:50:10.632382409 -0800
+++ b/include/linux/mm.h 2016-01-06 15:50:10.643382905 -0800
@@ -237,6 +237,7 @@ extern pgprot_t protection_map[16];
#define FAULT_FLAG_KILLABLE 0x10 /* The fault task is in SIGKILL killable region */
#define FAULT_FLAG_TRIED 0x20 /* Second try */
#define FAULT_FLAG_USER 0x40 /* The fault originated in userspace */
+#define FAULT_FLAG_FOREIGN 0x80 /* faulting for non current tsk/mm */
/*
* vm_fault is filled by the the pagefault handler and passed to the vma's
@@ -2143,6 +2144,7 @@ static inline struct page *follow_page(s
#define FOLL_MIGRATION 0x400 /* wait for page to replace migration entry */
#define FOLL_TRIED 0x800 /* a retry, previous pass started an IO */
#define FOLL_MLOCK 0x1000 /* lock present pages */
+#define FOLL_FOREIGN 0x2000 /* we are working on non-current tsk/mm */
typedef int (*pte_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr,
void *data);
diff -puN mm/gup.c~pkeys-14-gup-fault-foreign-flag mm/gup.c
--- a/mm/gup.c~pkeys-14-gup-fault-foreign-flag 2016-01-06 15:50:10.634382499 -0800
+++ b/mm/gup.c 2016-01-06 15:50:10.644382950 -0800
@@ -310,6 +310,8 @@ static int faultin_page(struct task_stru
return -ENOENT;
if (*flags & FOLL_WRITE)
fault_flags |= FAULT_FLAG_WRITE;
+ if (*flags & FOLL_FOREIGN)
+ fault_flags |= FAULT_FLAG_FOREIGN;
if (nonblocking)
fault_flags |= FAULT_FLAG_ALLOW_RETRY;
if (*flags & FOLL_NOWAIT)
@@ -360,11 +362,13 @@ static int faultin_page(struct task_stru
static int check_vma_flags(struct vm_area_struct *vma, unsigned long gup_flags)
{
vm_flags_t vm_flags = vma->vm_flags;
+ int write = (gup_flags & FOLL_WRITE);
+ int foreign = (gup_flags & FOLL_FOREIGN);
if (vm_flags & (VM_IO | VM_PFNMAP))
return -EFAULT;
- if (gup_flags & FOLL_WRITE) {
+ if (write) {
if (!(vm_flags & VM_WRITE)) {
if (!(gup_flags & FOLL_FORCE))
return -EFAULT;
@@ -392,7 +396,7 @@ static int check_vma_flags(struct vm_are
if (!(vm_flags & VM_MAYREAD))
return -EFAULT;
}
- if (!arch_vma_access_permitted(vma, (gup_flags & FOLL_WRITE)))
+ if (!arch_vma_access_permitted(vma, write, foreign))
return -EFAULT;
return 0;
}
@@ -562,7 +566,8 @@ EXPORT_SYMBOL(__get_user_pages);
bool vma_permits_fault(struct vm_area_struct *vma, unsigned int fault_flags)
{
- bool write = !!(fault_flags & FAULT_FLAG_WRITE);
+ bool write = !!(fault_flags & FAULT_FLAG_WRITE);
+ bool foreign = !!(fault_flags & FAULT_FLAG_FOREIGN);
vm_flags_t vm_flags = write ? VM_WRITE : VM_READ;
if (!(vm_flags & vma->vm_flags))
@@ -570,9 +575,9 @@ bool vma_permits_fault(struct vm_area_st
/*
* The architecture might have a hardware protection
- * mechanism other than read/write that can deny access
+ * mechanism other than read/write that can deny access.
*/
- if (!arch_vma_access_permitted(vma, write))
+ if (!arch_vma_access_permitted(vma, write, foreign))
return false;
return true;
diff -puN mm/ksm.c~pkeys-14-gup-fault-foreign-flag mm/ksm.c
--- a/mm/ksm.c~pkeys-14-gup-fault-foreign-flag 2016-01-06 15:50:10.635382545 -0800
+++ b/mm/ksm.c 2016-01-06 15:50:10.644382950 -0800
@@ -359,6 +359,10 @@ static inline bool ksm_test_exit(struct
* in case the application has unmapped and remapped mm,addr meanwhile.
* Could a ksm page appear anywhere else? Actually yes, in a VM_PFNMAP
* mmap of /dev/mem or /dev/kmem, where we would not want to touch it.
+ *
+ * FAULT_FLAG/FOLL_FOREIGN are because we do this outside the context
+ * of the process that owns 'vma'. We also do not want to enforce
+ * protection keys here anyway.
*/
static int break_ksm(struct vm_area_struct *vma, unsigned long addr)
{
@@ -367,12 +371,14 @@ static int break_ksm(struct vm_area_stru
do {
cond_resched();
- page = follow_page(vma, addr, FOLL_GET | FOLL_MIGRATION);
+ page = follow_page(vma, addr,
+ FOLL_GET | FOLL_MIGRATION | FOLL_FOREIGN);
if (IS_ERR_OR_NULL(page))
break;
if (PageKsm(page))
ret = handle_mm_fault(vma->vm_mm, vma, addr,
- FAULT_FLAG_WRITE);
+ FAULT_FLAG_WRITE |
+ FAULT_FLAG_FOREIGN);
else
ret = VM_FAULT_WRITE;
put_page(page);
diff -puN mm/memory.c~pkeys-14-gup-fault-foreign-flag mm/memory.c
--- a/mm/memory.c~pkeys-14-gup-fault-foreign-flag 2016-01-06 15:50:10.637382635 -0800
+++ b/mm/memory.c 2016-01-06 15:50:10.646383040 -0800
@@ -3345,7 +3345,8 @@ static int __handle_mm_fault(struct mm_s
pmd_t *pmd;
pte_t *pte;
- if (!arch_vma_access_permitted(vma, flags & FAULT_FLAG_WRITE))
+ if (!arch_vma_access_permitted(vma, flags & FAULT_FLAG_WRITE,
+ flags & FAULT_FLAG_FOREIGN))
return VM_FAULT_SIGSEGV;
if (unlikely(is_vm_hugetlb_page(vma)))
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2016-01-07 01:10 +0100 |
| Subject | [PATCH 26/31] x86, pkeys: add arch_validate_pkey() |
| Message-ID | <qO6jq-8sH-57@gated-at.bofh.it> |
| In reply to | #1303164 |
From: Dave Hansen <dave.hansen@linux.intel.com>
The syscall-level code is passed a protection key and need to
return an appropriate error code if the protection key is bogus.
We will be using this in subsequent patches.
Note that this also begins a series of arch-specific calls that
we need to expose in otherwise arch-independent code. We create
a linux/pkeys.h header where we will put *all* the stubs for
these functions.
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
---
b/arch/x86/Kconfig | 1 +
b/arch/x86/include/asm/pkeys.h | 6 ++++++
b/include/linux/pkeys.h | 25 +++++++++++++++++++++++++
b/mm/Kconfig | 2 ++
4 files changed, 34 insertions(+)
diff -puN /dev/null arch/x86/include/asm/pkeys.h
--- /dev/null 2015-12-10 15:28:13.322405854 -0800
+++ b/arch/x86/include/asm/pkeys.h 2016-01-06 15:50:14.531558199 -0800
@@ -0,0 +1,6 @@
+#ifndef _ASM_X86_PKEYS_H
+#define _ASM_X86_PKEYS_H
+
+#define arch_max_pkey() (boot_cpu_has(X86_FEATURE_OSPKE) ? 16 : 1)
+
+#endif /*_ASM_X86_PKEYS_H */
diff -puN arch/x86/Kconfig~pkeys-71-arch_validate_pkey arch/x86/Kconfig
--- a/arch/x86/Kconfig~pkeys-71-arch_validate_pkey 2016-01-06 15:50:14.526557973 -0800
+++ b/arch/x86/Kconfig 2016-01-06 15:50:14.532558243 -0800
@@ -153,6 +153,7 @@ config X86
select X86_DEV_DMA_OPS if X86_64
select X86_FEATURE_NAMES if PROC_FS
select ARCH_USES_HIGH_VMA_FLAGS if X86_INTEL_MEMORY_PROTECTION_KEYS
+ select ARCH_HAS_PKEYS if X86_INTEL_MEMORY_PROTECTION_KEYS
config INSTRUCTION_DECODER
def_bool y
diff -puN /dev/null include/linux/pkeys.h
--- /dev/null 2015-12-10 15:28:13.322405854 -0800
+++ b/include/linux/pkeys.h 2016-01-06 15:50:14.532558243 -0800
@@ -0,0 +1,25 @@
+#ifndef _LINUX_PKEYS_H
+#define _LINUX_PKEYS_H
+
+#include <linux/mm_types.h>
+#include <asm/mmu_context.h>
+
+#ifdef CONFIG_ARCH_HAS_PKEYS
+#include <asm/pkeys.h>
+#else /* ! CONFIG_ARCH_HAS_PKEYS */
+#define arch_max_pkey() (1)
+#endif /* ! CONFIG_ARCH_HAS_PKEYS */
+
+/*
+ * This is called from mprotect_pkey().
+ *
+ * Returns true if the protection keys is valid.
+ */
+static inline bool validate_pkey(int pkey)
+{
+ if (pkey < 0)
+ return false;
+ return (pkey < arch_max_pkey());
+}
+
+#endif /* _LINUX_PKEYS_H */
diff -puN mm/Kconfig~pkeys-71-arch_validate_pkey mm/Kconfig
--- a/mm/Kconfig~pkeys-71-arch_validate_pkey 2016-01-06 15:50:14.528558063 -0800
+++ b/mm/Kconfig 2016-01-06 15:50:14.532558243 -0800
@@ -671,3 +671,5 @@ config FRAME_VECTOR
config ARCH_USES_HIGH_VMA_FLAGS
bool
+config ARCH_HAS_PKEYS
+ bool
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2016-01-08 20:40 +0100 |
| Subject | Re: [PATCH 26/31] x86, pkeys: add arch_validate_pkey() |
| Message-ID | <qOL3b-2Tb-1@gated-at.bofh.it> |
| In reply to | #1303188 |
On Wed, 6 Jan 2016, Dave Hansen wrote: > > From: Dave Hansen <dave.hansen@linux.intel.com> > > The syscall-level code is passed a protection key and need to > return an appropriate error code if the protection key is bogus. > We will be using this in subsequent patches. > > Note that this also begins a series of arch-specific calls that > we need to expose in otherwise arch-independent code. We create > a linux/pkeys.h header where we will put *all* the stubs for > these functions. > > Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2016-01-07 01:10 +0100 |
| Subject | [PATCH 08/31] x86, pkeys: new page fault error code bit: PF_PK |
| Message-ID | <qO6jr-8sH-79@gated-at.bofh.it> |
| In reply to | #1303164 |
From: Dave Hansen <dave.hansen@linux.intel.com>
Note: "PK" is how the Intel SDM refers to this bit, so we also
use that nomenclature.
This only defines the bit, it does not plumb it anywhere to be
handled.
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
---
b/arch/x86/mm/fault.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff -puN arch/x86/mm/fault.c~pkeys-05-pfec arch/x86/mm/fault.c
--- a/arch/x86/mm/fault.c~pkeys-05-pfec 2016-01-06 15:50:06.068176638 -0800
+++ b/arch/x86/mm/fault.c 2016-01-06 15:50:06.071176773 -0800
@@ -33,6 +33,7 @@
* bit 2 == 0: kernel-mode access 1: user-mode access
* bit 3 == 1: use of reserved bit detected
* bit 4 == 1: fault was an instruction fetch
+ * bit 5 == 1: protection keys block access
*/
enum x86_pf_error_code {
@@ -41,6 +42,7 @@ enum x86_pf_error_code {
PF_USER = 1 << 2,
PF_RSVD = 1 << 3,
PF_INSTR = 1 << 4,
+ PF_PK = 1 << 5,
};
/*
@@ -916,6 +918,12 @@ static int spurious_fault_check(unsigned
if ((error_code & PF_INSTR) && !pte_exec(*pte))
return 0;
+ /*
+ * Note: We do not do lazy flushing on protection key
+ * changes, so no spurious fault will ever set PF_PK.
+ */
+ if ((error_code & PF_PK))
+ return 1;
return 1;
}
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2016-01-07 01:10 +0100 |
| Subject | [PATCH 13/31] x86, pkeys: fill in pkey field in siginfo |
| Message-ID | <qO6jr-8sH-67@gated-at.bofh.it> |
| In reply to | #1303164 |
From: Dave Hansen <dave.hansen@linux.intel.com>
This fills in the new siginfo field: si_pkey to indicate to
userspace which protection key was set on the PTE that we faulted
on.
Note though that *ALL* protection key faults have to be generated
by a valid, present PTE at some point. But this code does no PTE
lookups which seeds odd. The reason is that we take advantage of
the way we generate PTEs from VMAs. All PTEs under a VMA share
some attributes. For instance, they are _all_ either PROT_READ
*OR* PROT_NONE. They also always share a protection key, so we
never have to walk the page tables; we just use the VMA.
Note that _pkey is a 64-bit value. The current hardware only
supports 4-bit protection keys. We do this because there is
_plenty_ of space in _sigfault and it is possible that future
processors would support more than 4 bits of protection keys.
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
---
b/arch/x86/include/asm/pgtable_types.h | 5 ++
b/arch/x86/mm/fault.c | 64 ++++++++++++++++++++++++++++++++-
2 files changed, 68 insertions(+), 1 deletion(-)
diff -puN arch/x86/include/asm/pgtable_types.h~pkeys-09-siginfo-x86 arch/x86/include/asm/pgtable_types.h
--- a/arch/x86/include/asm/pgtable_types.h~pkeys-09-siginfo-x86 2016-01-06 15:50:08.273276052 -0800
+++ b/arch/x86/include/asm/pgtable_types.h 2016-01-06 15:50:08.278276277 -0800
@@ -64,6 +64,11 @@
#endif
#define __HAVE_ARCH_PTE_SPECIAL
+#define _PAGE_PKEY_MASK (_PAGE_PKEY_BIT0 | \
+ _PAGE_PKEY_BIT1 | \
+ _PAGE_PKEY_BIT2 | \
+ _PAGE_PKEY_BIT3)
+
#ifdef CONFIG_KMEMCHECK
#define _PAGE_HIDDEN (_AT(pteval_t, 1) << _PAGE_BIT_HIDDEN)
#else
diff -puN arch/x86/mm/fault.c~pkeys-09-siginfo-x86 arch/x86/mm/fault.c
--- a/arch/x86/mm/fault.c~pkeys-09-siginfo-x86 2016-01-06 15:50:08.275276142 -0800
+++ b/arch/x86/mm/fault.c 2016-01-06 15:50:08.279276323 -0800
@@ -15,12 +15,14 @@
#include <linux/context_tracking.h> /* exception_enter(), ... */
#include <linux/uaccess.h> /* faulthandler_disabled() */
+#include <asm/cpufeature.h> /* boot_cpu_has, ... */
#include <asm/traps.h> /* dotraplinkage, ... */
#include <asm/pgalloc.h> /* pgd_*(), ... */
#include <asm/kmemcheck.h> /* kmemcheck_*(), ... */
#include <asm/fixmap.h> /* VSYSCALL_ADDR */
#include <asm/vsyscall.h> /* emulate_vsyscall */
#include <asm/vm86.h> /* struct vm86 */
+#include <asm/mmu_context.h> /* vma_pkey() */
#define CREATE_TRACE_POINTS
#include <asm/trace/exceptions.h>
@@ -169,6 +171,56 @@ is_prefetch(struct pt_regs *regs, unsign
return prefetch;
}
+/*
+ * A protection key fault means that the PKRU value did not allow
+ * access to some PTE. Userspace can figure out what PKRU was
+ * from the XSAVE state, and this function fills out a field in
+ * siginfo so userspace can discover which protection key was set
+ * on the PTE.
+ *
+ * If we get here, we know that the hardware signaled a PF_PK
+ * fault and that there was a VMA once we got in the fault
+ * handler. It does *not* guarantee that the VMA we find here
+ * was the one that we faulted on.
+ *
+ * 1. T1 : mprotect_key(foo, PAGE_SIZE, pkey=4);
+ * 2. T1 : set PKRU to deny access to pkey=4, touches page
+ * 3. T1 : faults...
+ * 4. T2: mprotect_key(foo, PAGE_SIZE, pkey=5);
+ * 5. T1 : enters fault handler, takes mmap_sem, etc...
+ * 6. T1 : reaches here, sees vma_pkey(vma)=5, when we really
+ * faulted on a pte with its pkey=4.
+ */
+static void fill_sig_info_pkey(int si_code, siginfo_t *info,
+ struct vm_area_struct *vma)
+{
+ /* This is effectively an #ifdef */
+ if (!boot_cpu_has(X86_FEATURE_OSPKE))
+ return;
+
+ /* Fault not from Protection Keys: nothing to do */
+ if (si_code != SEGV_PKUERR)
+ return;
+ /*
+ * force_sig_info_fault() is called from a number of
+ * contexts, some of which have a VMA and some of which
+ * do not. The PF_PK handing happens after we have a
+ * valid VMA, so we should never reach this without a
+ * valid VMA.
+ */
+ if (!vma) {
+ WARN_ONCE(1, "PKU fault with no VMA passed in");
+ info->si_pkey = 0;
+ return;
+ }
+ /*
+ * si_pkey should be thought of as a strong hint, but not
+ * absolutely guranteed to be 100% accurate because of
+ * the race explained above.
+ */
+ info->si_pkey = vma_pkey(vma);
+}
+
static void
force_sig_info_fault(int si_signo, int si_code, unsigned long address,
struct task_struct *tsk, struct vm_area_struct *vma,
@@ -187,6 +239,8 @@ force_sig_info_fault(int si_signo, int s
lsb = PAGE_SHIFT;
info.si_addr_lsb = lsb;
+ fill_sig_info_pkey(si_code, &info, vma);
+
force_sig_info(si_signo, &info, tsk);
}
@@ -847,7 +901,15 @@ static noinline void
bad_area_access_error(struct pt_regs *regs, unsigned long error_code,
unsigned long address, struct vm_area_struct *vma)
{
- __bad_area(regs, error_code, address, vma, SEGV_ACCERR);
+ /*
+ * This OSPKE check is not strictly necessary at runtime.
+ * But, doing it this way allows compiler optimizations
+ * if pkeys are compiled out.
+ */
+ if (boot_cpu_has(X86_FEATURE_OSPKE) && (error_code & PF_PK))
+ __bad_area(regs, error_code, address, vma, SEGV_PKUERR);
+ else
+ __bad_area(regs, error_code, address, vma, SEGV_ACCERR);
}
static void
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2016-01-07 01:10 +0100 |
| Subject | [PATCH 12/31] signals, pkeys: notify userspace about protection key faults |
| Message-ID | <qO6jr-8sH-69@gated-at.bofh.it> |
| In reply to | #1303164 |
From: Dave Hansen <dave.hansen@linux.intel.com>
A protection key fault is very similar to any other access error.
There must be a VMA, etc... We even want to take the same action
(SIGSEGV) that we do with a normal access fault.
However, we do need to let userspace know that something is
different. We do this the same way what we did with SEGV_BNDERR
with Memory Protection eXtensions (MPX): define a new SEGV code:
SEGV_PKUERR.
We add a siginfo field: si_pkey that reveals to userspace which
protection key was set on the PTE that we faulted on. There is
no other easy way for userspace to figure this out. They could
parse smaps but that would be a bit cruel.
We share space with in siginfo with _addr_bnd. #BR faults from
MPX are completely separate from page faults (#PF) that trigger
from protection key violations, so we never need both at the same
time.
Note that _pkey is a 64-bit value. The current hardware only
supports 4-bit protection keys. We do this because there is
_plenty_ of space in _sigfault and it is possible that future
processors would support more than 4 bits of protection keys.
The x86 code to actually fill in the siginfo is in the next
patch.
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
---
b/include/uapi/asm-generic/siginfo.h | 17 ++++++++++++-----
b/kernel/signal.c | 4 ++++
2 files changed, 16 insertions(+), 5 deletions(-)
diff -puN include/uapi/asm-generic/siginfo.h~pkeys-09-siginfo-core include/uapi/asm-generic/siginfo.h
--- a/include/uapi/asm-generic/siginfo.h~pkeys-09-siginfo-core 2016-01-06 15:50:07.838256440 -0800
+++ b/include/uapi/asm-generic/siginfo.h 2016-01-06 15:50:07.843256665 -0800
@@ -91,10 +91,15 @@ typedef struct siginfo {
int _trapno; /* TRAP # which caused the signal */
#endif
short _addr_lsb; /* LSB of the reported address */
- struct {
- void __user *_lower;
- void __user *_upper;
- } _addr_bnd;
+ union {
+ /* used when si_code=SEGV_BNDERR */
+ struct {
+ void __user *_lower;
+ void __user *_upper;
+ } _addr_bnd;
+ /* used when si_code=SEGV_PKUERR */
+ u64 _pkey;
+ };
} _sigfault;
/* SIGPOLL */
@@ -137,6 +142,7 @@ typedef struct siginfo {
#define si_addr_lsb _sifields._sigfault._addr_lsb
#define si_lower _sifields._sigfault._addr_bnd._lower
#define si_upper _sifields._sigfault._addr_bnd._upper
+#define si_pkey _sifields._sigfault._pkey
#define si_band _sifields._sigpoll._band
#define si_fd _sifields._sigpoll._fd
#ifdef __ARCH_SIGSYS
@@ -206,7 +212,8 @@ typedef struct siginfo {
#define SEGV_MAPERR (__SI_FAULT|1) /* address not mapped to object */
#define SEGV_ACCERR (__SI_FAULT|2) /* invalid permissions for mapped object */
#define SEGV_BNDERR (__SI_FAULT|3) /* failed address bound checks */
-#define NSIGSEGV 3
+#define SEGV_PKUERR (__SI_FAULT|4) /* failed protection key checks */
+#define NSIGSEGV 4
/*
* SIGBUS si_codes
diff -puN kernel/signal.c~pkeys-09-siginfo-core kernel/signal.c
--- a/kernel/signal.c~pkeys-09-siginfo-core 2016-01-06 15:50:07.840256530 -0800
+++ b/kernel/signal.c 2016-01-06 15:50:07.844256710 -0800
@@ -2709,6 +2709,10 @@ int copy_siginfo_to_user(siginfo_t __use
err |= __put_user(from->si_upper, &to->si_upper);
}
#endif
+#ifdef SEGV_PKUERR
+ if (from->si_signo == SIGSEGV && from->si_code == SEGV_PKUERR)
+ err |= __put_user(from->si_pkey, &to->si_pkey);
+#endif
break;
case __SI_CHLD:
err |= __put_user(from->si_pid, &to->si_pid);
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2016-01-07 01:10 +0100 |
| Subject | [PATCH 23/31] x86, pkeys: add Kconfig prompt to existing config option |
| Message-ID | <qO6jr-8sH-81@gated-at.bofh.it> |
| In reply to | #1303164 |
From: Dave Hansen <dave.hansen@linux.intel.com> I don't have a strong opinion on whether we need this or not. Protection Keys has relatively little code associated with it, and it is not a heavyweight feature to keep enabled. However, I can imagine that folks would still appreciate being able to disable it. Here's the option if folks want it. Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> --- b/arch/x86/Kconfig | 10 ++++++++++ 1 file changed, 10 insertions(+) diff -puN arch/x86/Kconfig~pkeys-40-kconfig-prompt arch/x86/Kconfig --- a/arch/x86/Kconfig~pkeys-40-kconfig-prompt 2016-01-06 15:50:13.114494312 -0800 +++ b/arch/x86/Kconfig 2016-01-06 15:50:13.117494447 -0800 @@ -1682,8 +1682,18 @@ config X86_INTEL_MPX If unsure, say N. config X86_INTEL_MEMORY_PROTECTION_KEYS + prompt "Intel Memory Protection Keys" def_bool y + # Note: only available in 64-bit mode depends on CPU_SUP_INTEL && X86_64 + ---help--- + Memory Protection Keys provides a mechanism for enforcing + page-based protections, but without requiring modification of the + page tables when an application changes protection domains. + + For details, see Documentation/x86/protection-keys.txt + + If unsure, say y. config EFI bool "EFI runtime service support" _ -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2016-01-07 01:10 +0100 |
| Subject | [PATCH 15/31] mm: factor out VMA fault permission checking |
| Message-ID | <qO6jr-8sH-83@gated-at.bofh.it> |
| In reply to | #1303164 |
From: Dave Hansen <dave.hansen@linux.intel.com>
This code matches a fault condition up with the VMA and ensures
that the VMA allows the fault to be handled instead of just
erroring out.
We will be extending this in a moment to comprehend protection
keys.
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
---
b/mm/gup.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff -puN mm/gup.c~pkeys-10-pte-fault mm/gup.c
--- a/mm/gup.c~pkeys-10-pte-fault 2016-01-06 15:50:09.144315322 -0800
+++ b/mm/gup.c 2016-01-06 15:50:09.148315502 -0800
@@ -557,6 +557,18 @@ next_page:
}
EXPORT_SYMBOL(__get_user_pages);
+bool vma_permits_fault(struct vm_area_struct *vma, unsigned int fault_flags)
+{
+ vm_flags_t vm_flags;
+
+ vm_flags = (fault_flags & FAULT_FLAG_WRITE) ? VM_WRITE : VM_READ;
+
+ if (!(vm_flags & vma->vm_flags))
+ return false;
+
+ return true;
+}
+
/*
* fixup_user_fault() - manually resolve a user page fault
* @tsk: the task_struct to use for page fault accounting, or
@@ -588,15 +600,13 @@ int fixup_user_fault(struct task_struct
unsigned long address, unsigned int fault_flags)
{
struct vm_area_struct *vma;
- vm_flags_t vm_flags;
int ret;
vma = find_extend_vma(mm, address);
if (!vma || address < vma->vm_start)
return -EFAULT;
- vm_flags = (fault_flags & FAULT_FLAG_WRITE) ? VM_WRITE : VM_READ;
- if (!(vm_flags & vma->vm_flags))
+ if (!vma_permits_fault(vma, fault_flags))
return -EFAULT;
ret = handle_mm_fault(mm, vma, address, fault_flags);
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2016-01-07 01:10 +0100 |
| Subject | [PATCH 04/31] x86, pkeys: cpuid bit definition |
| Message-ID | <qO6jr-8sH-87@gated-at.bofh.it> |
| In reply to | #1303164 |
From: Dave Hansen <dave.hansen@linux.intel.com> There are two CPUID bits for protection keys. One is for whether the CPU contains the feature, and the other will appear set once the OS enables protection keys. Specifically: Bit 04: OSPKE. If 1, OS has set CR4.PKE to enable Protection keys (and the RDPKRU/WRPKRU instructions) This is because userspace can not see CR4 contents, but it can see CPUID contents. X86_FEATURE_PKU is referred to as "PKU" in the hardware documentation: CPUID.(EAX=07H,ECX=0H):ECX.PKU [bit 3] X86_FEATURE_OSPKE is "OSPKU": CPUID.(EAX=07H,ECX=0H):ECX.OSPKE [bit 4] These are the first CPU features which need to look at the ECX word in CPUID leaf 0x7, so this patch also includes fetching that word in to the cpuinfo->x86_capability[] array. Add it to the disabled-features mask when its config option is off. Even though we are not using it here, we also extend the REQUIRED_MASK_BIT_SET() macro to keep it mirroring the DISABLED_MASK_BIT_SET() version. This means that in almost all code, you should use: cpu_has(c, X86_FEATURE_PKU) and *not* the CONFIG option. Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> --- b/arch/x86/include/asm/cpufeature.h | 56 ++++++++++++++++++----------- b/arch/x86/include/asm/disabled-features.h | 13 ++++++ b/arch/x86/include/asm/required-features.h | 5 ++ b/arch/x86/kernel/cpu/common.c | 1 4 files changed, 54 insertions(+), 21 deletions(-) diff -puN arch/x86/include/asm/cpufeature.h~pkeys-01-cpuid arch/x86/include/asm/cpufeature.h --- a/arch/x86/include/asm/cpufeature.h~pkeys-01-cpuid 2016-01-06 15:50:04.310097377 -0800 +++ b/arch/x86/include/asm/cpufeature.h 2016-01-06 15:50:04.318097738 -0800 @@ -12,7 +12,7 @@ #include <asm/disabled-features.h> #endif -#define NCAPINTS 14 /* N 32-bit words worth of info */ +#define NCAPINTS 15 /* N 32-bit words worth of info */ #define NBUGINTS 1 /* N 32-bit bug flags */ /* @@ -258,6 +258,10 @@ /* AMD-defined CPU features, CPUID level 0x80000008 (ebx), word 13 */ #define X86_FEATURE_CLZERO (13*32+0) /* CLZERO instruction */ +/* Intel-defined CPU features, CPUID level 0x00000007:0 (ecx), word 13 */ +#define X86_FEATURE_PKU (14*32+ 3) /* Protection Keys for Userspace */ +#define X86_FEATURE_OSPKE (14*32+ 4) /* OS Protection Keys Enable */ + /* * BUG word(s) */ @@ -298,28 +302,38 @@ extern const char * const x86_bug_flags[ test_bit(bit, (unsigned long *)((c)->x86_capability)) #define REQUIRED_MASK_BIT_SET(bit) \ - ( (((bit)>>5)==0 && (1UL<<((bit)&31) & REQUIRED_MASK0)) || \ - (((bit)>>5)==1 && (1UL<<((bit)&31) & REQUIRED_MASK1)) || \ - (((bit)>>5)==2 && (1UL<<((bit)&31) & REQUIRED_MASK2)) || \ - (((bit)>>5)==3 && (1UL<<((bit)&31) & REQUIRED_MASK3)) || \ - (((bit)>>5)==4 && (1UL<<((bit)&31) & REQUIRED_MASK4)) || \ - (((bit)>>5)==5 && (1UL<<((bit)&31) & REQUIRED_MASK5)) || \ - (((bit)>>5)==6 && (1UL<<((bit)&31) & REQUIRED_MASK6)) || \ - (((bit)>>5)==7 && (1UL<<((bit)&31) & REQUIRED_MASK7)) || \ - (((bit)>>5)==8 && (1UL<<((bit)&31) & REQUIRED_MASK8)) || \ - (((bit)>>5)==9 && (1UL<<((bit)&31) & REQUIRED_MASK9)) ) + ( (((bit)>>5)==0 && (1UL<<((bit)&31) & REQUIRED_MASK0 )) || \ + (((bit)>>5)==1 && (1UL<<((bit)&31) & REQUIRED_MASK1 )) || \ + (((bit)>>5)==2 && (1UL<<((bit)&31) & REQUIRED_MASK2 )) || \ + (((bit)>>5)==3 && (1UL<<((bit)&31) & REQUIRED_MASK3 )) || \ + (((bit)>>5)==4 && (1UL<<((bit)&31) & REQUIRED_MASK4 )) || \ + (((bit)>>5)==5 && (1UL<<((bit)&31) & REQUIRED_MASK5 )) || \ + (((bit)>>5)==6 && (1UL<<((bit)&31) & REQUIRED_MASK6 )) || \ + (((bit)>>5)==7 && (1UL<<((bit)&31) & REQUIRED_MASK7 )) || \ + (((bit)>>5)==8 && (1UL<<((bit)&31) & REQUIRED_MASK8 )) || \ + (((bit)>>5)==9 && (1UL<<((bit)&31) & REQUIRED_MASK9 )) || \ + (((bit)>>5)==10 && (1UL<<((bit)&31) & REQUIRED_MASK10)) || \ + (((bit)>>5)==11 && (1UL<<((bit)&31) & REQUIRED_MASK11)) || \ + (((bit)>>5)==12 && (1UL<<((bit)&31) & REQUIRED_MASK12)) || \ + (((bit)>>5)==13 && (1UL<<((bit)&31) & REQUIRED_MASK13)) || \ + (((bit)>>5)==14 && (1UL<<((bit)&31) & REQUIRED_MASK14)) ) #define DISABLED_MASK_BIT_SET(bit) \ - ( (((bit)>>5)==0 && (1UL<<((bit)&31) & DISABLED_MASK0)) || \ - (((bit)>>5)==1 && (1UL<<((bit)&31) & DISABLED_MASK1)) || \ - (((bit)>>5)==2 && (1UL<<((bit)&31) & DISABLED_MASK2)) || \ - (((bit)>>5)==3 && (1UL<<((bit)&31) & DISABLED_MASK3)) || \ - (((bit)>>5)==4 && (1UL<<((bit)&31) & DISABLED_MASK4)) || \ - (((bit)>>5)==5 && (1UL<<((bit)&31) & DISABLED_MASK5)) || \ - (((bit)>>5)==6 && (1UL<<((bit)&31) & DISABLED_MASK6)) || \ - (((bit)>>5)==7 && (1UL<<((bit)&31) & DISABLED_MASK7)) || \ - (((bit)>>5)==8 && (1UL<<((bit)&31) & DISABLED_MASK8)) || \ - (((bit)>>5)==9 && (1UL<<((bit)&31) & DISABLED_MASK9)) ) + ( (((bit)>>5)==0 && (1UL<<((bit)&31) & DISABLED_MASK0 )) || \ + (((bit)>>5)==1 && (1UL<<((bit)&31) & DISABLED_MASK1 )) || \ + (((bit)>>5)==2 && (1UL<<((bit)&31) & DISABLED_MASK2 )) || \ + (((bit)>>5)==3 && (1UL<<((bit)&31) & DISABLED_MASK3 )) || \ + (((bit)>>5)==4 && (1UL<<((bit)&31) & DISABLED_MASK4 )) || \ + (((bit)>>5)==5 && (1UL<<((bit)&31) & DISABLED_MASK5 )) || \ + (((bit)>>5)==6 && (1UL<<((bit)&31) & DISABLED_MASK6 )) || \ + (((bit)>>5)==7 && (1UL<<((bit)&31) & DISABLED_MASK7 )) || \ + (((bit)>>5)==8 && (1UL<<((bit)&31) & DISABLED_MASK8 )) || \ + (((bit)>>5)==9 && (1UL<<((bit)&31) & DISABLED_MASK9 )) || \ + (((bit)>>5)==10 && (1UL<<((bit)&31) & DISABLED_MASK10)) || \ + (((bit)>>5)==11 && (1UL<<((bit)&31) & DISABLED_MASK11)) || \ + (((bit)>>5)==12 && (1UL<<((bit)&31) & DISABLED_MASK12)) || \ + (((bit)>>5)==13 && (1UL<<((bit)&31) & DISABLED_MASK13)) || \ + (((bit)>>5)==14 && (1UL<<((bit)&31) & DISABLED_MASK14)) ) #define cpu_has(c, bit) \ (__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 : \ diff -puN arch/x86/include/asm/disabled-features.h~pkeys-01-cpuid arch/x86/include/asm/disabled-features.h --- a/arch/x86/include/asm/disabled-features.h~pkeys-01-cpuid 2016-01-06 15:50:04.311097422 -0800 +++ b/arch/x86/include/asm/disabled-features.h 2016-01-06 15:50:04.318097738 -0800 @@ -28,6 +28,14 @@ # define DISABLE_CENTAUR_MCR 0 #endif /* CONFIG_X86_64 */ +#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS +# define DISABLE_PKU (1<<(X86_FEATURE_PKU)) +# define DISABLE_OSPKE (1<<(X86_FEATURE_OSPKE)) +#else +# define DISABLE_PKU 0 +# define DISABLE_OSPKE 0 +#endif /* CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS */ + /* * Make sure to add features to the correct mask */ @@ -41,5 +49,10 @@ #define DISABLED_MASK7 0 #define DISABLED_MASK8 0 #define DISABLED_MASK9 (DISABLE_MPX) +#define DISABLED_MASK10 0 +#define DISABLED_MASK11 0 +#define DISABLED_MASK12 0 +#define DISABLED_MASK13 0 +#define DISABLED_MASK14 (DISABLE_PKU|DISABLE_OSPKE) #endif /* _ASM_X86_DISABLED_FEATURES_H */ diff -puN arch/x86/include/asm/required-features.h~pkeys-01-cpuid arch/x86/include/asm/required-features.h --- a/arch/x86/include/asm/required-features.h~pkeys-01-cpuid 2016-01-06 15:50:04.313097512 -0800 +++ b/arch/x86/include/asm/required-features.h 2016-01-06 15:50:04.318097738 -0800 @@ -92,5 +92,10 @@ #define REQUIRED_MASK7 0 #define REQUIRED_MASK8 0 #define REQUIRED_MASK9 0 +#define REQUIRED_MASK10 0 +#define REQUIRED_MASK11 0 +#define REQUIRED_MASK12 0 +#define REQUIRED_MASK13 0 +#define REQUIRED_MASK14 0 #endif /* _ASM_X86_REQUIRED_FEATURES_H */ diff -puN arch/x86/kernel/cpu/common.c~pkeys-01-cpuid arch/x86/kernel/cpu/common.c --- a/arch/x86/kernel/cpu/common.c~pkeys-01-cpuid 2016-01-06 15:50:04.314097557 -0800 +++ b/arch/x86/kernel/cpu/common.c 2016-01-06 15:50:04.319097783 -0800 @@ -619,6 +619,7 @@ void get_cpu_cap(struct cpuinfo_x86 *c) cpuid_count(0x00000007, 0, &eax, &ebx, &ecx, &edx); c->x86_capability[9] = ebx; + c->x86_capability[14] = ecx; } /* Extended state features: level 0x0000000d */ _ -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2016-01-07 01:10 +0100 |
| Subject | [PATCH 20/31] x86, pkeys: differentiate instruction fetches |
| Message-ID | <qO6jr-8sH-89@gated-at.bofh.it> |
| In reply to | #1303164 |
From: Dave Hansen <dave.hansen@linux.intel.com>
As discussed earlier, we attempt to enforce protection keys in
software.
However, the code checks all faults to ensure that they are not
violating protection key permissions. It was assumed that all
faults are either write faults where we check PKRU[key].WD (write
disable) or read faults where we check the AD (access disable)
bit.
But, there is a third category of faults for protection keys:
instruction faults. Instruction faults never run afoul of
protection keys because they do not affect instruction fetches.
So, plumb the PF_INSTR bit down in to the
arch_vma_access_permitted() function where we do the protection
key checks.
We also add a new FAULT_FLAG_INSTRUCTION. This is because
handle_mm_fault() is not passed the architecture-specific
error_code where we keep PF_INSTR, so we need to encode the
instruction fetch information in to the arch-generic fault
flags.
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
---
b/arch/powerpc/include/asm/mmu_context.h | 2 +-
b/arch/s390/include/asm/mmu_context.h | 2 +-
b/arch/x86/include/asm/mmu_context.h | 5 ++++-
b/arch/x86/mm/fault.c | 8 ++++++--
b/include/asm-generic/mm_hooks.h | 2 +-
b/include/linux/mm.h | 1 +
b/mm/gup.c | 11 +++++++++--
b/mm/memory.c | 1 +
8 files changed, 24 insertions(+), 8 deletions(-)
diff -puN arch/powerpc/include/asm/mmu_context.h~pkeys-16-allow-execute-on-unreadable arch/powerpc/include/asm/mmu_context.h
--- a/arch/powerpc/include/asm/mmu_context.h~pkeys-16-allow-execute-on-unreadable 2016-01-06 15:50:11.677429524 -0800
+++ b/arch/powerpc/include/asm/mmu_context.h 2016-01-06 15:50:11.692430200 -0800
@@ -149,7 +149,7 @@ static inline void arch_bprm_mm_init(str
}
static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,
- bool write, bool foreign)
+ bool write, bool execute, bool foreign)
{
/* by default, allow everything */
return true;
diff -puN arch/s390/include/asm/mmu_context.h~pkeys-16-allow-execute-on-unreadable arch/s390/include/asm/mmu_context.h
--- a/arch/s390/include/asm/mmu_context.h~pkeys-16-allow-execute-on-unreadable 2016-01-06 15:50:11.679429614 -0800
+++ b/arch/s390/include/asm/mmu_context.h 2016-01-06 15:50:11.692430200 -0800
@@ -131,7 +131,7 @@ static inline void arch_bprm_mm_init(str
}
static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,
- bool write, bool foreign)
+ bool write, bool execute, bool foreign)
{
/* by default, allow everything */
return true;
diff -puN arch/x86/include/asm/mmu_context.h~pkeys-16-allow-execute-on-unreadable arch/x86/include/asm/mmu_context.h
--- a/arch/x86/include/asm/mmu_context.h~pkeys-16-allow-execute-on-unreadable 2016-01-06 15:50:11.681429704 -0800
+++ b/arch/x86/include/asm/mmu_context.h 2016-01-06 15:50:11.693430245 -0800
@@ -291,8 +291,11 @@ static inline bool vma_is_foreign(struct
}
static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,
- bool write, bool foreign)
+ bool write, bool execute, bool foreign)
{
+ /* pkeys never affect instruction fetches */
+ if (execute)
+ return true;
/* allow access if the VMA is not one from this process */
if (foreign || vma_is_foreign(vma))
return true;
diff -puN arch/x86/mm/fault.c~pkeys-16-allow-execute-on-unreadable arch/x86/mm/fault.c
--- a/arch/x86/mm/fault.c~pkeys-16-allow-execute-on-unreadable 2016-01-06 15:50:11.682429749 -0800
+++ b/arch/x86/mm/fault.c 2016-01-06 15:50:11.693430245 -0800
@@ -908,7 +908,8 @@ static inline bool bad_area_access_from_
if (error_code & PF_PK)
return true;
/* this checks permission keys on the VMA: */
- if (!arch_vma_access_permitted(vma, (error_code & PF_WRITE), foreign))
+ if (!arch_vma_access_permitted(vma, (error_code & PF_WRITE),
+ (error_code & PF_INSTR), foreign))
return true;
return false;
}
@@ -1112,7 +1113,8 @@ access_error(unsigned long error_code, s
* faults just to hit a PF_PK as soon as we fill in a
* page.
*/
- if (!arch_vma_access_permitted(vma, (error_code & PF_WRITE), foreign))
+ if (!arch_vma_access_permitted(vma, (error_code & PF_WRITE),
+ (error_code & PF_INSTR), foreign))
return 1;
if (error_code & PF_WRITE) {
@@ -1267,6 +1269,8 @@ __do_page_fault(struct pt_regs *regs, un
if (error_code & PF_WRITE)
flags |= FAULT_FLAG_WRITE;
+ if (error_code & PF_INSTR)
+ flags |= FAULT_FLAG_INSTRUCTION;
/*
* When running in the kernel we expect faults to occur only to
diff -puN include/asm-generic/mm_hooks.h~pkeys-16-allow-execute-on-unreadable include/asm-generic/mm_hooks.h
--- a/include/asm-generic/mm_hooks.h~pkeys-16-allow-execute-on-unreadable 2016-01-06 15:50:11.684429839 -0800
+++ b/include/asm-generic/mm_hooks.h 2016-01-06 15:50:11.694430290 -0800
@@ -27,7 +27,7 @@ static inline void arch_bprm_mm_init(str
}
static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,
- bool write, bool foreign)
+ bool write, bool execute, bool foreign)
{
/* by default, allow everything */
return true;
diff -puN include/linux/mm.h~pkeys-16-allow-execute-on-unreadable include/linux/mm.h
--- a/include/linux/mm.h~pkeys-16-allow-execute-on-unreadable 2016-01-06 15:50:11.685429885 -0800
+++ b/include/linux/mm.h 2016-01-06 15:50:11.695430335 -0800
@@ -238,6 +238,7 @@ extern pgprot_t protection_map[16];
#define FAULT_FLAG_TRIED 0x20 /* Second try */
#define FAULT_FLAG_USER 0x40 /* The fault originated in userspace */
#define FAULT_FLAG_FOREIGN 0x80 /* faulting for non current tsk/mm */
+#define FAULT_FLAG_INSTRUCTION 0x100 /* The fault was during an instruction fetch */
/*
* vm_fault is filled by the the pagefault handler and passed to the vma's
diff -puN mm/gup.c~pkeys-16-allow-execute-on-unreadable mm/gup.c
--- a/mm/gup.c~pkeys-16-allow-execute-on-unreadable 2016-01-06 15:50:11.687429975 -0800
+++ b/mm/gup.c 2016-01-06 15:50:11.695430335 -0800
@@ -396,7 +396,11 @@ static int check_vma_flags(struct vm_are
if (!(vm_flags & VM_MAYREAD))
return -EFAULT;
}
- if (!arch_vma_access_permitted(vma, write, foreign))
+ /*
+ * gups are always data accesses, not instruction
+ * fetches, so execute=false here
+ */
+ if (!arch_vma_access_permitted(vma, write, false, foreign))
return -EFAULT;
return 0;
}
@@ -576,8 +580,11 @@ bool vma_permits_fault(struct vm_area_st
/*
* The architecture might have a hardware protection
* mechanism other than read/write that can deny access.
+ *
+ * gup always represents data access, not instruction
+ * fetches, so execute=false here:
*/
- if (!arch_vma_access_permitted(vma, write, foreign))
+ if (!arch_vma_access_permitted(vma, write, false, foreign))
return false;
return true;
diff -puN mm/memory.c~pkeys-16-allow-execute-on-unreadable mm/memory.c
--- a/mm/memory.c~pkeys-16-allow-execute-on-unreadable 2016-01-06 15:50:11.689430065 -0800
+++ b/mm/memory.c 2016-01-06 15:50:11.696430380 -0800
@@ -3346,6 +3346,7 @@ static int __handle_mm_fault(struct mm_s
pte_t *pte;
if (!arch_vma_access_permitted(vma, flags & FAULT_FLAG_WRITE,
+ flags & FAULT_FLAG_INSTRUCTION,
flags & FAULT_FLAG_FOREIGN))
return VM_FAULT_SIGSEGV;
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
Page 2 of 3 — ← Prev page 1 [2] 3 Next page →
Back to top | Article view | linux.kernel
csiph-web