GNU C Library master sources branch master updated. glibc-2.28.9000-306-gbcdaad2

dj@sourceware.org dj@sourceware.org
Tue Nov 20 18:27:00 GMT 2018


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, master has been updated
       via  bcdaad21d4635931d1bd3b54a7894276925d081d (commit)
      from  5770c0ad1e0c784e817464ca2cf9436a58c9beb7 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=bcdaad21d4635931d1bd3b54a7894276925d081d

commit bcdaad21d4635931d1bd3b54a7894276925d081d
Author: DJ Delorie <dj@delorie.com>
Date:   Tue Nov 20 13:24:09 2018 -0500

    malloc: tcache double free check
    
    * malloc/malloc.c (tcache_entry): Add key field.
    (tcache_put): Set it.
    (tcache_get): Likewise.
    (_int_free): Check for double free in tcache.
    * malloc/tst-tcfree1.c: New.
    * malloc/tst-tcfree2.c: New.
    * malloc/Makefile: Run the new tests.
    * manual/probes.texi: Document memory_tcache_double_free probe.
    
    * dlfcn/dlerror.c (check_free): Prevent double frees.

diff --git a/ChangeLog b/ChangeLog
index be23442..9cdd3ba 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2018-11-20  DJ Delorie  <dj@redhat.com>
+
+	* malloc/malloc.c (tcache_entry): Add key field.
+	(tcache_put): Set it.
+	(tcache_get): Likewise.
+	(_int_free): Check for double free in tcache.
+	* malloc/tst-tcfree1.c: New.
+	* malloc/tst-tcfree2.c: New.
+	* malloc/Makefile: Run the new tests.
+	* manual/probes.texi: Document memory_tcache_double_free probe.
+
+	* dlfcn/dlerror.c (check_free): Prevent double frees.
+
 2018-11-20  Wilco Dijkstra  <wdijkstr@arm.com>
 
 	* sysdeps/aarch64/memset.S (MEMSET): Improve non-zero memset loop.
diff --git a/dlfcn/dlerror.c b/dlfcn/dlerror.c
index 33574fa..96bf925 100644
--- a/dlfcn/dlerror.c
+++ b/dlfcn/dlerror.c
@@ -198,7 +198,10 @@ check_free (struct dl_action_result *rec)
       Dl_info info;
       if (_dl_addr (check_free, &info, &map, NULL) != 0 && map->l_ns == 0)
 #endif
-	free ((char *) rec->errstring);
+	{
+	  free ((char *) rec->errstring);
+	  rec->errstring = NULL;
+	}
     }
 }
 
diff --git a/malloc/Makefile b/malloc/Makefile
index 7d54bad..e6dfbfc 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -38,6 +38,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
 	 tst-malloc_info \
 	 tst-malloc-too-large \
 	 tst-malloc-stats-cancellation \
+	 tst-tcfree1 tst-tcfree2 \
 
 tests-static := \
 	 tst-interpose-static-nothread \
diff --git a/malloc/malloc.c b/malloc/malloc.c
index 6d7a6a8..f730d7a 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -2967,6 +2967,8 @@ mremap_chunk (mchunkptr p, size_t new_size)
 typedef struct tcache_entry
 {
   struct tcache_entry *next;
+  /* This field exists to detect double frees.  */
+  struct tcache_perthread_struct *key;
 } tcache_entry;
 
 /* There is one of these for each thread, which contains the
@@ -2990,6 +2992,11 @@ tcache_put (mchunkptr chunk, size_t tc_idx)
 {
   tcache_entry *e = (tcache_entry *) chunk2mem (chunk);
   assert (tc_idx < TCACHE_MAX_BINS);
+
+  /* Mark this chunk as "in the tcache" so the test in _int_free will
+     detect a double free.  */
+  e->key = tcache;
+
   e->next = tcache->entries[tc_idx];
   tcache->entries[tc_idx] = e;
   ++(tcache->counts[tc_idx]);
@@ -3005,6 +3012,7 @@ tcache_get (size_t tc_idx)
   assert (tcache->entries[tc_idx] > 0);
   tcache->entries[tc_idx] = e->next;
   --(tcache->counts[tc_idx]);
+  e->key = NULL;
   return (void *) e;
 }
 
@@ -4218,6 +4226,26 @@ _int_free (mstate av, mchunkptr p, int have_lock)
   {
     size_t tc_idx = csize2tidx (size);
 
+    /* Check to see if it's already in the tcache.  */
+    tcache_entry *e = (tcache_entry *) chunk2mem (p);
+
+    /* This test succeeds on double free.  However, we don't 100%
+       trust it (it also matches random payload data at a 1 in
+       2^<size_t> chance), so verify it's not an unlikely coincidence
+       before aborting.  */
+    if (__glibc_unlikely (e->key == tcache && tcache))
+      {
+	tcache_entry *tmp;
+	LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx);
+	for (tmp = tcache->entries[tc_idx];
+	     tmp;
+	     tmp = tmp->next)
+	  if (tmp == e)
+	    malloc_printerr ("free(): double free detected in tcache 2");
+	/* If we get here, it was a coincidence.  We've wasted a few
+	   cycles, but don't abort.  */
+      }
+
     if (tcache
 	&& tc_idx < mp_.tcache_bins
 	&& tcache->counts[tc_idx] < mp_.tcache_count)
diff --git a/malloc/tst-tcfree1.c b/malloc/tst-tcfree1.c
new file mode 100644
index 0000000..bc29375
--- /dev/null
+++ b/malloc/tst-tcfree1.c
@@ -0,0 +1,42 @@
+/* Test that malloc tcache catches double free.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <error.h>
+#include <limits.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/signal.h>
+
+static int
+do_test (void)
+{
+  /* Do one allocation of any size that fits in tcache.  */
+  char * volatile x = malloc (32);
+
+  free (x); // puts in tcache
+  free (x); // should abort
+
+  printf("FAIL: tcache double free not detected\n");
+  return 1;
+}
+
+#define TEST_FUNCTION do_test
+#define EXPECTED_SIGNAL SIGABRT
+#include <support/test-driver.c>
diff --git a/malloc/tst-tcfree2.c b/malloc/tst-tcfree2.c
new file mode 100644
index 0000000..17f06ba
--- /dev/null
+++ b/malloc/tst-tcfree2.c
@@ -0,0 +1,48 @@
+/* Test that malloc tcache catches double free.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <error.h>
+#include <limits.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/signal.h>
+
+static int
+do_test (void)
+{
+  char * volatile ptrs[20];
+  int i;
+
+  /* Allocate enough small chunks so that when we free them all, the tcache
+     is full, and the first one we freed is at the end of its linked list.  */
+#define COUNT 20
+  for (i=0; i<COUNT; i++)
+    ptrs[i] = malloc (20);
+  for (i=0; i<COUNT; i++)
+    free (ptrs[i]);
+  free (ptrs[0]);
+
+  printf("FAIL: tcache double free\n");
+  return 1;
+}
+
+#define TEST_FUNCTION do_test
+#define EXPECTED_SIGNAL SIGABRT
+#include <support/test-driver.c>
diff --git a/manual/probes.texi b/manual/probes.texi
index ab2a310..0ea560e 100644
--- a/manual/probes.texi
+++ b/manual/probes.texi
@@ -243,6 +243,18 @@ This probe is triggered when the
 value of this tunable.
 @end deftp
 
+@deftp Probe memory_tcache_double_free (void *@var{$arg1}, int @var{$arg2})
+This probe is triggered when @code{free} determines that the memory
+being freed has probably already been freed, and resides in the
+per-thread cache.  Note that there is an extremely unlikely chance
+that this probe will trigger due to random payload data remaining in
+the allocated memory matching the key used to detect double frees.
+This probe actually indicates that an expensive linear search of the
+tcache, looking for a double free, has happened.  Argument @var{$arg1}
+is the memory location as passed to @code{free}, Argument @var{$arg2}
+is the tcache bin it resides in.
+@end deftp
+
 @node Mathematical Function Probes
 @section Mathematical Function Probes
 

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog                                          |   13 ++++++
 dlfcn/dlerror.c                                    |    5 ++-
 malloc/Makefile                                    |    1 +
 malloc/malloc.c                                    |   28 +++++++++++++
 .../x86/tst-cet-legacy-1.c => malloc/tst-tcfree1.c |   36 ++++++++---------
 .../x86/tst-cet-legacy-1.c => malloc/tst-tcfree2.c |   42 +++++++++++---------
 manual/probes.texi                                 |   12 ++++++
 7 files changed, 98 insertions(+), 39 deletions(-)
 copy sysdeps/x86/tst-cet-legacy-1.c => malloc/tst-tcfree1.c (67%)
 copy sysdeps/x86/tst-cet-legacy-1.c => malloc/tst-tcfree2.c (60%)


hooks/post-receive
-- 
GNU C Library master sources



More information about the Glibc-cvs mailing list