1 #include "pthread_impl.h"
3 /* "rsyscall" is a mechanism by which a thread can synchronously force all
4 * other threads to perform an arbitrary syscall. It is necessary to work
5 * around the non-conformant implementation of setuid() et al on Linux,
6 * which affect only the calling thread and not the whole process. This
7 * implementation performs some tricks with signal delivery to work around
8 * the fact that it does not keep any list of threads in userspace. */
11 volatile int lock, hold, blocks, cnt;
18 static void rsyscall_handler(int sig, siginfo_t *si, void *ctx)
20 struct pthread *self = __pthread_self();
23 if (!rs.hold || rs.cnt == libc.threads_minus_1) return;
25 /* Threads which have already decremented themselves from the
26 * thread count must not increment rs.cnt or otherwise act. */
28 sigfillset(&((ucontext_t *)ctx)->uc_sigmask);
32 r = __syscall(rs.nr, rs.arg[0], rs.arg[1],
33 rs.arg[2], rs.arg[3], rs.arg[4], rs.arg[5]);
37 __wake(&rs.cnt, 1, 1);
39 __wait(&rs.hold, 0, 1, 1);
41 if (!rs.cnt) __wake(&rs.cnt, 1, 1);
44 int __rsyscall(int nr, long a, long b, long c, long d, long e, long f)
50 if (!libc.threads_minus_1)
51 return syscall(nr, a, b, c, d, e, f);
53 self = __pthread_self();
57 __wait(&rs.blocks, 0, i, 1);
60 __libc_sigprocmask(SIG_BLOCK, &set, &set);
63 struct sigaction sa = {
64 .sa_flags = SA_SIGINFO | SA_RESTART,
65 .sa_sigaction = rsyscall_handler,
68 sigfillset(&sa.sa_mask);
69 sa.sa_sigaction = rsyscall_handler;
70 __libc_sigaction(SIGSYSCALL, &sa, 0);
75 rs.arg[0] = a; rs.arg[1] = b;
76 rs.arg[2] = c; rs.arg[3] = d;
77 rs.arg[4] = d; rs.arg[5] = f;
82 /* Dispatch signals until all threads respond */
83 for (i=libc.threads_minus_1; i; i--)
84 sigqueue(self->pid, SIGSYSCALL, (union sigval){0});
85 while ((i=rs.cnt) < libc.threads_minus_1) {
86 sigqueue(self->pid, SIGSYSCALL, (union sigval){0});
87 __wait(&rs.cnt, 0, i, 1);
90 /* Handle any lingering signals with no-op */
91 __libc_sigprocmask(SIG_UNBLOCK, &set, &set);
93 /* Resume other threads' signal handlers and wait for them */
95 __wake(&rs.hold, -1, 0);
96 while((i=rs.cnt)) __wait(&rs.cnt, 0, i, 1);
98 if (rs.err) errno = rs.err, ret = -1;
99 else ret = syscall(nr, a, b, c, d, e, f);
105 void __rsyscall_lock()
108 while (rs.lock) __wait(&rs.lock, 0, 1, 1);
111 void __rsyscall_unlock()
114 if (rs.lock) __wake(&rs.blocks, 1, 1);