diff options
author | Piotr Kwapulinski <kwapulinski.piotr@gmail.com> | 2016-03-22 17:27:51 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-03-22 18:36:02 -0400 |
commit | f138556daf62665f19178732ec4daf86c4ca13f4 (patch) | |
tree | 6e873ed98d9cae5c202e75847224d66147f110dd /mm | |
parent | a5f4db877177d2a3d7ae62a7bac3a5a27e083d7f (diff) |
mm/mprotect.c: don't imply PROT_EXEC on non-exec fs
The mprotect(PROT_READ) fails when called by the READ_IMPLIES_EXEC
binary on a memory mapped file located on non-exec fs. The mprotect
does not check whether fs is _executable_ or not. The PROT_EXEC flag is
set automatically even if a memory mapped file is located on non-exec
fs. Fix it by checking whether a memory mapped file is located on a
non-exec fs. If so the PROT_EXEC is not implied by the PROT_READ. The
implementation uses the VM_MAYEXEC flag set properly in mmap. Now it is
consistent with mmap.
I did the isolated tests (PT_GNU_STACK X/NX, multiple VMAs, X/NX fs). I
also patched the official 3.19.0-47-generic Ubuntu 14.04 kernel and it
seems to work.
Signed-off-by: Piotr Kwapulinski <kwapulinski.piotr@gmail.com>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Konstantin Khlebnikov <koct9i@gmail.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/mprotect.c | 13 |
1 files changed, 8 insertions, 5 deletions
diff --git a/mm/mprotect.c b/mm/mprotect.c index fa37c4cd973a..b650c5412f58 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c | |||
@@ -359,6 +359,9 @@ SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len, | |||
359 | struct vm_area_struct *vma, *prev; | 359 | struct vm_area_struct *vma, *prev; |
360 | int error = -EINVAL; | 360 | int error = -EINVAL; |
361 | const int grows = prot & (PROT_GROWSDOWN|PROT_GROWSUP); | 361 | const int grows = prot & (PROT_GROWSDOWN|PROT_GROWSUP); |
362 | const bool rier = (current->personality & READ_IMPLIES_EXEC) && | ||
363 | (prot & PROT_READ); | ||
364 | |||
362 | prot &= ~(PROT_GROWSDOWN|PROT_GROWSUP); | 365 | prot &= ~(PROT_GROWSDOWN|PROT_GROWSUP); |
363 | if (grows == (PROT_GROWSDOWN|PROT_GROWSUP)) /* can't be both */ | 366 | if (grows == (PROT_GROWSDOWN|PROT_GROWSUP)) /* can't be both */ |
364 | return -EINVAL; | 367 | return -EINVAL; |
@@ -375,11 +378,6 @@ SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len, | |||
375 | return -EINVAL; | 378 | return -EINVAL; |
376 | 379 | ||
377 | reqprot = prot; | 380 | reqprot = prot; |
378 | /* | ||
379 | * Does the application expect PROT_READ to imply PROT_EXEC: | ||
380 | */ | ||
381 | if ((prot & PROT_READ) && (current->personality & READ_IMPLIES_EXEC)) | ||
382 | prot |= PROT_EXEC; | ||
383 | 381 | ||
384 | down_write(¤t->mm->mmap_sem); | 382 | down_write(¤t->mm->mmap_sem); |
385 | 383 | ||
@@ -414,6 +412,10 @@ SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len, | |||
414 | 412 | ||
415 | /* Here we know that vma->vm_start <= nstart < vma->vm_end. */ | 413 | /* Here we know that vma->vm_start <= nstart < vma->vm_end. */ |
416 | 414 | ||
415 | /* Does the application expect PROT_READ to imply PROT_EXEC */ | ||
416 | if (rier && (vma->vm_flags & VM_MAYEXEC)) | ||
417 | prot |= PROT_EXEC; | ||
418 | |||
417 | newflags = calc_vm_prot_bits(prot, pkey); | 419 | newflags = calc_vm_prot_bits(prot, pkey); |
418 | newflags |= (vma->vm_flags & ~(VM_READ | VM_WRITE | VM_EXEC)); | 420 | newflags |= (vma->vm_flags & ~(VM_READ | VM_WRITE | VM_EXEC)); |
419 | 421 | ||
@@ -445,6 +447,7 @@ SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len, | |||
445 | error = -ENOMEM; | 447 | error = -ENOMEM; |
446 | goto out; | 448 | goto out; |
447 | } | 449 | } |
450 | prot = reqprot; | ||
448 | } | 451 | } |
449 | out: | 452 | out: |
450 | up_write(¤t->mm->mmap_sem); | 453 | up_write(¤t->mm->mmap_sem); |