Blame SOURCES/0002-stack_grow_into_huge-don-t-clobber-existing-mappings.patch

ca0f40
From a329008ea54056f0ed9d85cc3d0d9129474f7cd5 Mon Sep 17 00:00:00 2001
ca0f40
Message-Id: <a329008ea54056f0ed9d85cc3d0d9129474f7cd5.1496667760.git.jstancek@redhat.com>
ca0f40
In-Reply-To: <192ac21a3c057c5dedca4cdd1bf700f38992030c.1496667760.git.jstancek@redhat.com>
ca0f40
References: <192ac21a3c057c5dedca4cdd1bf700f38992030c.1496667760.git.jstancek@redhat.com>
ca0f40
From: Jan Stancek <jstancek@redhat.com>
ca0f40
Date: Thu, 1 Jun 2017 10:00:47 +0200
ca0f40
Subject: [PATCH v2 2/2] stack_grow_into_huge: don't clobber existing mappings
ca0f40
ca0f40
This test allocates hugepages above stack using MAP_FIXED and then
ca0f40
grows stack while it can. If a MAP_FIXED request is successful,
ca0f40
then mapping established by mmap() replaces any previous mappings
ca0f40
for the process' pages. If there's anything important there (libc
ca0f40
mappings), these can get clobbered as described here:
ca0f40
  http://marc.info/?l=linux-arm-kernel&m=149036535209519&w=2.
ca0f40
ca0f40
This patch is creating extra stack for new child and maps
ca0f40
one hugepage above it. The search starts at heap until it
ca0f40
hits existing mapping or until it can successfully map
ca0f40
huge page and stack below it.
ca0f40
ca0f40
If suitable place can't be found, test PASSes as inconclusive.
ca0f40
ca0f40
Signed-off-by: Jan Stancek <jstancek@redhat.com>
ca0f40
---
ca0f40
 tests/stack_grow_into_huge.c | 101 ++++++++++++++++++++++++++++---------------
ca0f40
 1 file changed, 67 insertions(+), 34 deletions(-)
ca0f40
ca0f40
This is a v2 series for:
ca0f40
  https://groups.google.com/forum/#!topic/libhugetlbfs/tAsWjuJ7x8k
ca0f40
ca0f40
diff --git a/tests/stack_grow_into_huge.c b/tests/stack_grow_into_huge.c
ca0f40
index a380da063264..9b8ea8d74887 100644
ca0f40
--- a/tests/stack_grow_into_huge.c
ca0f40
+++ b/tests/stack_grow_into_huge.c
ca0f40
@@ -25,6 +25,7 @@
ca0f40
 #include <sys/mman.h>
ca0f40
 #include <sys/resource.h>
ca0f40
 #include <sys/wait.h>
ca0f40
+#include <sched.h>
ca0f40
 
ca0f40
 #include <hugetlbfs.h>
ca0f40
 #include "hugetests.h"
ca0f40
@@ -54,7 +55,10 @@
ca0f40
 #define STACK_ALLOCATION_SIZE	(16*1024*1024)
ca0f40
 #endif
ca0f40
 
ca0f40
-void do_child(void *stop_address)
ca0f40
+#define MIN_CHILD_STACK (2*1024*1024)
ca0f40
+#define STEP (STACK_ALLOCATION_SIZE)
ca0f40
+
ca0f40
+int do_child(void *stop_address)
ca0f40
 {
ca0f40
 	struct rlimit r;
ca0f40
 	volatile int *x;
ca0f40
@@ -71,15 +75,68 @@ void do_child(void *stop_address)
ca0f40
 		x = alloca(STACK_ALLOCATION_SIZE);
ca0f40
 		*x = 1;
ca0f40
 	} while ((void *)x >= stop_address);
ca0f40
+
ca0f40
+	return 0;
ca0f40
+}
ca0f40
+
ca0f40
+void *try_setup_stack_and_huge(int fd, void *hint)
ca0f40
+{
ca0f40
+	void *mmap_address, *stack_start, *tmp;
ca0f40
+	long hpage_size = gethugepagesize();
ca0f40
+	void *stop = alloca(1);
ca0f40
+
ca0f40
+	/*
ca0f40
+	 * Find a spot for huge page. We start at "hint" and
ca0f40
+	 * keep going down in "STEP" increments until we find
ca0f40
+	 * a place where we can mmap huge page.
ca0f40
+	 */
ca0f40
+	mmap_address = PALIGN(hint, hpage_size);
ca0f40
+	do {
ca0f40
+		mmap_address += STEP;
ca0f40
+		if (mmap_address >= stop)
ca0f40
+			return NULL;
ca0f40
+		if (range_is_mapped((unsigned long)mmap_address,
ca0f40
+			(unsigned long)mmap_address + hpage_size))
ca0f40
+			continue;
ca0f40
+		tmp = mmap(mmap_address, hpage_size,
ca0f40
+			PROT_READ|PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, 0);
ca0f40
+	} while (tmp == MAP_FAILED);
ca0f40
+	verbose_printf("huge page is at: %p-%p\n",
ca0f40
+		mmap_address, mmap_address + hpage_size);
ca0f40
+
ca0f40
+	/*
ca0f40
+	 * Find a spot for stack below huge page. We start at end of
ca0f40
+	 * huge page we found above and keep trying to mmap stack
ca0f40
+	 * below. Because stack needs to grow into hugepage, we
ca0f40
+	 * also have to make sure nothing is mapped in gap between
ca0f40
+	 * stack and huge page.
ca0f40
+	 */
ca0f40
+	stack_start = mmap_address + hpage_size;
ca0f40
+	do {
ca0f40
+		if (range_is_mapped((unsigned long)stack_start,
ca0f40
+			(unsigned long)stack_start + STEP + MIN_CHILD_STACK)) {
ca0f40
+			verbose_printf("range is mapped: %p-%p\n", stack_start,
ca0f40
+				stack_start + STEP + MIN_CHILD_STACK);
ca0f40
+			munmap(mmap_address, hpage_size);
ca0f40
+			return NULL;
ca0f40
+		}
ca0f40
+		stack_start += STEP;
ca0f40
+		if (stack_start >= stop)
ca0f40
+			return NULL;
ca0f40
+		tmp = mmap(stack_start, MIN_CHILD_STACK, PROT_READ|PROT_WRITE,
ca0f40
+			MAP_GROWSDOWN|MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0);
ca0f40
+	} while (tmp == MAP_FAILED);
ca0f40
+
ca0f40
+	verbose_printf("Child stack is at %p-%p\n",
ca0f40
+		stack_start, stack_start + MIN_CHILD_STACK);
ca0f40
+	return stack_start + MIN_CHILD_STACK;
ca0f40
 }
ca0f40
 
ca0f40
 int main(int argc, char *argv[])
ca0f40
 {
ca0f40
 	int fd, pid, s, ret;
ca0f40
 	struct rlimit r;
ca0f40
-	char *b;
ca0f40
-	long hpage_size = gethugepagesize();
ca0f40
-	void *stack_address, *mmap_address, *heap_address;
ca0f40
+	void *stack_end;
ca0f40
 
ca0f40
 	test_init(argc, argv);
ca0f40
 
ca0f40
@@ -94,37 +151,13 @@ int main(int argc, char *argv[])
ca0f40
 	if (fd < 0)
ca0f40
 		CONFIG("Couldn't get hugepage fd");
ca0f40
 
ca0f40
-	stack_address = alloca(0);
ca0f40
-	heap_address = sbrk(0);
ca0f40
+	stack_end = try_setup_stack_and_huge(fd, sbrk(0));
ca0f40
+	if (!stack_end)
ca0f40
+		PASS_INCONCLUSIVE();
ca0f40
 
ca0f40
-	/*
ca0f40
-	 * paranoia: start mapping two hugepages below the start of the stack,
ca0f40
-	 * in case the alignment would cause us to map over something if we
ca0f40
-	 * only used a gap of one hugepage.
ca0f40
-	 */
ca0f40
-	mmap_address = PALIGN(stack_address - 2 * hpage_size, hpage_size);
ca0f40
-
ca0f40
-	do {
ca0f40
-		b = mmap(mmap_address, hpage_size, PROT_READ|PROT_WRITE,
ca0f40
-						MAP_FIXED|MAP_SHARED, fd, 0);
ca0f40
-		mmap_address -= hpage_size;
ca0f40
-		/*
ca0f40
-		 * if we get all the way down to the heap, stop trying
ca0f40
-		 */
ca0f40
-		if (mmap_address <= heap_address)
ca0f40
-			break;
ca0f40
-	} while (b == MAP_FAILED);
ca0f40
-
ca0f40
-	if (b == MAP_FAILED)
ca0f40
-		FAIL("mmap: %s", strerror(errno));
ca0f40
-
ca0f40
-	if ((pid = fork()) < 0)
ca0f40
-		FAIL("fork: %s", strerror(errno));
ca0f40
-
ca0f40
-	if (pid == 0) {
ca0f40
-		do_child(mmap_address);
ca0f40
-		exit(0);
ca0f40
-	}
ca0f40
+	pid = clone(do_child, stack_end, SIGCHLD, 0);
ca0f40
+	if (pid < 0)
ca0f40
+		FAIL("clone: %s", strerror(errno));
ca0f40
 
ca0f40
 	ret = waitpid(pid, &s, 0);
ca0f40
 	if (ret == -1)
ca0f40
-- 
ca0f40
1.8.3.1
ca0f40