aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-10-10 14:01:51 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-10-10 14:01:51 -0400
commit93c26d7dc02380fe11e57ff0d152368743762169 (patch)
tree5234bc86561c6b8c7fd698a2d456add3c960db1f /mm
parent5fa0eb0b4d4780fbd6d8a09850cc4fd539e9fe65 (diff)
parent6679dac513fd612f34d3a3d99d7b84ed6d5eb5cc (diff)
Merge branch 'mm-pkeys-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull protection keys syscall interface from Thomas Gleixner: "This is the final step of Protection Keys support which adds the syscalls so user space can actually allocate keys and protect memory areas with them. Details and usage examples can be found in the documentation. The mm side of this has been acked by Mel" * 'mm-pkeys-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/pkeys: Update documentation x86/mm/pkeys: Do not skip PKRU register if debug registers are not used x86/pkeys: Fix pkeys build breakage for some non-x86 arches x86/pkeys: Add self-tests x86/pkeys: Allow configuration of init_pkru x86/pkeys: Default to a restrictive init PKRU pkeys: Add details of system call use to Documentation/ generic syscalls: Wire up memory protection keys syscalls x86: Wire up protection keys system calls x86/pkeys: Allocation/free syscalls x86/pkeys: Make mprotect_key() mask off additional vm_flags mm: Implement new pkey_mprotect() system call x86/pkeys: Add fault handling for PF_PK page fault bit
Diffstat (limited to 'mm')
-rw-r--r--mm/mprotect.c90
1 files changed, 85 insertions, 5 deletions
diff --git a/mm/mprotect.c b/mm/mprotect.c
index ec91dfd3f900..bcdbe62f3e6d 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -23,11 +23,13 @@
23#include <linux/mmu_notifier.h> 23#include <linux/mmu_notifier.h>
24#include <linux/migrate.h> 24#include <linux/migrate.h>
25#include <linux/perf_event.h> 25#include <linux/perf_event.h>
26#include <linux/pkeys.h>
26#include <linux/ksm.h> 27#include <linux/ksm.h>
27#include <linux/pkeys.h> 28#include <linux/pkeys.h>
28#include <asm/uaccess.h> 29#include <asm/uaccess.h>
29#include <asm/pgtable.h> 30#include <asm/pgtable.h>
30#include <asm/cacheflush.h> 31#include <asm/cacheflush.h>
32#include <asm/mmu_context.h>
31#include <asm/tlbflush.h> 33#include <asm/tlbflush.h>
32 34
33#include "internal.h" 35#include "internal.h"
@@ -353,8 +355,11 @@ fail:
353 return error; 355 return error;
354} 356}
355 357
356SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len, 358/*
357 unsigned long, prot) 359 * pkey==-1 when doing a legacy mprotect()
360 */
361static int do_mprotect_pkey(unsigned long start, size_t len,
362 unsigned long prot, int pkey)
358{ 363{
359 unsigned long nstart, end, tmp, reqprot; 364 unsigned long nstart, end, tmp, reqprot;
360 struct vm_area_struct *vma, *prev; 365 struct vm_area_struct *vma, *prev;
@@ -383,6 +388,14 @@ SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,
383 if (down_write_killable(&current->mm->mmap_sem)) 388 if (down_write_killable(&current->mm->mmap_sem))
384 return -EINTR; 389 return -EINTR;
385 390
391 /*
392 * If userspace did not allocate the pkey, do not let
393 * them use it here.
394 */
395 error = -EINVAL;
396 if ((pkey != -1) && !mm_pkey_is_allocated(current->mm, pkey))
397 goto out;
398
386 vma = find_vma(current->mm, start); 399 vma = find_vma(current->mm, start);
387 error = -ENOMEM; 400 error = -ENOMEM;
388 if (!vma) 401 if (!vma)
@@ -409,8 +422,9 @@ SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,
409 prev = vma; 422 prev = vma;
410 423
411 for (nstart = start ; ; ) { 424 for (nstart = start ; ; ) {
425 unsigned long mask_off_old_flags;
412 unsigned long newflags; 426 unsigned long newflags;
413 int pkey = arch_override_mprotect_pkey(vma, prot, -1); 427 int new_vma_pkey;
414 428
415 /* Here we know that vma->vm_start <= nstart < vma->vm_end. */ 429 /* Here we know that vma->vm_start <= nstart < vma->vm_end. */
416 430
@@ -418,8 +432,17 @@ SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,
418 if (rier && (vma->vm_flags & VM_MAYEXEC)) 432 if (rier && (vma->vm_flags & VM_MAYEXEC))
419 prot |= PROT_EXEC; 433 prot |= PROT_EXEC;
420 434
421 newflags = calc_vm_prot_bits(prot, pkey); 435 /*
422 newflags |= (vma->vm_flags & ~(VM_READ | VM_WRITE | VM_EXEC)); 436 * Each mprotect() call explicitly passes r/w/x permissions.
437 * If a permission is not passed to mprotect(), it must be
438 * cleared from the VMA.
439 */
440 mask_off_old_flags = VM_READ | VM_WRITE | VM_EXEC |
441 ARCH_VM_PKEY_FLAGS;
442
443 new_vma_pkey = arch_override_mprotect_pkey(vma, prot, pkey);
444 newflags = calc_vm_prot_bits(prot, new_vma_pkey);
445 newflags |= (vma->vm_flags & ~mask_off_old_flags);
423 446
424 /* newflags >> 4 shift VM_MAY% in place of VM_% */ 447 /* newflags >> 4 shift VM_MAY% in place of VM_% */
425 if ((newflags & ~(newflags >> 4)) & (VM_READ | VM_WRITE | VM_EXEC)) { 448 if ((newflags & ~(newflags >> 4)) & (VM_READ | VM_WRITE | VM_EXEC)) {
@@ -455,3 +478,60 @@ out:
455 up_write(&current->mm->mmap_sem); 478 up_write(&current->mm->mmap_sem);
456 return error; 479 return error;
457} 480}
481
482SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,
483 unsigned long, prot)
484{
485 return do_mprotect_pkey(start, len, prot, -1);
486}
487
488SYSCALL_DEFINE4(pkey_mprotect, unsigned long, start, size_t, len,
489 unsigned long, prot, int, pkey)
490{
491 return do_mprotect_pkey(start, len, prot, pkey);
492}
493
494SYSCALL_DEFINE2(pkey_alloc, unsigned long, flags, unsigned long, init_val)
495{
496 int pkey;
497 int ret;
498
499 /* No flags supported yet. */
500 if (flags)
501 return -EINVAL;
502 /* check for unsupported init values */
503 if (init_val & ~PKEY_ACCESS_MASK)
504 return -EINVAL;
505
506 down_write(&current->mm->mmap_sem);
507 pkey = mm_pkey_alloc(current->mm);
508
509 ret = -ENOSPC;
510 if (pkey == -1)
511 goto out;
512
513 ret = arch_set_user_pkey_access(current, pkey, init_val);
514 if (ret) {
515 mm_pkey_free(current->mm, pkey);
516 goto out;
517 }
518 ret = pkey;
519out:
520 up_write(&current->mm->mmap_sem);
521 return ret;
522}
523
524SYSCALL_DEFINE1(pkey_free, int, pkey)
525{
526 int ret;
527
528 down_write(&current->mm->mmap_sem);
529 ret = mm_pkey_free(current->mm, pkey);
530 up_write(&current->mm->mmap_sem);
531
532 /*
533 * We could provie warnings or errors if any VMA still
534 * has the pkey set here.
535 */
536 return ret;
537}