summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2020-10-01 12:18:18 -0400
committerRich Felker <dalias@aerifal.cx>2020-10-14 20:27:12 -0400
commit25ea9f712c30c32957de493d4711ee39d0bbb024 (patch)
tree2513ac2a9bacad97e3f7d08108c7adf6de240114
parentbd153422f28634bb6e53f13f80beb8289d405267 (diff)
downloadmusl-25ea9f712c30c32957de493d4711ee39d0bbb024.tar.gz
fix unintended observability of SIGABRT disposition reset via sigaction
the existing abort locking logic in sigaction only accounted for attempts to change the disposition, not attempts to observe the change made by abort. unfortunately the change is still observable in at least one other place: inheritance of signal dispositions across exec and posix_spawn. fixing these is a separate task and it's not even clear whether a complete fix is possible.
-rw-r--r--src/signal/sigaction.c17
1 files changed, 8 insertions, 9 deletions
diff --git a/src/signal/sigaction.c b/src/signal/sigaction.c
index a4737404..7232d4b9 100644
--- a/src/signal/sigaction.c
+++ b/src/signal/sigaction.c
@@ -21,6 +21,13 @@ int __libc_sigaction(int sig, const struct sigaction *restrict sa, struct sigact
{
struct k_sigaction ksa, ksa_old;
unsigned long set[_NSIG/(8*sizeof(long))];
+ /* Doing anything with the disposition of SIGABRT requires a lock,
+ * so that it cannot be changed while abort is terminating the
+ * process and so any change made by abort can't be observed. */
+ if (sig == SIGABRT) {
+ __block_all_sigs(&set);
+ LOCK(__abort_lock);
+ }
if (sa) {
if ((uintptr_t)sa->sa_handler > 1UL) {
a_or_l(handler_set+(sig-1)/(8*sizeof(long)),
@@ -44,21 +51,13 @@ int __libc_sigaction(int sig, const struct sigaction *restrict sa, struct sigact
a_store(&__eintr_valid_flag, 1);
}
}
- /* Changing the disposition of SIGABRT to anything but
- * SIG_DFL requires a lock, so that it cannot be changed
- * while abort is terminating the process after simply
- * calling raise(SIGABRT) failed to do so. */
- if (sa->sa_handler != SIG_DFL && sig == SIGABRT) {
- __block_all_sigs(&set);
- LOCK(__abort_lock);
- }
ksa.handler = sa->sa_handler;
ksa.flags = sa->sa_flags | SA_RESTORER;
ksa.restorer = (sa->sa_flags & SA_SIGINFO) ? __restore_rt : __restore;
memcpy(&ksa.mask, &sa->sa_mask, _NSIG/8);
}
int r = __syscall(SYS_rt_sigaction, sig, sa?&ksa:0, old?&ksa_old:0, _NSIG/8);
- if (sig == SIGABRT && sa && sa->sa_handler != SIG_DFL) {
+ if (sig == SIGABRT) {
UNLOCK(__abort_lock);
__restore_sigs(&set);
}