Bug 22853 (CVE-2019-1010025) - Heap address of pthread_create thread is aligned.
Summary: Heap address of pthread_create thread is aligned.
Status: UNCONFIRMED
Alias: CVE-2019-1010025
Product: glibc
Classification: Unclassified
Component: nptl (show other bugs)
Version: unspecified
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2018-02-16 12:09 UTC by Ilya Smith
Modified: 2019-08-05 12:29 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:
fweimer: security-


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ilya Smith 2018-02-16 12:09:45 UTC
When pthread_create'ed thread firstly calls malloc, glibc create a new heap region for it. Size of this heap depends on compile-time configuration and in my case ( x84-64 arch ) HEAP_MAX_SIZE is 64MB

In function malloc/arena.c:new_heap there is a condigion when heap will be aligned by HEAP_MAX_SIZE. This means that address of created heap will be aligned to HEAP_MAX_SIZE what is 64MB in my case.

Now we can compute the probability to guess the heap address by attacker.

2^48 - 4096 is size of user-mode task. 64MB is 2^26 that means there is 48-26=22, 2^22 possible heaps in the application.
For many Linux distributives mmap_rnd_bits is 28 (tunable with /proc/sys/vm/mmap_rnd_bits ). It means for such systems 8 hi-bits would be set - 48 bits - (mmap_rnd_bits + PAGE_SHIFT) = 8, this means we know 8 hi bits of mmap_base address - it will be started from 0x7f.
What does it means? it means that if application create thread and call malloc from new thread, it is 2^14 possible values for such heap.

Proof of Concept:

first get program that outputs malloc addr:

#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <sys/mman.h>

void * first(void *x)
{
       int a = (int)x;
       int *p_a = &a;

	void *ptr;
       ptr = malloc(8);
       if (ptr == 0)
       {
               printf("Failed to alloc %d\n", errno);
               return -1;
       }
	printf("%p\n", ptr);
       return 0;
}

int main()
{
       int res;
       pthread_t one;

       res = pthread_create(&one, NULL, &first, 0);
       if (res)
       {
               printf("Failed create thread %d\n", errno);
               return -1;
       }
       void *val;
       pthread_join(one,&val);
       return 0;
}

now execute it many times and get histogram with python:

import subprocess

d = {}
i = 0
while i < 1000000:
   output = subprocess.check_output('./thread_stack_heap_hysto')
   key = int(output, 16)
   if key in d:
       d[key] += 1
   else:
       d[key] = 1
   i += 1
print 'total: ', len(d)
for key in d:
   print hex(key), d[key]


and the result:
$ python get_hysto.py
total:  16385
…

16385 is 0x4001, and 1 here is because max address of kernel for 1 page less then 2^48.

Summary, heap should not be aligned on 64 megabytes, this behaviour allows attacker to brute force heap of pthread created thread.
Comment 1 Florian Weimer 2018-02-28 13:21:17 UTC
Flagging as security- because this is just hardening.
Comment 2 Ilya Smith 2018-02-28 15:45:40 UTC
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.
Comment 3 Florian Weimer 2019-08-05 11:34:20 UTC
(In reply to Ilya Smith from comment #2)
> 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.

ASLR bypass itself is not a vulnerability.  It may simplify exploitation of another, unrelated vulnerability.
Comment 4 Adhemerval Zanella 2019-08-05 12:29:05 UTC
My understanding of reporter intention is to point out the malloc heap alignment restriction lowers the total entropy available to kernel, which is an implementation detail from glibc. But I agree with Florian reasoning that this is hardening feature.