about summary refs log tree commit diff
path: root/src/malloc
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2015-06-09 20:30:35 +0000
committerRich Felker <dalias@aerifal.cx>2015-06-09 21:31:55 +0000
commit276904c2f6bde3a31a24ebfa201482601d18b4f9 (patch)
treede72437def91f8479a027d51d69d0a11fa96cfc2 /src/malloc
parentbd1eaceaa3975bd2a2a34e211cff896affaecadf (diff)
downloadmusl-276904c2f6bde3a31a24ebfa201482601d18b4f9.tar.gz
musl-276904c2f6bde3a31a24ebfa201482601d18b4f9.tar.xz
musl-276904c2f6bde3a31a24ebfa201482601d18b4f9.zip
in malloc, refuse to use brk if it grows into stack
the linux/nommu fdpic ELF loader sets up the brk range to overlap
entirely with the main thread's stack (but growing from opposite
ends), so that the resulting failure mode for malloc is not to return
a null pointer but to start returning pointers to memory that overlaps
with the caller's stack. needless to say this extremely dangerous and
makes brk unusable.

since it's non-trivial to detect execution environments that might be
affected by this kernel bug, and since the severity of the bug makes
any sort of detection that might yield false-negatives unsafe, we
instead check the proximity of the brk to the stack pointer each time
the brk is to be expanded. both the main thread's stack (where the
real known risk lies) and the calling thread's stack are checked. an
arbitrary gap distance of 8 MB is imposed, chosen to be larger than
linux default main-thread stack reservation sizes and larger than any
reasonable stack configuration on nommu.

the effeciveness of this patch relies on an assumption that the amount
by which the brk is being grown is smaller than the gap limit, which
is always true for malloc's use of brk. reliance on this assumption is
why the check is being done in malloc-specific code and not in __brk.
Diffstat (limited to 'src/malloc')
-rw-r--r--src/malloc/malloc.c10
1 files changed, 9 insertions, 1 deletions
diff --git a/src/malloc/malloc.c b/src/malloc/malloc.c
index d4de2dc1..a42aeede 100644
--- a/src/malloc/malloc.c
+++ b/src/malloc/malloc.c
@@ -152,6 +152,14 @@ void __dump_heap(int x)
 }
 #endif
 
+static int is_near_stack(uintptr_t b)
+{
+	const uintptr_t c = 8<<20;
+	uintptr_t a = (uintptr_t)libc.auxv;
+	uintptr_t d = (uintptr_t)&b;
+	return a-b<=c || d-b<=c;
+}
+
 static struct chunk *expand_heap(size_t n)
 {
 	static int init;
@@ -174,7 +182,7 @@ static struct chunk *expand_heap(size_t n)
 	new = mal.brk + n + SIZE_ALIGN + PAGE_SIZE - 1 & -PAGE_SIZE;
 	n = new - mal.brk;
 
-	if (__brk(new) != new) {
+	if (is_near_stack(mal.brk) || __brk(new) != new) {
 		size_t min = (size_t)PAGE_SIZE << mal.mmap_step/2;
 		n += -n & PAGE_SIZE-1;
 		if (n < min) n = min;