]> git.hungrycats.org Git - linux/commitdiff
[PATCH] PROT_GROWSDOWN/PROT_GROWSUP flags for mprotect
authorRoland McGrath <roland@redhat.com>
Thu, 25 Sep 2003 01:15:39 +0000 (18:15 -0700)
committerLinus Torvalds <torvalds@home.osdl.org>
Thu, 25 Sep 2003 01:15:39 +0000 (18:15 -0700)
There is currently no clean and efficient way to apply mprotect to all of a
program's stack, i.e. to the moving edge of a GROWSDOWN or GROWSUP mapping.
Some processes want to change these protections, particularly to set or
clear the PROT_EXEC bits on stack space.  As it is, an mprotect done to
cover the precise edge page of the mapping will have the desired effect of
changing the protection for existing pages and having that new protection
carried over to new pages grown later.  But there is no very reasonable way
of ascertaining where the edge of the mapping is if it might have grown in
the past beyond the usage at the moment.  An mprotect call that doesn't
cover the edge page splits the mapping and doesn't do what we need.

This patch adds flags that can be OR'd into the protection bits in an
mprotect system call.  PROT_GROWSDOWN means the memory lies in a GROWSDOWN
mapping and the start address of the region to be changed should be
extended down to the current low page of that mapping.  Similarly,
PROT_GROWSUP means the pages lie in a GROWSUP mapping and the length of the
region to be changed should be extended up to include its highest page.
These flags also explicitly request the (already implicit) behavior that
the protection change applied to the lowest/highest page of a growing
mapping is passed on to new pages grown later.  There are no other changes
to the mprotect behavior; in particular, the boundary in the non-growing
direction (the end address computed from the start+len arguments in the
GROWSDOWN case, and the start argument in the GROWSUP case) is as given by
the arguments to the system call.  This is desireable in the use of this
call by a process on its stack, so it can change the protections of the
growing mapping used for program stack distinctly from the protections on
the arguments, environment, and AT_* data from exec.

19 files changed:
include/asm-alpha/mman.h
include/asm-arm/mman.h
include/asm-arm26/mman.h
include/asm-cris/mman.h
include/asm-h8300/mman.h
include/asm-i386/mman.h
include/asm-ia64/mman.h
include/asm-m68k/mman.h
include/asm-mips/mman.h
include/asm-parisc/mman.h
include/asm-ppc/mman.h
include/asm-ppc64/mman.h
include/asm-s390/mman.h
include/asm-sh/mman.h
include/asm-sparc/mman.h
include/asm-sparc64/mman.h
include/asm-v850/mman.h
include/asm-x86_64/mman.h
mm/mprotect.c

index caa92997d4feb35ff4cddddd59d555b9ac413e25..eb9c279045efe07573e308c5715eb7458c4e91df 100644 (file)
@@ -6,6 +6,8 @@
 #define PROT_EXEC      0x4             /* page can be executed */
 #define PROT_SEM       0x8             /* page may be used for atomic ops */
 #define PROT_NONE      0x0             /* page can not be accessed */
+#define PROT_GROWSDOWN 0x01000000      /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP   0x02000000      /* mprotect flag: extend change to end of growsup vma */
 
 #define MAP_SHARED     0x01            /* Share changes */
 #define MAP_PRIVATE    0x02            /* Changes are private */
index 044a5ef62548e948aa4766ba2d36dc5338e4ee70..8e4f69c4fa5faa845479b68e4e3159374576f5f1 100644 (file)
@@ -6,6 +6,8 @@
 #define PROT_EXEC      0x4             /* page can be executed */
 #define PROT_SEM       0x8             /* page may be used for atomic ops */
 #define PROT_NONE      0x0             /* page can not be accessed */
+#define PROT_GROWSDOWN 0x01000000      /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP   0x02000000      /* mprotect flag: extend change to end of growsup vma */
 
 #define MAP_SHARED     0x01            /* Share changes */
 #define MAP_PRIVATE    0x02            /* Changes are private */
index 521e2ffc0929eabbf021e9350ab8ff3fedbcd0c4..cc27b824026564af2b61d9373923b9d6bebbd709 100644 (file)
@@ -6,6 +6,8 @@
 #define PROT_EXEC      0x4             /* page can be executed */
 #define PROT_SEM       0x8             /* page may be used for atomic ops */
 #define PROT_NONE      0x0             /* page can not be accessed */
+#define PROT_GROWSDOWN 0x01000000      /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP   0x02000000      /* mprotect flag: extend change to end of growsup vma */
 
 #define MAP_SHARED     0x01            /* Share changes */
 #define MAP_PRIVATE    0x02            /* Changes are private */
index 4de58ad6efa16477b01b7e75c2462be48f8d85ad..8570e72b9502cd73d560785ba9acdb9b8525db4f 100644 (file)
@@ -8,6 +8,8 @@
 #define PROT_EXEC      0x4             /* page can be executed */
 #define PROT_SEM       0x8             /* page may be used for atomic ops */
 #define PROT_NONE      0x0             /* page can not be accessed */
+#define PROT_GROWSDOWN 0x01000000      /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP   0x02000000      /* mprotect flag: extend change to end of growsup vma */
 
 #define MAP_SHARED     0x01            /* Share changes */
 #define MAP_PRIVATE    0x02            /* Changes are private */
index 5c3fc5898bccdc9e06eea55f82ebaecd01457451..abe08856c84fdc86e58a495c37c42cb4d9eb5227 100644 (file)
@@ -5,6 +5,8 @@
 #define PROT_WRITE     0x2             /* page can be written */
 #define PROT_EXEC      0x4             /* page can be executed */
 #define PROT_NONE      0x0             /* page can not be accessed */
+#define PROT_GROWSDOWN 0x01000000      /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP   0x02000000      /* mprotect flag: extend change to end of growsup vma */
 
 #define MAP_SHARED     0x01            /* Share changes */
 #define MAP_PRIVATE    0x02            /* Changes are private */
index 348090b360781f4a8fc521d37781f8b6d7546b3b..6a80c93c7e5a996a745b836c58b543f34503efda 100644 (file)
@@ -6,6 +6,10 @@
 #define PROT_EXEC      0x4             /* page can be executed */
 #define PROT_SEM       0x8             /* page may be used for atomic ops */
 #define PROT_NONE      0x0             /* page can not be accessed */
+#define PROT_GROWSDOWN 0x01000000      /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP   0x02000000      /* mprotect flag: extend change to end of growsup vma */
+#define PROT_GROWSDOWN 0x01000000      /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP   0x02000000      /* mprotect flag: extend change to end of growsup vma */
 
 #define MAP_SHARED     0x01            /* Share changes */
 #define MAP_PRIVATE    0x02            /* Changes are private */
index 698871eeff2d3874a3ab03306a3e45b5534f3e95..6de0f91d46ae0dbf435472bbd826828b862b305f 100644 (file)
@@ -11,6 +11,8 @@
 #define PROT_EXEC      0x4             /* page can be executed */
 #define PROT_SEM       0x8             /* page may be used for atomic ops */
 #define PROT_NONE      0x0             /* page can not be accessed */
+#define PROT_GROWSDOWN 0x01000000      /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP   0x02000000      /* mprotect flag: extend change to end of growsup vma */
 
 #define MAP_SHARED     0x01            /* Share changes */
 #define MAP_PRIVATE    0x02            /* Changes are private */
index 59c2d3c265d1acf300fb87d23992fa63d840ed06..f831c4eeae6e0fd05c0cdd3552615cad83a1736c 100644 (file)
@@ -6,6 +6,8 @@
 #define PROT_EXEC      0x4             /* page can be executed */
 #define PROT_SEM       0x8             /* page may be used for atomic ops */
 #define PROT_NONE      0x0             /* page can not be accessed */
+#define PROT_GROWSDOWN 0x01000000      /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP   0x02000000      /* mprotect flag: extend change to end of growsup vma */
 
 #define MAP_SHARED     0x01            /* Share changes */
 #define MAP_PRIVATE    0x02            /* Changes are private */
index 54b7fb1cb8f3c827b4aef9089c7a3172bc9923e7..62060957ba93a743d8b8ceaa11b11f2706ffb578 100644 (file)
@@ -20,6 +20,8 @@
 #define PROT_EXEC      0x04            /* page can be executed */
 /*                     0x08               reserved for PROT_EXEC_NOFLUSH */
 #define PROT_SEM       0x10            /* page may be used for atomic ops */
+#define PROT_GROWSDOWN 0x01000000      /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP   0x02000000      /* mprotect flag: extend change to end of growsup vma */
 
 /*
  * Flags for mmap
index b5c3bd6ced729b56dc15e7f963e2891841bd8aae..e829607eb8bc2a4d2e77c48bc93362cc311ddeee 100644 (file)
@@ -6,6 +6,8 @@
 #define PROT_EXEC      0x4             /* page can be executed */
 #define PROT_SEM       0x8             /* page may be used for atomic ops */
 #define PROT_NONE      0x0             /* page can not be accessed */
+#define PROT_GROWSDOWN 0x01000000      /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP   0x02000000      /* mprotect flag: extend change to end of growsup vma */
 
 #define MAP_SHARED     0x01            /* Share changes */
 #define MAP_PRIVATE    0x02            /* Changes are private */
index 14f8ab333442c177a2d9eb05fc16db127c03200b..5fd19fd4936c90490af91ae2d766440778abf9eb 100644 (file)
@@ -6,6 +6,8 @@
 #define PROT_EXEC      0x4             /* page can be executed */
 #define PROT_SEM       0x8             /* page may be used for atomic ops */
 #define PROT_NONE      0x0             /* page can not be accessed */
+#define PROT_GROWSDOWN 0x01000000      /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP   0x02000000      /* mprotect flag: extend change to end of growsup vma */
 
 #define MAP_SHARED     0x01            /* Share changes */
 #define MAP_PRIVATE    0x02            /* Changes are private */
index 57c185aab25a0d159d0fa128a21a285449294512..d4f93446a52c75e8278c8b7faf7920493f693801 100644 (file)
@@ -13,6 +13,8 @@
 #define PROT_EXEC      0x4             /* page can be executed */
 #define PROT_SEM       0x8             /* page may be used for atomic ops */
 #define PROT_NONE      0x0             /* page can not be accessed */
+#define PROT_GROWSDOWN 0x01000000      /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP   0x02000000      /* mprotect flag: extend change to end of growsup vma */
 
 #define MAP_SHARED     0x01            /* Share changes */
 #define MAP_PRIVATE    0x02            /* Changes are private */
index b90e013966176f8b96f93fdcb72ad996c59b423c..ea86bd12204fe55032fe1418ed62924b606bda29 100644 (file)
@@ -14,6 +14,8 @@
 #define PROT_EXEC      0x4             /* page can be executed */
 #define PROT_SEM       0x8             /* page may be used for atomic ops */
 #define PROT_NONE      0x0             /* page can not be accessed */
+#define PROT_GROWSDOWN 0x01000000      /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP   0x02000000      /* mprotect flag: extend change to end of growsup vma */
 
 #define MAP_SHARED     0x01            /* Share changes */
 #define MAP_PRIVATE    0x02            /* Changes are private */
index 7846d31bb647389fb7eb4d7a6cdbbbedd51362dc..3ebab5f79db794d34afa60a62ce8ec9a462a49c4 100644 (file)
@@ -6,6 +6,8 @@
 #define PROT_EXEC      0x4             /* page can be executed */
 #define PROT_SEM       0x8             /* page may be used for atomic ops */
 #define PROT_NONE      0x0             /* page can not be accessed */
+#define PROT_GROWSDOWN 0x01000000      /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP   0x02000000      /* mprotect flag: extend change to end of growsup vma */
 
 #define MAP_SHARED     0x01            /* Share changes */
 #define MAP_PRIVATE    0x02            /* Changes are private */
index 7fc6075d358e18fc9c657c8f5110e5dc51ac0ad3..138eb81dd70d3fd5a1c0a9f2b1e266049e960d47 100644 (file)
@@ -9,6 +9,8 @@
 #define PROT_EXEC      0x4             /* page can be executed */
 #define PROT_SEM       0x8             /* page may be used for atomic ops */
 #define PROT_NONE      0x0             /* page can not be accessed */
+#define PROT_GROWSDOWN 0x01000000      /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP   0x02000000      /* mprotect flag: extend change to end of growsup vma */
 
 #define MAP_SHARED     0x01            /* Share changes */
 #define MAP_PRIVATE    0x02            /* Changes are private */
index f5980a152936cb46f4961e1fd2123c35ec5b7fa9..01cecf54357b876d3fe5d8f31c33ac181a8bb670 100644 (file)
@@ -9,6 +9,8 @@
 #define PROT_EXEC      0x4             /* page can be executed */
 #define PROT_SEM       0x8             /* page may be used for atomic ops */
 #define PROT_NONE      0x0             /* page can not be accessed */
+#define PROT_GROWSDOWN 0x01000000      /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP   0x02000000      /* mprotect flag: extend change to end of growsup vma */
 
 #define MAP_SHARED     0x01            /* Share changes */
 #define MAP_PRIVATE    0x02            /* Changes are private */
index 441b8716dbf4b42bba49980d692760e4be229793..e2b90081b56f8ca2d7b3f9dc6a6012b249ee9add 100644 (file)
@@ -5,6 +5,8 @@
 #define PROT_WRITE     0x2             /* page can be written */
 #define PROT_EXEC      0x4             /* page can be executed */
 #define PROT_NONE      0x0             /* page can not be accessed */
+#define PROT_GROWSDOWN 0x01000000      /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP   0x02000000      /* mprotect flag: extend change to end of growsup vma */
 
 #define MAP_SHARED     0x01            /* Share changes */
 #define MAP_PRIVATE    0x02            /* Changes are private */
index 41b02d502b8378bfda1952b69824a13b3df0d211..78e60a4fd4ee543c58ba359f9488bddcc95741f4 100644 (file)
@@ -6,6 +6,8 @@
 #define PROT_EXEC      0x4             /* page can be executed */
 #define PROT_NONE      0x0             /* page can not be accessed */
 #define PROT_SEM       0x8
+#define PROT_GROWSDOWN 0x01000000      /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP   0x02000000      /* mprotect flag: extend change to end of growsup vma */
 
 #define MAP_SHARED     0x01            /* Share changes */
 #define MAP_PRIVATE    0x02            /* Changes are private */
index 699962ebd1e48cf047ffdf7221605be05ed1eb97..31b27771a74c68accd23d95423cbc485bab252fd 100644 (file)
@@ -227,6 +227,10 @@ sys_mprotect(unsigned long start, size_t len, unsigned long prot)
        unsigned long vm_flags, nstart, end, tmp;
        struct vm_area_struct * vma, * next, * prev;
        int error = -EINVAL;
+       const int grows = prot & (PROT_GROWSDOWN|PROT_GROWSUP);
+       prot &= ~(PROT_GROWSDOWN|PROT_GROWSUP);
+       if (grows == (PROT_GROWSDOWN|PROT_GROWSUP)) /* can't be both */
+               return -EINVAL;
 
        if (start & ~PAGE_MASK)
                return -EINVAL;
@@ -245,8 +249,26 @@ sys_mprotect(unsigned long start, size_t len, unsigned long prot)
 
        vma = find_vma_prev(current->mm, start, &prev);
        error = -ENOMEM;
-       if (!vma || vma->vm_start > start)
+       if (!vma)
                goto out;
+       if (unlikely(grows & PROT_GROWSDOWN)) {
+               if (vma->vm_start >= end)
+                       goto out;
+               start = vma->vm_start;
+               error = -EINVAL;
+               if (!(vma->vm_flags & VM_GROWSDOWN))
+                       goto out;
+       }
+       else {
+               if (vma->vm_start > start)
+                       goto out;
+               if (unlikely(grows & PROT_GROWSUP)) {
+                       end = vma->vm_end;
+                       error = -EINVAL;
+                       if (!(vma->vm_flags & VM_GROWSUP))
+                               goto out;
+               }
+       }
 
        for (nstart = start ; ; ) {
                unsigned int newflags;