Handle the PROT_GROWSDOWN and PROT_GROWSUP mprotect flags properly
which stops glibc falling over when a program requires an executable
stack and glibc has been built to assume that PROT_GROWSDOWN will work.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@5041 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/m_syswrap/syswrap-generic.c b/coregrind/m_syswrap/syswrap-generic.c
index 4c2bd7b..0b5e10b 100644
--- a/coregrind/m_syswrap/syswrap-generic.c
+++ b/coregrind/m_syswrap/syswrap-generic.c
@@ -4552,8 +4552,43 @@
PRE_REG_READ3(long, "mprotect",
unsigned long, addr, vki_size_t, len, unsigned long, prot);
- if (!ML_(valid_client_addr)(ARG1, ARG2, tid, "mprotect"))
+ if (!ML_(valid_client_addr)(ARG1, ARG2, tid, "mprotect")) {
SET_STATUS_Failure( VKI_ENOMEM );
+ } else if (ARG3 & (VKI_PROT_GROWSDOWN|VKI_PROT_GROWSUP)) {
+ UInt grows = ARG3 & (VKI_PROT_GROWSDOWN|VKI_PROT_GROWSUP);
+ NSegment *aseg = VG_(am_find_nsegment)(ARG1);
+ NSegment *rseg;
+
+ vg_assert(aseg);
+
+ if (grows == VKI_PROT_GROWSDOWN) {
+ rseg = VG_(am_next_nsegment)( aseg, False/*backwards*/ );
+ if (rseg &&
+ rseg->kind == SkResvn &&
+ rseg->smode == SmUpper &&
+ rseg->end+1 == aseg->start) {
+ Addr end = ARG1 + ARG2;
+ ARG1 = aseg->start;
+ ARG2 = end - aseg->start;
+ ARG3 &= ~VKI_PROT_GROWSDOWN;
+ } else {
+ SET_STATUS_Failure( VKI_EINVAL );
+ }
+ } else if (grows == VKI_PROT_GROWSUP) {
+ rseg = VG_(am_next_nsegment)( aseg, True/*forwards*/ );
+ if (rseg &&
+ rseg->kind == SkResvn &&
+ rseg->smode == SmLower &&
+ aseg->end+1 == rseg->start) {
+ ARG2 = aseg->end - ARG1 + 1;
+ ARG3 &= ~VKI_PROT_GROWSUP;
+ } else {
+ SET_STATUS_Failure( VKI_EINVAL );
+ }
+ } else {
+ SET_STATUS_Failure( VKI_EINVAL );
+ }
+ }
}
POST(sys_mprotect)
diff --git a/include/vki-amd64-linux.h b/include/vki-amd64-linux.h
index e4277ad..79f96a4 100644
--- a/include/vki-amd64-linux.h
+++ b/include/vki-amd64-linux.h
@@ -216,6 +216,8 @@
#define VKI_PROT_WRITE 0x2 /* page can be written */
#define VKI_PROT_EXEC 0x4 /* page can be executed */
#define VKI_PROT_NONE 0x0 /* page can not be accessed */
+#define VKI_PROT_GROWSDOWN 0x01000000 /* mprotect flag: extend change to start of growsdown vma */
+#define VKI_PROT_GROWSUP 0x02000000 /* mprotect flag: extend change to end of growsup vma */
#define VKI_MAP_SHARED 0x01 /* Share changes */
#define VKI_MAP_PRIVATE 0x02 /* Changes are private */
diff --git a/include/vki-ppc32-linux.h b/include/vki-ppc32-linux.h
index 7f8b752..d5ade89 100644
--- a/include/vki-ppc32-linux.h
+++ b/include/vki-ppc32-linux.h
@@ -237,6 +237,8 @@
#define VKI_PROT_READ 0x1 /* page can be read */
#define VKI_PROT_WRITE 0x2 /* page can be written */
#define VKI_PROT_EXEC 0x4 /* page can be executed */
+#define VKI_PROT_GROWSDOWN 0x01000000 /* mprotect flag: extend change to start of growsdown vma */
+#define VKI_PROT_GROWSUP 0x02000000 /* mprotect flag: extend change to end of growsup vma */
#define VKI_MAP_SHARED 0x01 /* Share changes */
#define VKI_MAP_PRIVATE 0x02 /* Changes are private */
diff --git a/include/vki-x86-linux.h b/include/vki-x86-linux.h
index ae73305..5d8d329 100644
--- a/include/vki-x86-linux.h
+++ b/include/vki-x86-linux.h
@@ -246,6 +246,8 @@
#define VKI_PROT_READ 0x1 /* page can be read */
#define VKI_PROT_WRITE 0x2 /* page can be written */
#define VKI_PROT_EXEC 0x4 /* page can be executed */
+#define VKI_PROT_GROWSDOWN 0x01000000 /* mprotect flag: extend change to start of growsdown vma */
+#define VKI_PROT_GROWSUP 0x02000000 /* mprotect flag: extend change to end of growsup vma */
#define VKI_MAP_SHARED 0x01 /* Share changes */
#define VKI_MAP_PRIVATE 0x02 /* Changes are private */