fix race condition in sigqueue
authorRich Felker <dalias@aerifal.cx>
Sun, 31 Jul 2011 01:11:31 +0000 (21:11 -0400)
committerRich Felker <dalias@aerifal.cx>
Sun, 31 Jul 2011 01:11:31 +0000 (21:11 -0400)
this race is fundamentally due to linux's bogus requirement that
userspace, rather than kernelspace, fill in the siginfo structure. an
intervening signal handler that calls fork could cause both the parent
and child process to send signals claiming to be from the parent,
which could in turn have harmful effects depending on what the
recipient does with the signal. we simply block all signals for the
interval between getuid and sigqueue syscalls (much like what raise()
does already) to prevent the race and make the getuid/sigqueue pair
atomic.

this will be a non-issue if linux is fixed to validate the siginfo
structure or fill it in from kernelspace.

src/signal/sigqueue.c

index aeac4875b3bd3d9aeecd0b3f28ffb752146924ab..bdb12856a965ef14f86667265b80e5d70281c3b6 100644 (file)
@@ -1,16 +1,22 @@
 #include <signal.h>
 #include <string.h>
 #include <unistd.h>
+#include <stdint.h>
 #include "syscall.h"
 
 int sigqueue(pid_t pid, int sig, const union sigval value)
 {
        siginfo_t si;
+       sigset_t set;
+       int r;
        memset(&si, 0, sizeof si);
        si.si_signo = sig;
        si.si_code = SI_QUEUE;
        si.si_value = value;
-       si.si_pid = getpid();
        si.si_uid = getuid();
-       return syscall(SYS_rt_sigqueueinfo, pid, sig, &si);
+       pthread_sigmask(SIG_BLOCK, (void *)(uint64_t[1]){-1}, &set);
+       si.si_pid = getpid();
+       r = syscall(SYS_rt_sigqueueinfo, pid, sig, &si);
+       pthread_sigmask(SIG_SETMASK, &set, 0);
+       return r;
 }