Patch [1/4] async-signal safe TLS.
authorPaul Pluzhnikov <ppluzhnikov@google.com>
Wed, 18 Dec 2013 23:07:11 +0000 (15:07 -0800)
committerPaul Pluzhnikov <ppluzhnikov@google.com>
Wed, 18 Dec 2013 23:07:11 +0000 (15:07 -0800)
2013-12-18  Andrew Hunter  <ahh@google.com>

* sysdeps/generic/ldsodefs.h (_dl_mask_all_signals): New prototype.
(_dl_unmask_signals): Likewise.
* sysdeps/mach/hurd/dl-sysdep.h (_dl_mask_all_signals): New stub.
(_dl_unmask_all_signals): Likewise.
* sysdeps/unix/sysv/linux/dl-sysdep.h (_dl_mask_all_signals): New prototype.
(_dl_unmask_all_signals): Likewise.
* sysdeps/unix/sysv/linux/dl-sysdep.c (_dl_mask_all_signals): New function.
(_dl_unmask_signals): Likewise.

ChangeLog
sysdeps/generic/ldsodefs.h
sysdeps/mach/hurd/dl-sysdep.h
sysdeps/unix/sysv/linux/dl-sysdep.c
sysdeps/unix/sysv/linux/dl-sysdep.h

index 173c280..126c92e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2013-12-18  Andrew Hunter  <ahh@google.com>
+
+       * sysdeps/generic/ldsodefs.h (_dl_mask_all_signals): New prototype.
+       (_dl_unmask_signals): Likewise.
+       * sysdeps/mach/hurd/dl-sysdep.h (_dl_mask_all_signals): New stub.
+       (_dl_unmask_all_signals): Likewise.
+       * sysdeps/unix/sysv/linux/dl-sysdep.h (_dl_mask_all_signals): New prototype.
+       (_dl_unmask_all_signals): Likewise.
+       * sysdeps/unix/sysv/linux/dl-sysdep.c (_dl_mask_all_signals): New function.
+       (_dl_unmask_signals): Likewise.
+
 2013-12-18  Brooks Moses  <bmoses@google.com>
 
        [BZ #15846]
index 146aca4..e919e41 100644 (file)
@@ -234,6 +234,11 @@ extern int _dl_name_match_p (const char *__name, const struct link_map *__map)
 extern unsigned long int _dl_higher_prime_number (unsigned long int n)
      internal_function;
 
+/* Mask every signal, returning the previous sigmask in OLD.  */
+extern void _dl_mask_all_signals (sigset_t *old) internal_function;
+/* Undo _dl_mask_all_signals.  */
+extern void _dl_unmask_signals (sigset_t *old) internal_function;
+
 /* Function used as argument for `_dl_receive_error' function.  The
    arguments are the error code, error string, and the objname the
    error occurred in.  */
index 52563b0..0e7cac4 100644 (file)
 # define DL_ARGV_NOT_RELRO 1
 # define LIBC_STACK_END_NOT_RELRO 1
 #endif
+
+#include <signal.h>
+inline void _dl_mask_all_signals (sigset_t *) internal_function;
+inline void _dl_mask_all_signals (sigset_t *) { }
+
+inline void _dl_unmask_all_signals (sigset_t *) internal_function;
+inline void _dl_unmask_all_signals (sigset_t *) { }
index e80cb8d..4b837ac 100644 (file)
@@ -19,6 +19,7 @@
 /* Linux needs some special initialization, but otherwise uses
    the generic dynamic linker system interface code.  */
 
+#include <assert.h>
 #include <string.h>
 #include <fcntl.h>
 #include <unistd.h>
@@ -130,3 +131,48 @@ _dl_discover_osversion (void)
 
   return version;
 }
+
+/* Mask every signal, returning the previous sigmask in OLD.  */
+void
+internal_function
+_dl_mask_all_signals (sigset_t *old)
+{
+  int ret;
+  sigset_t new;
+
+  sigfillset (&new);
+
+  /* This function serves as a replacement to pthread_sigmask, which
+     isn't available from within the dynamic linker since it would require
+     linking with libpthread. We duplicate some of the functionality here
+     to avoid requiring libpthread.  This isn't quite identical to
+     pthread_sigmask in that we do not mask internal signals used for
+     cancellation and setxid handling. This disables asynchronous
+     cancellation for the duration the signals are disabled, but it's a
+     small window, and prevents any problems with the use of TLS variables
+     in the signal handlers that would have executed.  */
+
+  /* It's very important we don't touch errno here, as that's TLS; since this
+     gets called from get_tls_addr we might end up recursing.  */
+
+  INTERNAL_SYSCALL_DECL (err);
+
+  ret = INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &new, old,
+                         _NSIG / 8);
+
+  assert (ret == 0);
+}
+
+/* Return sigmask to what it was before a call to _dl_mask_all_signals.  */
+void
+internal_function
+_dl_unmask_signals (sigset_t *old)
+{
+  int ret;
+  INTERNAL_SYSCALL_DECL (err);
+
+  ret = INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, old, NULL,
+                         _NSIG / 8);
+
+  assert (ret == 0);
+}
index e1eab09..0fe1e1c 100644 (file)
@@ -30,4 +30,8 @@
 /* Get version of the OS.  */
 extern int _dl_discover_osversion (void) attribute_hidden;
 # define HAVE_DL_DISCOVER_OSVERSION    1
+
+#include <signal.h>
+void _dl_mask_all_signals (sigset_t *) internal_function;
+void _dl_unmask_all_signals (sigset_t *) internal_function;
 #endif