Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1452468 > unrolled thread
| Started by | Dave Hansen <dave@sr71.net> |
|---|---|
| First post | 2016-07-29 18:40 +0200 |
| Last post | 2016-07-29 18:40 +0200 |
| Articles | 4 — 1 participant |
Back to article view | Back to linux.kernel
[PATCH 00/10] [v6] System Calls for Memory Protection Keys Dave Hansen <dave@sr71.net> - 2016-07-29 18:40 +0200
[PATCH 07/10] pkeys: add details of system call use to Documentation/ Dave Hansen <dave@sr71.net> - 2016-07-29 18:40 +0200
[PATCH 03/10] x86, pkeys: make mprotect_key() mask off additional vm_flags Dave Hansen <dave@sr71.net> - 2016-07-29 18:40 +0200
[PATCH 02/10] mm: implement new pkey_mprotect() system call Dave Hansen <dave@sr71.net> - 2016-07-29 18:40 +0200
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2016-07-29 18:40 +0200 |
| Subject | [PATCH 00/10] [v6] System Calls for Memory Protection Keys |
| Message-ID | <s0iZj-763-3@gated-at.bofh.it> |
This set takes all of the feedback on the last version into
account and simplifies the ABI. It adds one feature: restrictive
'init_pkru' support. I realize it's during the merge window, but
I'm posting so folks who aren't busy with merge window activities
can take a look.
Barring any new issues, I think this is ready to be applied once
4.9 material is being queued.
Folks wishing to run this code can do so on any processor with
the new PKU support in qemu >=2.6. Just boot with -cpu
qemu64,+pku,+xsave, and make sure to apply this patch[1] to qemu.
Changes from v5:
* Removed pkey_set/get() system calls to simplify ABI
* Added 'init_pkru' support to ensure we have a restrictive
PKRU by default.
* Requisite changes to selftests, plus some bugfixes around
stdio in signal handlers
--
Memory Protection Keys for User pages (pkeys) is a CPU feature
which will first appear on Skylake Servers, but will also be
supported on future non-server parts. It provides a mechanism
for enforcing page-based protections, but without requiring
modification of the page tables when an application changes
wishes to change permissions.
Among other things, this feature was designed to help fix a class
of bugs in long-running applications where data corruption is
detected long after it occurs. Applications today either live
with the corruption or eat a huge performance penalty from
calling mprotect() frequently. The developers of these
applications are already running this code and are very eager to
see this feature merged and picked up in future distributions
where their customers can use it.
Patches to implement execute-only mapping support using pkeys
were merged in to 4.6. But, to do anything more useful with
pkeys, an application needs to be able to set the pkey field in
the PTE (obviously has to be done in-kernel) and make changes to
the "rights" register (using unprivileged instructions).
An application also needs to have an an allocator for the keys
themselves. If two different parts of an application both want
to protect their data with pkeys, they first need to know which
key to use for their individual purposes.
This set introduces 3 system calls:
sys_pkey_mprotect(): apply PTE to memory (patches #1-3)
sys_pkey_alloc(): ask the kernel for a free pkey (patch #4)
sys_pkey_free(): the reverse of alloc (patch #4)
I have manpages written for these syscalls, and have had multiple
rounds of reviews on the manpages list. I have not revised them
to remove pkey_get/set(), but will once this is merged in -tip.
This set is also available here:
git://git.kernel.org/pub/scm/linux/kernel/git/daveh/x86-pkeys.git pkeys-v040
I've written a set of unit tests for these interfaces, which is
available as the last patch in the series and integrated in to
kselftests.
Folks wishing to run this code can do so with the new PKU support
in qemu >=2.6. Just boot with -cpu qemu64,+pku,+xsave, and make
sure to apply this patch[1] to qemu.
=== diffstat ===
Dave Hansen (10):
x86, pkeys: add fault handling for PF_PK page fault bit
mm: implement new pkey_mprotect() system call
x86, pkeys: make mprotect_key() mask off additional vm_flags
x86, pkeys: allocation/free syscalls
x86: wire up protection keys system calls
generic syscalls: wire up memory protection keys syscalls
pkeys: add details of system call use to Documentation/
x86, pkeys: default to a restrictive init PKRU
x86, pkeys: allow configuration of init_pkru
x86, pkeys: add self-tests
Documentation/kernel-parameters.txt | 5 +
Documentation/x86/protection-keys.txt | 63 +
arch/alpha/include/uapi/asm/mman.h | 5 +
arch/mips/include/uapi/asm/mman.h | 5 +
arch/parisc/include/uapi/asm/mman.h | 5 +
arch/x86/entry/syscalls/syscall_32.tbl | 5 +
arch/x86/entry/syscalls/syscall_64.tbl | 5 +
arch/x86/include/asm/mmu.h | 8 +
arch/x86/include/asm/mmu_context.h | 25 +-
arch/x86/include/asm/pkeys.h | 73 +-
arch/x86/kernel/fpu/core.c | 4 +
arch/x86/kernel/fpu/xstate.c | 5 +-
arch/x86/mm/fault.c | 9 +
arch/x86/mm/pkeys.c | 143 +-
arch/xtensa/include/uapi/asm/mman.h | 5 +
include/linux/pkeys.h | 41 +-
include/linux/syscalls.h | 8 +
include/uapi/asm-generic/mman-common.h | 5 +
include/uapi/asm-generic/unistd.h | 12 +-
mm/mprotect.c | 90 +-
tools/testing/selftests/x86/Makefile | 3 +-
tools/testing/selftests/x86/pkey-helpers.h | 219 +++
tools/testing/selftests/x86/protection_keys.c | 1411 +++++++++++++++++
23 files changed, 2116 insertions(+), 38 deletions(-)
=== changelog ===
Changes from v5:
* remove sys_pkey_get/set() to simplify the ABI. There was
concern they could not be easily vsyscall-accelerated.
* Added 'init_pkru' support to ensure we have a restrictive
PKRU by default.
* Requisite changes to selftests, plus some bugfixes around
stdio in signal handlers
Changes from v4:
* removed validate_pkey(). It was redundant with the work we do
in mm_pkey_alloc() and all of the mm_pkey_is_allocated() checks.
* reorder patches to wait to wire up any syscalls until the end.
* make allocation map functions explicity use unsigned masks
* some tweaks to changelog (and associated manpages)
Changes from v3:
* added generic syscalls declarations to include/linux/syscalls.h
to fix arm64 compile issue.
Changes from v2:
* selftest updates:
* formatting changes like what Ingo asked for with MPX
* actually call WRPKRU in __wrpkru()
* once __wrpkru() was fixed, revealed a bug in the ptrace
test where we were testing against the wrong pointer during
the "baseline" test
* Man-pages that match this set are here:
http://marc.info/?l=linux-man&m=146540723525616&w=2
Changes from v1:
* updates to alloc/free patch description calling out that
"in-use" pkeys may still be pkey_free()'d successfully.
* Fixed a bug in the selftest where the 'flags' argument was
not passed to pkey_get().
* Added all syscalls to generic syscalls header
* Added extra checking to selftests so it doesn't fall over
when 1G pages are made the hugetlbfs default.
1. http://lists.nongnu.org/archive/html/qemu-devel/2016-07/msg04774.html
Cc: linux-api@vger.kernel.org
Cc: linux-arch@vger.kernel.org
Cc: linux-mm@kvack.org
Cc: x86@kernel.org
Cc: torvalds@linux-foundation.org
Cc: akpm@linux-foundation.org
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: mgorman@techsingularity.net
Cc: Dave Hansen (Intel) <dave.hansen@intel.com>
[toc] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2016-07-29 18:40 +0200 |
| Subject | [PATCH 07/10] pkeys: add details of system call use to Documentation/ |
| Message-ID | <s0iZk-763-23@gated-at.bofh.it> |
| In reply to | #1452468 |
From: Dave Hansen <dave.hansen@linux.intel.com> This spells out all of the pkey-related system calls that we have and provides some example code fragments to demonstrate how we expect them to be used. Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Cc: linux-api@vger.kernel.org Cc: linux-arch@vger.kernel.org Cc: linux-mm@kvack.org Cc: x86@kernel.org Cc: torvalds@linux-foundation.org Cc: akpm@linux-foundation.org Cc: Arnd Bergmann <arnd@arndb.de> Cc: mgorman@techsingularity.net --- b/Documentation/x86/protection-keys.txt | 62 ++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff -puN Documentation/x86/protection-keys.txt~pkeys-120-syscall-docs Documentation/x86/protection-keys.txt --- a/Documentation/x86/protection-keys.txt~pkeys-120-syscall-docs 2016-07-29 09:18:58.863582283 -0700 +++ b/Documentation/x86/protection-keys.txt 2016-07-29 09:18:58.866582419 -0700 @@ -18,6 +18,68 @@ even though there is theoretically space permissions are enforced on data access only and have no effect on instruction fetches. +=========================== Syscalls =========================== + +There are 2 system calls which directly interact with pkeys: + + int pkey_alloc(unsigned long flags, unsigned long init_access_rights) + int pkey_free(int pkey); + int pkey_mprotect(unsigned long start, size_t len, + unsigned long prot, int pkey); + +Before a pkey can be used, it must first be allocated with +pkey_alloc(). An application calls the WRPKRU instruction +directly in order to change access permissions to memory covered +with a key. In this example WRPKRU is wrapped by a C function +called pkey_set(). + + int real_prot = PROT_READ|PROT_WRITE; + pkey = pkey_alloc(0, PKEY_DENY_WRITE); + ptr = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + ret = pkey_mprotect(ptr, PAGE_SIZE, real_prot, pkey); + ... application runs here + +Now, if the application needs to update the data at 'ptr', it can +gain access, do the update, then remove its write access: + + pkey_set(pkey, 0); // clear PKEY_DENY_WRITE + *ptr = foo; // assign something + pkey_set(pkey, PKEY_DENY_WRITE); // set PKEY_DENY_WRITE again + +Now when it frees the memory, it will also free the pkey since it +is no longer in use: + + munmap(ptr, PAGE_SIZE); + pkey_free(pkey); + +=========================== Behavior =========================== + +The kernel attempts to make protection keys consistent with the +behavior of a plain mprotect(). For instance if you do this: + + mprotect(ptr, size, PROT_NONE); + something(ptr); + +you can expect the same effects with protection keys when doing this: + + pkey = pkey_alloc(0, PKEY_DISABLE_WRITE | PKEY_DISABLE_READ); + pkey_mprotect(ptr, size, PROT_READ|PROT_WRITE, pkey); + something(ptr); + +That should be true whether something() is a direct access to 'ptr' +like: + + *ptr = foo; + +or when the kernel does the access on the application's behalf like +with a read(): + + read(fd, ptr, 1); + +The kernel will send a SIGSEGV in both cases, but si_code will be set +to SEGV_PKERR when violating protection keys versus SEGV_ACCERR when +the plain mprotect() permissions are violated. + =========================== Config Option =========================== This config option adds approximately 1.5kb of text. and 50 bytes of _
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2016-07-29 18:40 +0200 |
| Subject | [PATCH 03/10] x86, pkeys: make mprotect_key() mask off additional vm_flags |
| Message-ID | <s0iZk-763-29@gated-at.bofh.it> |
| In reply to | #1452468 |
From: Dave Hansen <dave.hansen@linux.intel.com>
Today, mprotect() takes 4 bits of data: PROT_READ/WRITE/EXEC/NONE.
Three of those bits: READ/WRITE/EXEC get translated directly in to
vma->vm_flags by calc_vm_prot_bits(). If a bit is unset in
mprotect()'s 'prot' argument then it must be cleared in vma->vm_flags
during the mprotect() call.
We do this clearing today by first calculating the VMA flags we
want set, then clearing the ones we do not want to inherit from
the original VMA:
vm_flags = calc_vm_prot_bits(prot, key);
...
newflags = vm_flags;
newflags |= (vma->vm_flags & ~(VM_READ | VM_WRITE | VM_EXEC));
However, we *also* want to mask off the original VMA's vm_flags in
which we store the protection key.
To do that, this patch adds a new macro:
ARCH_VM_PKEY_FLAGS
which allows the architecture to specify additional bits that it would
like cleared. We use that to ensure that the VM_PKEY_BIT* bits get
cleared.
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Mel Gorman <mgorman@techsingularity.net>
Cc: linux-api@vger.kernel.org
Cc: linux-arch@vger.kernel.org
Cc: linux-mm@kvack.org
Cc: x86@kernel.org
Cc: torvalds@linux-foundation.org
Cc: akpm@linux-foundation.org
Cc: Arnd Bergmann <arnd@arndb.de>
---
b/arch/x86/include/asm/pkeys.h | 2 ++
b/include/linux/pkeys.h | 1 +
b/mm/mprotect.c | 11 ++++++++++-
3 files changed, 13 insertions(+), 1 deletion(-)
diff -puN arch/x86/include/asm/pkeys.h~pkeys-112-mask-off-correct-vm_flags arch/x86/include/asm/pkeys.h
--- a/arch/x86/include/asm/pkeys.h~pkeys-112-mask-off-correct-vm_flags 2016-07-29 09:18:56.818489664 -0700
+++ b/arch/x86/include/asm/pkeys.h 2016-07-29 09:18:56.824489935 -0700
@@ -38,4 +38,6 @@ static inline int arch_override_mprotect
extern int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
unsigned long init_val);
+#define ARCH_VM_PKEY_FLAGS (VM_PKEY_BIT0 | VM_PKEY_BIT1 | VM_PKEY_BIT2 | VM_PKEY_BIT3)
+
#endif /*_ASM_X86_PKEYS_H */
diff -puN include/linux/pkeys.h~pkeys-112-mask-off-correct-vm_flags include/linux/pkeys.h
--- a/include/linux/pkeys.h~pkeys-112-mask-off-correct-vm_flags 2016-07-29 09:18:56.820489755 -0700
+++ b/include/linux/pkeys.h 2016-07-29 09:18:56.825489981 -0700
@@ -16,6 +16,7 @@
#define execute_only_pkey(mm) (0)
#define arch_override_mprotect_pkey(vma, prot, pkey) (0)
#define PKEY_DEDICATED_EXECUTE_ONLY 0
+#define ARCH_VM_PKEY_FLAGS 0
#endif /* ! CONFIG_ARCH_HAS_PKEYS */
#endif /* _LINUX_PKEYS_H */
diff -puN mm/mprotect.c~pkeys-112-mask-off-correct-vm_flags mm/mprotect.c
--- a/mm/mprotect.c~pkeys-112-mask-off-correct-vm_flags 2016-07-29 09:18:56.821489800 -0700
+++ b/mm/mprotect.c 2016-07-29 09:18:56.825489981 -0700
@@ -417,6 +417,7 @@ static int do_mprotect_pkey(unsigned lon
prev = vma;
for (nstart = start ; ; ) {
+ unsigned long mask_off_old_flags;
unsigned long newflags;
int new_vma_pkey;
@@ -426,9 +427,17 @@ static int do_mprotect_pkey(unsigned lon
if (rier && (vma->vm_flags & VM_MAYEXEC))
prot |= PROT_EXEC;
+ /*
+ * Each mprotect() call explicitly passes r/w/x permissions.
+ * If a permission is not passed to mprotect(), it must be
+ * cleared from the VMA.
+ */
+ mask_off_old_flags = VM_READ | VM_WRITE | VM_EXEC |
+ ARCH_VM_PKEY_FLAGS;
+
new_vma_pkey = arch_override_mprotect_pkey(vma, prot, pkey);
newflags = calc_vm_prot_bits(prot, new_vma_pkey);
- newflags |= (vma->vm_flags & ~(VM_READ | VM_WRITE | VM_EXEC));
+ newflags |= (vma->vm_flags & ~mask_off_old_flags);
/* newflags >> 4 shift VM_MAY% in place of VM_% */
if ((newflags & ~(newflags >> 4)) & (VM_READ | VM_WRITE | VM_EXEC)) {
_
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2016-07-29 18:40 +0200 |
| Subject | [PATCH 02/10] mm: implement new pkey_mprotect() system call |
| Message-ID | <s0iZk-763-31@gated-at.bofh.it> |
| In reply to | #1452468 |
From: Dave Hansen <dave.hansen@linux.intel.com>
pkey_mprotect() is just like mprotect, except it also takes a
protection key as an argument. On systems that do not support
protection keys, it still works, but requires that key=0.
Otherwise it does exactly what mprotect does.
I expect it to get used like this, if you want to guarantee that
any mapping you create can *never* be accessed without the right
protection keys set up.
int real_prot = PROT_READ|PROT_WRITE;
pkey = pkey_alloc(0, PKEY_DENY_ACCESS);
ptr = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
ret = pkey_mprotect(ptr, PAGE_SIZE, real_prot, pkey);
This way, there is *no* window where the mapping is accessible
since it was always either PROT_NONE or had a protection key set
that denied all access.
We settled on 'unsigned long' for the type of the key here. We
only need 4 bits on x86 today, but I figured that other
architectures might need some more space.
Semantically, we have a bit of a problem if we combine this
syscall with our previously-introduced execute-only support:
What do we do when we mix execute-only pkey use with
pkey_mprotect() use? For instance:
pkey_mprotect(ptr, PAGE_SIZE, PROT_WRITE, 6); // set pkey=6
mprotect(ptr, PAGE_SIZE, PROT_EXEC); // set pkey=X_ONLY_PKEY?
mprotect(ptr, PAGE_SIZE, PROT_WRITE); // is pkey=6 again?
To solve that, we make the plain-mprotect()-initiated execute-only
support only apply to VMAs that have the default protection key (0)
set on them.
Proposed semantics:
1. protection key 0 is special and represents the default,
"unassigned" protection key. It is always allocated.
2. mprotect() never affects a mapping's pkey_mprotect()-assigned
protection key. A protection key of 0 (even if set explicitly)
represents an unassigned protection key.
2a. mprotect(PROT_EXEC) on a mapping with an assigned protection
key may or may not result in a mapping with execute-only
properties. pkey_mprotect() plus pkey_set() on all threads
should be used to _guarantee_ execute-only semantics if this
is not a strong enough semantic.
3. mprotect(PROT_EXEC) may result in an "execute-only" mapping. The
kernel will internally attempt to allocate and dedicate a
protection key for the purpose of execute-only mappings. This
may not be possible in cases where there are no free protection
keys available. It can also happen, of course, in situations
where there is no hardware support for protection keys.
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Acked-by: Mel Gorman <mgorman@techsingularity.net>
Cc: linux-api@vger.kernel.org
Cc: linux-arch@vger.kernel.org
Cc: linux-mm@kvack.org
Cc: x86@kernel.org
Cc: torvalds@linux-foundation.org
Cc: akpm@linux-foundation.org
Cc: Arnd Bergmann <arnd@arndb.de>
---
b/arch/x86/include/asm/mmu_context.h | 15 ++++++++++-----
b/arch/x86/include/asm/pkeys.h | 11 +++++++++--
b/include/linux/pkeys.h | 12 ------------
b/mm/mprotect.c | 30 ++++++++++++++++++++++++++----
4 files changed, 45 insertions(+), 23 deletions(-)
diff -puN arch/x86/include/asm/mmu_context.h~pkeys-110-syscalls-mprotect_pkey arch/x86/include/asm/mmu_context.h
--- a/arch/x86/include/asm/mmu_context.h~pkeys-110-syscalls-mprotect_pkey 2016-07-29 09:18:56.332467653 -0700
+++ b/arch/x86/include/asm/mmu_context.h 2016-07-29 09:18:56.341468060 -0700
@@ -4,6 +4,7 @@
#include <asm/desc.h>
#include <linux/atomic.h>
#include <linux/mm_types.h>
+#include <linux/pkeys.h>
#include <trace/events/tlb.h>
@@ -195,16 +196,20 @@ static inline void arch_unmap(struct mm_
mpx_notify_unmap(mm, vma, start, end);
}
+#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
static inline int vma_pkey(struct vm_area_struct *vma)
{
- u16 pkey = 0;
-#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
unsigned long vma_pkey_mask = VM_PKEY_BIT0 | VM_PKEY_BIT1 |
VM_PKEY_BIT2 | VM_PKEY_BIT3;
- pkey = (vma->vm_flags & vma_pkey_mask) >> VM_PKEY_SHIFT;
-#endif
- return pkey;
+
+ return (vma->vm_flags & vma_pkey_mask) >> VM_PKEY_SHIFT;
+}
+#else
+static inline int vma_pkey(struct vm_area_struct *vma)
+{
+ return 0;
}
+#endif
static inline bool __pkru_allows_pkey(u16 pkey, bool write)
{
diff -puN arch/x86/include/asm/pkeys.h~pkeys-110-syscalls-mprotect_pkey arch/x86/include/asm/pkeys.h
--- a/arch/x86/include/asm/pkeys.h~pkeys-110-syscalls-mprotect_pkey 2016-07-29 09:18:56.334467743 -0700
+++ b/arch/x86/include/asm/pkeys.h 2016-07-29 09:18:56.342468105 -0700
@@ -1,7 +1,12 @@
#ifndef _ASM_X86_PKEYS_H
#define _ASM_X86_PKEYS_H
-#define arch_max_pkey() (boot_cpu_has(X86_FEATURE_OSPKE) ? 16 : 1)
+#define PKEY_DEDICATED_EXECUTE_ONLY 15
+/*
+ * Consider the PKEY_DEDICATED_EXECUTE_ONLY key unavailable.
+ */
+#define arch_max_pkey() (boot_cpu_has(X86_FEATURE_OSPKE) ? \
+ PKEY_DEDICATED_EXECUTE_ONLY : 1)
extern int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
unsigned long init_val);
@@ -10,7 +15,6 @@ extern int arch_set_user_pkey_access(str
* 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)
{
@@ -31,4 +35,7 @@ static inline int arch_override_mprotect
return __arch_override_mprotect_pkey(vma, prot, pkey);
}
+extern int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
+ unsigned long init_val);
+
#endif /*_ASM_X86_PKEYS_H */
diff -puN include/linux/pkeys.h~pkeys-110-syscalls-mprotect_pkey include/linux/pkeys.h
--- a/include/linux/pkeys.h~pkeys-110-syscalls-mprotect_pkey 2016-07-29 09:18:56.336467834 -0700
+++ b/include/linux/pkeys.h 2016-07-29 09:18:56.342468105 -0700
@@ -18,16 +18,4 @@
#define PKEY_DEDICATED_EXECUTE_ONLY 0
#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/mprotect.c~pkeys-110-syscalls-mprotect_pkey mm/mprotect.c
--- a/mm/mprotect.c~pkeys-110-syscalls-mprotect_pkey 2016-07-29 09:18:56.338467924 -0700
+++ b/mm/mprotect.c 2016-07-29 09:18:56.342468105 -0700
@@ -352,8 +352,11 @@ fail:
return error;
}
-SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,
- unsigned long, prot)
+/*
+ * pkey==-1 when doing a legacy mprotect()
+ */
+static int do_mprotect_pkey(unsigned long start, size_t len,
+ unsigned long prot, int pkey)
{
unsigned long nstart, end, tmp, reqprot;
struct vm_area_struct *vma, *prev;
@@ -361,6 +364,12 @@ SYSCALL_DEFINE3(mprotect, unsigned long,
const int grows = prot & (PROT_GROWSDOWN|PROT_GROWSUP);
const bool rier = (current->personality & READ_IMPLIES_EXEC) &&
(prot & PROT_READ);
+ /*
+ * A temporary safety check since we are not validating
+ * the pkey before we introduce the allocation code.
+ */
+ if (pkey != -1)
+ return -EINVAL;
prot &= ~(PROT_GROWSDOWN|PROT_GROWSUP);
if (grows == (PROT_GROWSDOWN|PROT_GROWSUP)) /* can't be both */
@@ -409,7 +418,7 @@ SYSCALL_DEFINE3(mprotect, unsigned long,
for (nstart = start ; ; ) {
unsigned long newflags;
- int pkey = arch_override_mprotect_pkey(vma, prot, -1);
+ int new_vma_pkey;
/* Here we know that vma->vm_start <= nstart < vma->vm_end. */
@@ -417,7 +426,8 @@ SYSCALL_DEFINE3(mprotect, unsigned long,
if (rier && (vma->vm_flags & VM_MAYEXEC))
prot |= PROT_EXEC;
- newflags = calc_vm_prot_bits(prot, pkey);
+ new_vma_pkey = arch_override_mprotect_pkey(vma, prot, pkey);
+ newflags = calc_vm_prot_bits(prot, new_vma_pkey);
newflags |= (vma->vm_flags & ~(VM_READ | VM_WRITE | VM_EXEC));
/* newflags >> 4 shift VM_MAY% in place of VM_% */
@@ -454,3 +464,15 @@ out:
up_write(¤t->mm->mmap_sem);
return error;
}
+
+SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,
+ unsigned long, prot)
+{
+ return do_mprotect_pkey(start, len, prot, -1);
+}
+
+SYSCALL_DEFINE4(pkey_mprotect, unsigned long, start, size_t, len,
+ unsigned long, prot, int, pkey)
+{
+ return do_mprotect_pkey(start, len, prot, pkey);
+}
_
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web