[Libguestfs] [PATCH nbdkit] wrapper: Set MALLOC_CHECK=1 and MALLOC_PERTURB_ (randomly).

Richard W.M. Jones rjones at redhat.com
Mon Mar 18 16:59:09 UTC 2019


This is a cheap way to find some use-after-free and uninitialized read
problems when using glibc.

This in fact reveals a race during filter shutdown (which this
commit does not fix):

 Thread 2 (Thread 0x7f1caaa5ffc0 (LWP 7223)):
 #0  0x00007f1cab0a05f8 in pthread_rwlock_wrlock () from /lib64/libpthread.so.0
 #1  0x0000000000408842 in lock_unload () at locks.c:97
 #2  0x00000000004066ff in filter_free (b=0x203c330) at filters.c:77
 #3  0x000000000040a6f4 in main (argc=11, argv=0x7ffc1f4486e8) at main.c:649

 Thread 1 (Thread 0x7f1caaa5e700 (LWP 7226)):
 #0  0x000000000040732a in filter_finalize (b=0x203c330, conn=0x203d870)
     at filters.c:421
 #1  0x0000000000404d07 in _handle_single_connection (sockin=6, sockout=6)
     at connections.c:239
 #2  0x0000000000404d76 in handle_single_connection (sockin=6, sockout=6)
     at connections.c:258
 #3  0x00000000004119f6 in start_thread (datav=0x203b450) at sockets.c:263
 #4  0x00007f1cab09b5a2 in start_thread () from /lib64/libpthread.so.0
 #5  0x00007f1caafc85c3 in clone () from /lib64/libc.so.6

What's happening here is that the filter / plugin chain is freed by
Thread 2, while Thread 1 is calling filter->finalize.  At this point
filter->finalize points to freed memory, but "normally" this would
still contain the correct function pointer.  However when
MALLOC_PERTURB_ is set the function pointer is overwritten with the
non-zero dead memory pattern which we then attempt to call, causing a
segfault (in Thread 1).
---
 wrapper.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/wrapper.c b/wrapper.c
index ffb058b..6b5118c 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -70,6 +70,7 @@
 #include <unistd.h>
 #include <getopt.h>
 #include <limits.h>
+#include <time.h>
 
 #include "options.h"
 
@@ -133,6 +134,9 @@ main (int argc, char *argv[])
 {
   bool verbose = false;
   char *s;
+  time_t t;
+  unsigned tu;
+  char ts[32];
 
   /* If NBDKIT_VALGRIND=1 is set in the environment, then we run the
    * program under valgrind.  This is used by the tests.  Similarly if
@@ -250,6 +254,19 @@ main (int argc, char *argv[])
   if (verbose)
     print_command ();
 
+  /* This is a cheap way to find some use-after-free and uninitialized
+   * read problems when using glibc, and doesn't affect normal
+   * operation or other libc.  We don't overwrite existing values so
+   * this can be disabled or overridden at runtime.
+   */
+  setenv ("MALLOC_CHECK_", "1", 0);
+  time (&t);
+  tu = t;
+  tu %= 255;
+  tu++;
+  snprintf (ts, sizeof ts, "%u", tu);
+  setenv ("MALLOC_PERTURB_", ts, 0);
+
   /* Run the final command. */
   execvp (cmd[0], (char **) cmd);
   perror (cmd[0]);
-- 
2.20.1




More information about the Libguestfs mailing list