|
|
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
|