This is the mail archive of the glibc-cvs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

GNU C Library master sources branch release/2.27/master updated. glibc-2.27-91-g5047716


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, release/2.27/master has been updated
       via  50477165b93538654f2d03a598e9ede45e7f5ac3 (commit)
       via  4b246928bd7ffabad7303dffa84ee542450e56d9 (commit)
      from  9f433fc791ca4f9d678903ff45b504b524c886fb (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=50477165b93538654f2d03a598e9ede45e7f5ac3

commit 50477165b93538654f2d03a598e9ede45e7f5ac3
Author: DJ Delorie <dj@redhat.com>
Date:   Fri Nov 30 22:13:09 2018 -0500

    malloc: Add another test for tcache double free check.
    
    This one tests for BZ#23907 where the double free
    test didn't check the tcache bin bounds before dereferencing
    the bin.
    
    [BZ #23907]
    * malloc/tst-tcfree3.c: New.
    * malloc/Makefile: Add it.
    
    (cherry picked from commit 7c9a7c68363051cfc5fa1ebb96b3b2c1f82dcb76)

diff --git a/ChangeLog b/ChangeLog
index b2408aa..e782412 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2018-12-07  DJ Delorie  <dj@redhat.com>
+
+	[BZ #23907]
+	* malloc/tst-tcfree3.c: New.
+	* malloc/Makefile: Add it.
+
 2018-11-26  Florian Weimer  <fweimer@redhat.com>
 
 	[BZ #23907]
diff --git a/malloc/Makefile b/malloc/Makefile
index 946f2c2..a23d370 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -37,7 +37,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
 	 tst-malloc-tcache-leak \
 	 tst-malloc_info \
 	 tst-malloc-too-large \
-	 tst-tcfree1 tst-tcfree2 \
+	 tst-tcfree1 tst-tcfree2 tst-tcfree3 \
 
 tests-static := \
 	 tst-interpose-static-nothread \
diff --git a/malloc/tst-tcfree3.c b/malloc/tst-tcfree3.c
new file mode 100644
index 0000000..016d30d
--- /dev/null
+++ b/malloc/tst-tcfree3.c
@@ -0,0 +1,56 @@
+/* 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 <malloc.h>
+#include <string.h>
+
+/* Prevent GCC from optimizing away any malloc/free pairs.  */
+#pragma GCC optimize ("O0")
+
+static int
+do_test (void)
+{
+  /* Do two allocation of any size that fit in tcache, and one that
+     doesn't.  */
+  int ** volatile a = malloc (32);
+  int ** volatile b = malloc (32);
+  /* This is just under the mmap threshold.  */
+  int ** volatile c = malloc (127 * 1024);
+
+  /* The invalid "tcache bucket" we might dereference will likely end
+     up somewhere within this memory block, so make all the accidental
+     "next" pointers cause segfaults.  BZ #23907.  */
+  memset (c, 0xff, 127 * 1024);
+
+  free (a); // puts in tcache
+
+  /* A is now free and contains the key we use to detect in-tcache.
+     Copy the key to the other chunks.  */
+  memcpy (b, a, 32);
+  memcpy (c, a, 32);
+
+  /* This free tests the "are we in the tcache already" loop with a
+     VALID bin but "coincidental" matching key.  */
+  free (b); // should NOT abort
+  /* This free tests the "is it a valid tcache bin" test.  */
+  free (c); // should NOT abort
+
+  return 0;
+}
+
+#include <support/test-driver.c>

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=4b246928bd7ffabad7303dffa84ee542450e56d9

commit 4b246928bd7ffabad7303dffa84ee542450e56d9
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.
    
    (cherry picked from commit bcdaad21d4635931d1bd3b54a7894276925d081d)
    
    malloc: tcache: Validate tc_idx before checking for double-frees [BZ #23907]
    
    The previous check could read beyond the end of the tcache entry
    array.  If the e->key == tcache cookie check happened to pass, this
    would result in crashes.
    
    (cherry picked from commit affec03b713c82c43a5b025dddc21bde3334f41e)

diff --git a/ChangeLog b/ChangeLog
index 2f1e82b..b2408aa 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2018-11-26  Florian Weimer  <fweimer@redhat.com>
+
+	[BZ #23907]
+	* malloc/malloc.c (_int_free): Validate tc_idx before checking for
+	double-frees.
+
+
+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-27  Florian Weimer  <fweimer@redhat.com>
 
 	[BZ #23927]
diff --git a/dlfcn/dlerror.c b/dlfcn/dlerror.c
index 04dce9d..0fd1cf1 100644
--- a/dlfcn/dlerror.c
+++ b/dlfcn/dlerror.c
@@ -197,7 +197,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 17873e6..946f2c2 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -37,6 +37,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
 	 tst-malloc-tcache-leak \
 	 tst-malloc_info \
 	 tst-malloc-too-large \
+	 tst-tcfree1 tst-tcfree2 \
 
 tests-static := \
 	 tst-interpose-static-nothread \
diff --git a/malloc/malloc.c b/malloc/malloc.c
index f8e7250..80c6003 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -2904,6 +2904,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
@@ -2927,6 +2929,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]);
@@ -2942,6 +2949,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;
 }
 
@@ -4165,13 +4173,33 @@ _int_free (mstate av, mchunkptr p, int have_lock)
 #if USE_TCACHE
   {
     size_t tc_idx = csize2tidx (size);
-
-    if (tcache
-	&& tc_idx < mp_.tcache_bins
-	&& tcache->counts[tc_idx] < mp_.tcache_count)
+    if (tcache != NULL && tc_idx < mp_.tcache_bins)
       {
-	tcache_put (p, tc_idx);
-	return;
+	/* 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_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->counts[tc_idx] < mp_.tcache_count)
+	  {
+	    tcache_put (p, tc_idx);
+	    return;
+	  }
       }
   }
 #endif
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 8ab6756..4742cdb 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            |   26 +++++++++++++++++++++++
 dlfcn/dlerror.c      |    5 +++-
 malloc/Makefile      |    1 +
 malloc/malloc.c      |   40 ++++++++++++++++++++++++++++++-----
 malloc/tst-tcfree1.c |   42 +++++++++++++++++++++++++++++++++++++
 malloc/tst-tcfree2.c |   48 ++++++++++++++++++++++++++++++++++++++++++
 malloc/tst-tcfree3.c |   56 ++++++++++++++++++++++++++++++++++++++++++++++++++
 manual/probes.texi   |   12 ++++++++++
 8 files changed, 223 insertions(+), 7 deletions(-)
 create mode 100644 malloc/tst-tcfree1.c
 create mode 100644 malloc/tst-tcfree2.c
 create mode 100644 malloc/tst-tcfree3.c


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]