From c1dd59582e5b518983b0f4db66f0f8a969139c1b Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Wed, 24 Sep 2003 18:15:39 -0700 Subject: [PATCH] [PATCH] PROT_GROWSDOWN/PROT_GROWSUP flags for mprotect 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. --- include/asm-alpha/mman.h | 2 ++ include/asm-arm/mman.h | 2 ++ include/asm-arm26/mman.h | 2 ++ include/asm-cris/mman.h | 2 ++ include/asm-h8300/mman.h | 2 ++ include/asm-i386/mman.h | 4 ++++ include/asm-ia64/mman.h | 2 ++ include/asm-m68k/mman.h | 2 ++ include/asm-mips/mman.h | 2 ++ include/asm-parisc/mman.h | 2 ++ include/asm-ppc/mman.h | 2 ++ include/asm-ppc64/mman.h | 2 ++ include/asm-s390/mman.h | 2 ++ include/asm-sh/mman.h | 2 ++ include/asm-sparc/mman.h | 2 ++ include/asm-sparc64/mman.h | 2 ++ include/asm-v850/mman.h | 2 ++ include/asm-x86_64/mman.h | 2 ++ mm/mprotect.c | 24 +++++++++++++++++++++++- 19 files changed, 61 insertions(+), 1 deletion(-) diff --git a/include/asm-alpha/mman.h b/include/asm-alpha/mman.h index caa92997d4feb..eb9c279045efe 100644 --- a/include/asm-alpha/mman.h +++ b/include/asm-alpha/mman.h @@ -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 */ diff --git a/include/asm-arm/mman.h b/include/asm-arm/mman.h index 044a5ef62548e..8e4f69c4fa5fa 100644 --- a/include/asm-arm/mman.h +++ b/include/asm-arm/mman.h @@ -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 */ diff --git a/include/asm-arm26/mman.h b/include/asm-arm26/mman.h index 521e2ffc0929e..cc27b82402656 100644 --- a/include/asm-arm26/mman.h +++ b/include/asm-arm26/mman.h @@ -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 */ diff --git a/include/asm-cris/mman.h b/include/asm-cris/mman.h index 4de58ad6efa16..8570e72b9502c 100644 --- a/include/asm-cris/mman.h +++ b/include/asm-cris/mman.h @@ -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 */ diff --git a/include/asm-h8300/mman.h b/include/asm-h8300/mman.h index 5c3fc5898bccd..abe08856c84fd 100644 --- a/include/asm-h8300/mman.h +++ b/include/asm-h8300/mman.h @@ -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 */ diff --git a/include/asm-i386/mman.h b/include/asm-i386/mman.h index 348090b360781..6a80c93c7e5a9 100644 --- a/include/asm-i386/mman.h +++ b/include/asm-i386/mman.h @@ -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 */ diff --git a/include/asm-ia64/mman.h b/include/asm-ia64/mman.h index 698871eeff2d3..6de0f91d46ae0 100644 --- a/include/asm-ia64/mman.h +++ b/include/asm-ia64/mman.h @@ -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 */ diff --git a/include/asm-m68k/mman.h b/include/asm-m68k/mman.h index 59c2d3c265d1a..f831c4eeae6e0 100644 --- a/include/asm-m68k/mman.h +++ b/include/asm-m68k/mman.h @@ -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 */ diff --git a/include/asm-mips/mman.h b/include/asm-mips/mman.h index 54b7fb1cb8f3c..62060957ba93a 100644 --- a/include/asm-mips/mman.h +++ b/include/asm-mips/mman.h @@ -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 diff --git a/include/asm-parisc/mman.h b/include/asm-parisc/mman.h index b5c3bd6ced729..e829607eb8bc2 100644 --- a/include/asm-parisc/mman.h +++ b/include/asm-parisc/mman.h @@ -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 */ diff --git a/include/asm-ppc/mman.h b/include/asm-ppc/mman.h index 14f8ab333442c..5fd19fd4936c9 100644 --- a/include/asm-ppc/mman.h +++ b/include/asm-ppc/mman.h @@ -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 */ diff --git a/include/asm-ppc64/mman.h b/include/asm-ppc64/mman.h index 57c185aab25a0..d4f93446a52c7 100644 --- a/include/asm-ppc64/mman.h +++ b/include/asm-ppc64/mman.h @@ -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 */ diff --git a/include/asm-s390/mman.h b/include/asm-s390/mman.h index b90e013966176..ea86bd12204fe 100644 --- a/include/asm-s390/mman.h +++ b/include/asm-s390/mman.h @@ -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 */ diff --git a/include/asm-sh/mman.h b/include/asm-sh/mman.h index 7846d31bb6473..3ebab5f79db79 100644 --- a/include/asm-sh/mman.h +++ b/include/asm-sh/mman.h @@ -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 */ diff --git a/include/asm-sparc/mman.h b/include/asm-sparc/mman.h index 7fc6075d358e1..138eb81dd70d3 100644 --- a/include/asm-sparc/mman.h +++ b/include/asm-sparc/mman.h @@ -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 */ diff --git a/include/asm-sparc64/mman.h b/include/asm-sparc64/mman.h index f5980a152936c..01cecf54357b8 100644 --- a/include/asm-sparc64/mman.h +++ b/include/asm-sparc64/mman.h @@ -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 */ diff --git a/include/asm-v850/mman.h b/include/asm-v850/mman.h index 441b8716dbf4b..e2b90081b56f8 100644 --- a/include/asm-v850/mman.h +++ b/include/asm-v850/mman.h @@ -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 */ diff --git a/include/asm-x86_64/mman.h b/include/asm-x86_64/mman.h index 41b02d502b837..78e60a4fd4ee5 100644 --- a/include/asm-x86_64/mman.h +++ b/include/asm-x86_64/mman.h @@ -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 */ diff --git a/mm/mprotect.c b/mm/mprotect.c index 699962ebd1e48..31b27771a74c6 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -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; -- 2.53.0