bdc76f
commit b90ddd08f6dd688e651df9ee89ca3a69ff88cd0c
bdc76f
Author: Istvan Kurucsai <pistukem@gmail.com>
bdc76f
Date:   Tue Jan 16 14:54:32 2018 +0100
bdc76f
bdc76f
    malloc: Additional checks for unsorted bin integrity I.
bdc76f
    
bdc76f
    On Thu, Jan 11, 2018 at 3:50 PM, Florian Weimer <fweimer@redhat.com> wrote:
bdc76f
    > On 11/07/2017 04:27 PM, Istvan Kurucsai wrote:
bdc76f
    >>
bdc76f
    >> +          next = chunk_at_offset (victim, size);
bdc76f
    >
bdc76f
    >
bdc76f
    > For new code, we prefer declarations with initializers.
bdc76f
    
bdc76f
    Noted.
bdc76f
    
bdc76f
    >> +          if (__glibc_unlikely (chunksize_nomask (victim) <= 2 * SIZE_SZ)
bdc76f
    >> +              || __glibc_unlikely (chunksize_nomask (victim) >
bdc76f
    >> av->system_mem))
bdc76f
    >> +            malloc_printerr("malloc(): invalid size (unsorted)");
bdc76f
    >> +          if (__glibc_unlikely (chunksize_nomask (next) < 2 * SIZE_SZ)
bdc76f
    >> +              || __glibc_unlikely (chunksize_nomask (next) >
bdc76f
    >> av->system_mem))
bdc76f
    >> +            malloc_printerr("malloc(): invalid next size (unsorted)");
bdc76f
    >> +          if (__glibc_unlikely ((prev_size (next) & ~(SIZE_BITS)) !=
bdc76f
    >> size))
bdc76f
    >> +            malloc_printerr("malloc(): mismatching next->prev_size
bdc76f
    >> (unsorted)");
bdc76f
    >
bdc76f
    >
bdc76f
    > I think this check is redundant because prev_size (next) and chunksize
bdc76f
    > (victim) are loaded from the same memory location.
bdc76f
    
bdc76f
    I'm fairly certain that it compares mchunk_size of victim against
bdc76f
    mchunk_prev_size of the next chunk, i.e. the size of victim in its
bdc76f
    header and footer.
bdc76f
    
bdc76f
    >> +          if (__glibc_unlikely (bck->fd != victim)
bdc76f
    >> +              || __glibc_unlikely (victim->fd != unsorted_chunks (av)))
bdc76f
    >> +            malloc_printerr("malloc(): unsorted double linked list
bdc76f
    >> corrupted");
bdc76f
    >> +          if (__glibc_unlikely (prev_inuse(next)))
bdc76f
    >> +            malloc_printerr("malloc(): invalid next->prev_inuse
bdc76f
    >> (unsorted)");
bdc76f
    >
bdc76f
    >
bdc76f
    > There's a missing space after malloc_printerr.
bdc76f
    
bdc76f
    Noted.
bdc76f
    
bdc76f
    > Why do you keep using chunksize_nomask?  We never investigated why the
bdc76f
    > original code uses it.  It may have been an accident.
bdc76f
    
bdc76f
    You are right, I don't think it makes a difference in these checks. So
bdc76f
    the size local can be reused for the checks against victim. For next,
bdc76f
    leaving it as such avoids the masking operation.
bdc76f
    
bdc76f
    > Again, for non-main arenas, the checks against av->system_mem could be made
bdc76f
    > tighter (against the heap size).  Maybe you could put the condition into a
bdc76f
    > separate inline function?
bdc76f
    
bdc76f
    We could also do a chunk boundary check similar to what I proposed in
bdc76f
    the thread for the first patch in the series to be even more strict.
bdc76f
    I'll gladly try to implement either but believe that refining these
bdc76f
    checks would bring less benefits than in the case of the top chunk.
bdc76f
    Intra-arena or intra-heap overlaps would still be doable here with
bdc76f
    unsorted chunks and I don't see any way to counter that besides more
bdc76f
    generic measures like randomizing allocations and your metadata
bdc76f
    encoding patches.
bdc76f
    
bdc76f
    I've attached a revised version with the above comments incorporated
bdc76f
    but without the refined checks.
bdc76f
    
bdc76f
    Thanks,
bdc76f
    Istvan
bdc76f
    
bdc76f
    From a12d5d40fd7aed5fa10fc444dcb819947b72b315 Mon Sep 17 00:00:00 2001
bdc76f
    From: Istvan Kurucsai <pistukem@gmail.com>
bdc76f
    Date: Tue, 16 Jan 2018 14:48:16 +0100
bdc76f
    Subject: [PATCH v2 1/1] malloc: Additional checks for unsorted bin integrity
bdc76f
     I.
bdc76f
    
bdc76f
    Ensure the following properties of chunks encountered during binning:
bdc76f
    - victim chunk has reasonable size
bdc76f
    - next chunk has reasonable size
bdc76f
    - next->prev_size == victim->size
bdc76f
    - valid double linked list
bdc76f
    - PREV_INUSE of next chunk is unset
bdc76f
    
bdc76f
        * malloc/malloc.c (_int_malloc): Additional binning code checks.
bdc76f
bdc76f
diff --git a/malloc/malloc.c b/malloc/malloc.c
bdc76f
index d8d4581a9dcea80a..dad0e73735789530 100644
bdc76f
--- a/malloc/malloc.c
bdc76f
+++ b/malloc/malloc.c
bdc76f
@@ -3724,11 +3724,22 @@ _int_malloc (mstate av, size_t bytes)
bdc76f
       while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
bdc76f
         {
bdc76f
           bck = victim->bk;
bdc76f
-          if (__builtin_expect (chunksize_nomask (victim) <= 2 * SIZE_SZ, 0)
bdc76f
-              || __builtin_expect (chunksize_nomask (victim)
bdc76f
-				   > av->system_mem, 0))
bdc76f
-            malloc_printerr ("malloc(): memory corruption");
bdc76f
           size = chunksize (victim);
bdc76f
+          mchunkptr next = chunk_at_offset (victim, size);
bdc76f
+
bdc76f
+          if (__glibc_unlikely (size <= 2 * SIZE_SZ)
bdc76f
+              || __glibc_unlikely (size > av->system_mem))
bdc76f
+            malloc_printerr ("malloc(): invalid size (unsorted)");
bdc76f
+          if (__glibc_unlikely (chunksize_nomask (next) < 2 * SIZE_SZ)
bdc76f
+              || __glibc_unlikely (chunksize_nomask (next) > av->system_mem))
bdc76f
+            malloc_printerr ("malloc(): invalid next size (unsorted)");
bdc76f
+          if (__glibc_unlikely ((prev_size (next) & ~(SIZE_BITS)) != size))
bdc76f
+            malloc_printerr ("malloc(): mismatching next->prev_size (unsorted)");
bdc76f
+          if (__glibc_unlikely (bck->fd != victim)
bdc76f
+              || __glibc_unlikely (victim->fd != unsorted_chunks (av)))
bdc76f
+            malloc_printerr ("malloc(): unsorted double linked list corrupted");
bdc76f
+          if (__glibc_unlikely (prev_inuse(next)))
bdc76f
+            malloc_printerr ("malloc(): invalid next->prev_inuse (unsorted)");
bdc76f
 
bdc76f
           /*
bdc76f
              If a small request, try to use last remainder if it is the