In current implementation for any thread created with pthread_create glibc will create a new heap after the first malloc call from context of this thread. GNU Libc have special caches to keep stacks of finished threads and there's heaps. This caches allow glibc make faster creation of threads and its heaps. On any call to pthread_create or malloc from thread glibc first checks appropriated caches in hope to find already mmaped regions. And if find any use them. The problem here is this behaviour totally breaks ASLR - if attacker can leak address of ended thread stack or heap, he can use this address later in any vulnerability in hope to get the same stack region / heap memory region and successfully exploit application. Current kernel implementation of ASLR is going to be improved I hope. I prepared patches which will random addresses returned by kernel on any mmap. Here is Proof of Concepts: #include <pthread.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <sys/mman.h> #include <asm/prctl.h> #include <sys/prctl.h> void * func(void *x) { long a[1024]; printf("addr: %p\n", &a[0]); if (x) printf("value %lx\n", a[0]); else { a[0] = 0xdeadbeef; printf("value %lx\n", a[0]); } void * addr = malloc(32); printf("malloced %p\n", addr); free(addr); return 0; } int main(int argc, char **argv, char **envp) { int res, val; pthread_t thread; res = pthread_create(&thread, NULL, func, 0); if (res) { printf("Failed create thread %d\n", errno); return -1; } pthread_join(thread, &val); res = pthread_create(&thread, NULL, func, 1); if (res) { printf("Failed create thread %d\n", errno); return -1; } pthread_join(thread, &val); return 0; } and run: blackzert@crasher:~/aslur/tests$ ./pthread_cache addr: 0x7ffb90c52f40 value deadbeef malloced 0x7ffb8c000cd0 addr: 0x7ffb90c52f40 value deadbeef malloced 0x7ffb8c000cd0 with strace: blackzert@crasher:~/aslur/tests$ strace -e mmap,munmap ./pthread_cache mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f134346d000 mmap(NULL, 146377, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f1343449000 mmap(NULL, 2212904, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f134302d000 mmap(0x7f1343244000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x17000) = 0x7f1343244000 mmap(0x7f1343246000, 13352, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f1343246000 mmap(NULL, 3971488, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f1342c63000 mmap(0x7f1343023000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1c0000) = 0x7f1343023000 mmap(0x7f1343029000, 14752, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f1343029000 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1343448000 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1343447000 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1343446000 munmap(0x7f1343449000, 146377) = 0 mmap(NULL, 8392704, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7f1342462000 addr: 0x7f1342c5ff40 value deadbeef malloced 0x7f133c000cd0 addr: 0x7f1342c5ff40 value deadbeef malloced 0x7f133c000cd0 +++ exited with 0 +++ As you can see no mmap call between allocation.
Flagging as security- because this is a request for additional hardening.
Hello, Can you please explain me what exactly this hardening is? If this hardening of security, this should be a security bug, But if you think something different, please explain me. From my point of view this bug only about security because lead to ASLR bypass or in some cases may be used as exploitation technique.
One way to harden is to use a tunable for a thread stack cache, and set that to zero.
hello, I would like to ask why so far this bug has not been fixed in glibc