[PATCH] malloc: Fix [BZ #22853] weak randomization on thread arenas.

iripoll iripoll@disca.upv.es
Wed Mar 25 14:56:44 GMT 2020


Hello,

>>
> 
> Alright, could you post a v2 with the inline functions change, without
> the test and with a proper commit message?
> 
> Thanks for you patience and for the work on moving this forward.
> 

Here is the the patch with all the comments and suggestions.

Regards,
Ismael and Hector.



 From 6230b07e0fc85856275f89c16a18b46f8ed23936 Mon Sep 17 00:00:00 2001
From: Ismael Ripoll <iripoll@disca.upv.es>
Date: Wed, 25 Mar 2020 12:36:24 +0100
Subject: [PATCH] Fix [BZ #22853] weak randomization on thread arenas.

Signed-off-by: Ismael Ripoll <iripoll@disca.upv.es>
Co-Authored-By: Hector Marco-Gisbert <hmarco@hmarco.org>
---
  malloc/arena.c | 38 +++++++++++++++++++++++++++++---------
  1 file changed, 29 insertions(+), 9 deletions(-)

diff --git a/malloc/arena.c b/malloc/arena.c
index cecdb7f4c4..623824088b 100644
--- a/malloc/arena.c
+++ b/malloc/arena.c
@@ -122,13 +122,23 @@ int __malloc_initialized = -1;
          ptr = arena_get2 ((size), NULL);				      \
    } while (0)

-/* find the heap and corresponding arena for a given ptr */
-
-#define heap_for_ptr(ptr) \
-  ((heap_info *) ((unsigned long) (ptr) & ~(HEAP_MAX_SIZE - 1)))
-#define arena_for_chunk(ptr) \
-  (chunk_main_arena (ptr) ? &main_arena : heap_for_ptr (ptr)->ar_ptr)
-
+/* find the heap and corresponding arena for a given ptr.  Note that
+   heap_info is not HEAP_MAX_SIZE aligned any more.  But a random
+   offset from the expected alignment, known by the process.  This way
+   it is fast to get the head of the area and be ASLR friendly.
+*/
+static unsigned long arena_rnd;
+static inline heap_info *
+heap_for_ptr (mchunkptr ptr)
+{
+  return (heap_info *) ((((uintptr_t) ptr - arena_rnd)
+                         & ~(HEAP_MAX_SIZE - 1)) | arena_rnd);
+}
+static inline struct malloc_state *
+arena_for_chunk (mchunkptr ptr)
+{
+  return chunk_main_arena (ptr) ? &main_arena : heap_for_ptr (ptr)->ar_ptr;
+}

  /**************************************************************************/

@@ -293,6 +303,11 @@ ptmalloc_init (void)

    __malloc_initialized = 0;

+  size_t pagesize = GLRO (dl_pagesize);
+  /* Get the entropy from the already existing ASLR. */
+  arena_rnd = ((unsigned long) & arena_rnd) & (HEAP_MAX_SIZE - 1) &
+              ~(pagesize - 1);
+
  #ifdef SHARED
    /* In case this libc copy is in a non-default namespace, never use brk.
       Likewise if dlopened from statically linked program.  */
@@ -490,6 +505,11 @@ new_heap (size_t size, size_t top_pad)
          {
            p2 = (char *) (((unsigned long) p1 + (HEAP_MAX_SIZE - 1))
                           & ~(HEAP_MAX_SIZE - 1));
+          /* The heap_info is at a random offset from the alignment to
+             HEAP_MAX_SIZE. */
+          p2 = (char *) ((unsigned long) p2 | arena_rnd);
+          if (p1 + HEAP_MAX_SIZE <= p2)
+            p2 -= HEAP_MAX_SIZE;
            ul = p2 - p1;
            if (ul)
              __munmap (p1, ul);
@@ -500,12 +520,12 @@ new_heap (size_t size, size_t top_pad)
        else
          {
            /* Try to take the chance that an allocation of only HEAP_MAX_SIZE
-             is already aligned. */
+             is already aligned to arena_rnd. */
            p2 = (char *) MMAP (0, HEAP_MAX_SIZE, PROT_NONE, MAP_NORESERVE);
            if (p2 == MAP_FAILED)
              return 0;

-          if ((unsigned long) p2 & (HEAP_MAX_SIZE - 1))
+          if (((unsigned long) p2 & (HEAP_MAX_SIZE - 1)) != arena_rnd)
              {
                __munmap (p2, HEAP_MAX_SIZE);
                return 0;
-- 
2.20.1


More information about the Libc-alpha mailing list