aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorPiotr Kwapulinski <kwapulinski.piotr@gmail.com>2016-03-22 17:27:51 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-03-22 18:36:02 -0400
commitf138556daf62665f19178732ec4daf86c4ca13f4 (patch)
tree6e873ed98d9cae5c202e75847224d66147f110dd /mm
parenta5f4db877177d2a3d7ae62a7bac3a5a27e083d7f (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.c13
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(&current->mm->mmap_sem); 382 down_write(&current->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 }
449out: 452out:
450 up_write(&current->mm->mmap_sem); 453 up_write(&current->mm->mmap_sem);