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

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