summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Pluzhnikov <ppluzhnikov@google.com>2013-12-18 15:07:11 -0800
committerPaul Pluzhnikov <ppluzhnikov@google.com>2013-12-18 15:07:11 -0800
commit69a17d9d245dc3551792e95e1823cc2d877592f3 (patch)
tree719f3789f573b05c6c168f3720048acd42420ea4
parenta588438951a271ca10623fb8c7e25693c7ebea67 (diff)
Patch [1/4] async-signal safe TLS.
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.
-rw-r--r--ChangeLog11
-rw-r--r--sysdeps/generic/ldsodefs.h5
-rw-r--r--sysdeps/mach/hurd/dl-sysdep.h7
-rw-r--r--sysdeps/unix/sysv/linux/dl-sysdep.c46
-rw-r--r--sysdeps/unix/sysv/linux/dl-sysdep.h4
5 files changed, 73 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 173c2801f1..126c92e006 100644
--- 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]
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 146aca4dfb..e919e4136c 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -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. */
diff --git a/sysdeps/mach/hurd/dl-sysdep.h b/sysdeps/mach/hurd/dl-sysdep.h
index 52563b0ca0..0e7cac4ab0 100644
--- a/sysdeps/mach/hurd/dl-sysdep.h
+++ b/sysdeps/mach/hurd/dl-sysdep.h
@@ -29,3 +29,10 @@
# 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 *) { }
diff --git a/sysdeps/unix/sysv/linux/dl-sysdep.c b/sysdeps/unix/sysv/linux/dl-sysdep.c
index e80cb8d9f0..4b837acbc0 100644
--- a/sysdeps/unix/sysv/linux/dl-sysdep.c
+++ b/sysdeps/unix/sysv/linux/dl-sysdep.c
@@ -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);
+}
diff --git a/sysdeps/unix/sysv/linux/dl-sysdep.h b/sysdeps/unix/sysv/linux/dl-sysdep.h
index e1eab09025..0fe1e1c3d0 100644
--- a/sysdeps/unix/sysv/linux/dl-sysdep.h
+++ b/sysdeps/unix/sysv/linux/dl-sysdep.h
@@ -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