[v1a] malloc: Do not free or realloc chunks in corrupt arenas

Message ID 563CDC0F.3090105@redhat.com
State New, archived
Headers

Commit Message

Florian Weimer Nov. 6, 2015, 4:57 p.m. UTC
  On 11/06/2015 05:54 PM, Florian Weimer wrote:
> I am not sure if this is an actual bug in the malloc backtrace patch, or
> if this is can only happen once there are additional sources of corrupt
> arenas besides the malloc backtrace path
> 
> This was found through code inspection.  I do not have a test case at
> the moment.

Sorry, wrong version of patch attached.  This is the correct one, I hope.

Florian
  

Patch

2015-11-06  Florian Weimer  <fweimer@redhat.com>

	* malloc/malloc.c (__libc_free): Do not free chunks in corrupt
	arenas.
	(realloc_from_corrupt): New function.
	(__libc_realloc): Call it for corrupt arenas.

diff --git a/malloc/malloc.c b/malloc/malloc.c
index 839263e..2446c4a 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -2966,10 +2966,38 @@  __libc_free (void *mem)
     }
 
   ar_ptr = arena_for_chunk (p);
+
+  if (__glibc_unlikely (arena_is_corrupt (ar_ptr)))
+    /* Do nothing if the arena is known to be corrupt.  */
+    return;
+
   _int_free (ar_ptr, p, 0);
 }
 libc_hidden_def (__libc_free)
 
+/* Always make a copy to enlarge a chunk in a corrupt arena.  The
+   chunk must not have been allocated with mmap.  */
+static void *
+realloc_from_corrupt (void *oldmem, size_t bytes,
+		      INTERNAL_SIZE_T oldsize)
+{
+  /* Size adjustment for the non-mmap case.  */
+  oldsize -= SIZE_SZ;
+
+  /* Reuse the old chunk if possible.  */
+  if (oldsize >= bytes)
+    return oldmem;
+
+  void *newmem = __libc_malloc (bytes);
+  if (__glibc_unlikely (newmem == NULL))
+    return NULL;
+  memcpy (newmem, oldmem, oldsize);
+
+  /* Do not free the old object because the arena is known to be
+     corrupt.  */
+  return newmem;
+}
+
 void *
 __libc_realloc (void *oldmem, size_t bytes)
 {
@@ -3041,6 +3069,9 @@  __libc_realloc (void *oldmem, size_t bytes)
       return newmem;
     }
 
+  if (__glibc_unlikely (arena_is_corrupt (ar_ptr)))
+    return realloc_from_corrupt (oldmem, bytes, oldsize);
+
   (void) mutex_lock (&ar_ptr->mutex);
 
   newp = _int_realloc (ar_ptr, oldp, oldsize, nb);