xref: /aosp_15_r20/external/libcap/psx/psx.c (revision 2810ac1b38eead2603277920c78344c84ddf3aff)
1 /*
2  * Copyright (c) 2019-21 Andrew G Morgan <[email protected]>
3  *
4  * This file contains a collection of routines that perform thread
5  * synchronization to ensure that a whole process is running as a
6  * single privilege entity - independent of the number of pthreads.
7  *
8  * The whole file would be unnecessary if glibc exported an explicit
9  * psx_syscall()-like function that leveraged the nptl:setxid
10  * mechanism to synchronize thread state over the whole process.
11  */
12 #undef _POSIX_C_SOURCE
13 #define _POSIX_C_SOURCE 199309L
14 
15 #ifndef _GNU_SOURCE
16 #define _GNU_SOURCE
17 #endif
18 
19 #include <errno.h>
20 #include <pthread.h>
21 #include <sched.h>
22 #include <signal.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <sys/syscall.h>
29 
30 #include "psx_syscall.h"
31 
32 #ifdef _PSX_DEBUG_MEMORY
33 
_psx_calloc(const char * file,const int line,size_t nmemb,size_t size)34 static void *_psx_calloc(const char *file, const int line,
35 			 size_t nmemb, size_t size) {
36     void *ptr = calloc(nmemb, size);
37     fprintf(stderr, "psx:%d:%s:%d: calloc(%ld, %ld) -> %p\n", gettid(),
38 	    file, line, (long int)nmemb, (long int)size, ptr);
39     return ptr;
40 }
41 
_psx_free(const char * file,const int line,void * ptr)42 static void _psx_free(const char *file, const int line, void *ptr) {
43     fprintf(stderr, "psx:%d:%s:%d: free(%p)\n", gettid(), file, line, ptr);
44     return free(ptr);
45 }
46 
47 #define calloc(a, b)  _psx_calloc(__FILE__, __LINE__, a, b)
48 #define free(a)       _psx_free(__FILE__, __LINE__, a)
49 
50 #endif /* def _PSX_DEBUG_MEMORY */
51 
52 /*
53  * psx_load_syscalls() can be weakly defined in dependent libraries to
54  * provide a mechanism for a library to optionally leverage this psx
55  * mechanism. Specifically, when libcap calls psx_load_sycalls() it
56  * provides a weakly declared default that maps its system calls to
57  * the regular system call functions. However, when linked with psx,
58  * this function here overrides the syscalls to be the psx ones.
59  */
psx_load_syscalls(long int (** syscall_fn)(long int,long int,long int,long int),long int (** syscall6_fn)(long int,long int,long int,long int,long int,long int,long int))60 void psx_load_syscalls(long int (**syscall_fn)(long int,
61 					      long int, long int, long int),
62 		       long int (**syscall6_fn)(long int,
63 					       long int, long int, long int,
64 					       long int, long int, long int))
65 {
66     *syscall_fn = psx_syscall3;
67     *syscall6_fn = psx_syscall6;
68 }
69 
70 /*
71  * type to keep track of registered threads.
72  */
73 typedef struct registered_thread_s {
74     struct registered_thread_s *next, *prev;
75     pthread_t thread;
76     pthread_mutex_t mu;
77     int pending;
78     int gone;
79     long int retval;
80     pid_t tid;
81 } registered_thread_t;
82 
83 static pthread_once_t psx_tracker_initialized = PTHREAD_ONCE_INIT;
84 
85 typedef enum {
86     _PSX_IDLE = 0,
87     _PSX_SETUP = 1,
88     _PSX_SYSCALL = 2,
89     _PSX_CREATE = 3,
90     _PSX_INFORK = 4,
91     _PSX_EXITING = 5,
92 } psx_tracker_state_t;
93 
94 /*
95  * This global structure holds the global coordination state for
96  * libcap's psx_posix_syscall() support.
97  */
98 static struct psx_tracker_s {
99     int has_forked;
100 
101     pthread_mutex_t state_mu;
102     pthread_cond_t cond; /* this is only used to wait on 'state' changes */
103     psx_tracker_state_t state;
104     int initialized;
105     int psx_sig;
106     psx_sensitivity_t sensitivity;
107 
108     struct {
109 	long syscall_nr;
110 	long arg1, arg2, arg3, arg4, arg5, arg6;
111 	int six;
112 	int active;
113     } cmd;
114 
115     struct sigaction sig_action;
116     struct sigaction chained_action;
117     registered_thread_t *root;
118 } psx_tracker;
119 
120 /*
121  * psx_action_key is used for thread local storage of the thread's
122  * registration.
123  */
124 pthread_key_t psx_action_key;
125 
126 /*
127  * psx_do_registration called locked and creates a tracker entry for
128  * the current thread with a TLS specific key pointing at the threads
129  * specific tracker.
130  */
psx_do_registration(void)131 static void *psx_do_registration(void) {
132     registered_thread_t *node = calloc(1, sizeof(registered_thread_t));
133     if (node == NULL) {
134 	perror("unable to register psx handler");
135 	_exit(1);
136     }
137     pthread_mutex_init(&node->mu, NULL);
138     node->thread = pthread_self();
139     pthread_setspecific(psx_action_key, node);
140     node->next = psx_tracker.root;
141     if (node->next) {
142 	node->next->prev = node;
143     }
144     psx_tracker.root = node;
145     return node;
146 }
147 
148 /*
149  * psx_posix_syscall_actor performs the system call on the targeted
150  * thread and signals it is no longer pending.
151  */
psx_posix_syscall_actor(int signum,siginfo_t * info,void * ignore)152 static void psx_posix_syscall_actor(int signum, siginfo_t *info, void *ignore) {
153     /* bail early if this isn't something we recognize */
154     if (signum != psx_tracker.psx_sig || !psx_tracker.cmd.active ||
155 	info == NULL || info->si_code != SI_TKILL || info->si_pid != getpid()) {
156 	if (psx_tracker.chained_action.sa_sigaction != 0) {
157 	    psx_tracker.chained_action.sa_sigaction(signum, info, ignore);
158 	}
159 	return;
160     }
161 
162     long int retval;
163     if (!psx_tracker.cmd.six) {
164 	retval = syscall(psx_tracker.cmd.syscall_nr,
165 			 psx_tracker.cmd.arg1,
166 			 psx_tracker.cmd.arg2,
167 			 psx_tracker.cmd.arg3);
168     } else {
169 	retval = syscall(psx_tracker.cmd.syscall_nr,
170 			 psx_tracker.cmd.arg1,
171 			 psx_tracker.cmd.arg2,
172 			 psx_tracker.cmd.arg3,
173 			 psx_tracker.cmd.arg4,
174 			 psx_tracker.cmd.arg5,
175 			 psx_tracker.cmd.arg6);
176     }
177 
178     /*
179      * This handler can only be called on registered threads which
180      * have had this specific defined at start-up. (But see the
181      * subsequent test.)
182      */
183     registered_thread_t *ref = pthread_getspecific(psx_action_key);
184     if (ref) {
185 	pthread_mutex_lock(&ref->mu);
186 	ref->pending = 0;
187 	ref->retval = retval;
188 	ref->tid = syscall(SYS_gettid);
189 	pthread_mutex_unlock(&ref->mu);
190     } /*
191        * else thread must be dying and its psx_action_key has already
192        * been cleaned up.
193        */
194 }
195 
196 /*
197  * Some forward declarations for the initialization
198  * psx_syscall_start() routine.
199  */
200 static void _psx_cleanup(void);
201 static void _psx_prepare_fork(void);
202 static void _psx_fork_completed(void);
203 static void _psx_forked_child(void);
204 int __wrap_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
205 			  void *(*start_routine) (void *), void *arg);
206 
207 /*
208  * psx requires this function to be provided by the linkage wrapping.
209  */
210 extern int __real_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
211 				 void *(*start_routine) (void *), void *arg);
212 
213 /*
214  * psx_confirm_sigaction reconfirms that the psx handler is the first
215  * handler to respond to the psx signal. It assumes that
216  * psx_tracker.psx_sig has been set.
217  */
psx_confirm_sigaction(void)218 static void psx_confirm_sigaction(void) {
219     sigset_t mask, orig;
220     struct sigaction existing_sa;
221 
222     /*
223      * Block interrupts while potentially rewriting the handler.
224      */
225     sigemptyset(&mask);
226     sigaddset(&mask, psx_tracker.psx_sig);
227     sigprocmask(SIG_BLOCK, &mask, &orig);
228 
229     sigaction(psx_tracker.psx_sig, NULL, &existing_sa);
230     if (existing_sa.sa_sigaction != psx_posix_syscall_actor) {
231 	memcpy(&psx_tracker.chained_action, &existing_sa, sizeof(struct sigaction));
232 	psx_tracker.sig_action.sa_sigaction = psx_posix_syscall_actor;
233 	sigemptyset(&psx_tracker.sig_action.sa_mask);
234 	psx_tracker.sig_action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART;
235 	sigaction(psx_tracker.psx_sig, &psx_tracker.sig_action, NULL);
236     }
237 
238     sigprocmask(SIG_SETMASK, &orig, NULL);
239 }
240 
241 /*
242  * psx_syscall_start initializes the subsystem including initializing
243  * the mutex.
244  */
psx_syscall_start(void)245 static void psx_syscall_start(void) {
246     pthread_mutex_init(&psx_tracker.state_mu, NULL);
247     pthread_cond_init(&psx_tracker.cond, NULL);
248     pthread_key_create(&psx_action_key, NULL);
249     pthread_atfork(_psx_prepare_fork, _psx_fork_completed, _psx_forked_child);
250 
251     /*
252      * All sorts of things are assumed by Linux and glibc and/or musl
253      * about signal handlers and which can be blocked. Go has its own
254      * idiosyncrasies too. We tried SIGRTMAX until
255      *
256      *   https://bugzilla.kernel.org/show_bug.cgi?id=210533
257      *
258      * Our current strategy is to aggressively intercept SIGSYS.
259      */
260     psx_tracker.psx_sig = SIGSYS;
261 
262     psx_confirm_sigaction();
263     psx_do_registration(); /* register the main thread. */
264     atexit(_psx_cleanup);
265 
266     psx_tracker.initialized = 1;
267 }
268 
269 /*
270  * This is the only way this library globally locks. Note, this is not
271  * to be confused with psx_sig (interrupt) blocking - which is
272  * performed around thread creation and when the signal handler is
273  * being confirmed.
274  */
psx_lock(void)275 static void psx_lock(void)
276 {
277     pthread_once(&psx_tracker_initialized, psx_syscall_start);
278     pthread_mutex_lock(&psx_tracker.state_mu);
279 }
280 
281 /*
282  * This is the only way this library unlocks.
283  */
psx_unlock(void)284 static void psx_unlock(void)
285 {
286     pthread_mutex_unlock(&psx_tracker.state_mu);
287 }
288 
289 /*
290  * under lock perform a state transition. Changing state is generally
291  * done via this function. However, there is a single exception in
292  * _psx_cleanup().
293  */
psx_new_state(psx_tracker_state_t was,psx_tracker_state_t is)294 static void psx_new_state(psx_tracker_state_t was, psx_tracker_state_t is)
295 {
296     psx_lock();
297     while (psx_tracker.state != was) {
298 	pthread_cond_wait(&psx_tracker.cond, &psx_tracker.state_mu);
299     }
300     psx_tracker.state = is;
301     if (is == _PSX_IDLE) {
302 	/* only announce newly idle states since that is all we wait for */
303 	pthread_cond_signal(&psx_tracker.cond);
304     }
305     psx_unlock();
306 }
307 
psx_syscall3(long int syscall_nr,long int arg1,long int arg2,long int arg3)308 long int psx_syscall3(long int syscall_nr,
309 		      long int arg1, long int arg2, long int arg3) {
310     return psx_syscall(syscall_nr, arg1, arg2, arg3);
311 }
312 
psx_syscall6(long int syscall_nr,long int arg1,long int arg2,long int arg3,long int arg4,long int arg5,long int arg6)313 long int psx_syscall6(long int syscall_nr,
314 		      long int arg1, long int arg2, long int arg3,
315 		      long int arg4, long int arg5, long int arg6) {
316     return psx_syscall(syscall_nr, arg1, arg2, arg3, arg4, arg5, arg6);
317 }
318 
_psx_prepare_fork(void)319 static void _psx_prepare_fork(void) {
320     /*
321      * obtain global lock - we don't want any syscalls while the fork
322      * is occurring since it may interfere with the preparation for
323      * the fork.
324      */
325     psx_new_state(_PSX_IDLE, _PSX_INFORK);
326 }
327 
_psx_fork_completed(void)328 static void _psx_fork_completed(void) {
329     /*
330      * The only way we can get here is if state is _PSX_INFORK and was
331      * previously _PSX_IDLE. Now that the fork has completed, the
332      * parent can continue as if it hadn't happened - the forked child
333      * does not tie its security state to that of the parent process
334      * and threads.
335      *
336      * We don't strictly need to change the psx_tracker.state since we
337      * hold the mutex over the fork, but we do to make deadlock
338      * debugging easier.
339      */
340     psx_new_state(_PSX_INFORK, _PSX_IDLE);
341 }
342 
_psx_forked_child(void)343 static void _psx_forked_child(void) {
344     /*
345      * The only way we can get here is if state is _PSX_INFORK and was
346      * previously _PSX_IDLE. However, none of the registered threads
347      * exist in this newly minted child process, so we have to reset
348      * the tracking structure to avoid any confusion. We also scuttle
349      * any chance of the PSX API working on more than one thread in
350      * the child by leaving the state as _PSX_INFORK. We do support
351      * all psx_syscall()s by reverting to them being direct in the
352      * fork()ed child.
353      *
354      * We do this because the glibc man page for fork() suggests that
355      * only a subset of things will work post fork(). Specifically,
356      * only a "async-signal-safe functions (see signal-safety(7))
357      * until such time as it calls execve(2)" can be relied upon. That
358      * man page suggests that you can't expect mutexes to work: "not
359      * async-signal-safe because it uses pthread_mutex_lock(3)
360      * internally.".
361      */
362     registered_thread_t *next, *old_root;
363     old_root = psx_tracker.root;
364     psx_tracker.root = NULL;
365 
366     psx_tracker.has_forked = 1;
367 
368     for (; old_root; old_root = next) {
369 	next = old_root->next;
370 	memset(old_root, 0, sizeof(*old_root));
371 	free(old_root);
372     }
373 }
374 
375 /*
376  * called locked to unregister a node from the tracker.
377  */
psx_do_unregister(registered_thread_t * node)378 static void psx_do_unregister(registered_thread_t *node) {
379     if (psx_tracker.root == node) {
380 	psx_tracker.root = node->next;
381     }
382     if (node->next) {
383 	node->next->prev = node->prev;
384     }
385     if (node->prev) {
386 	node->prev->next = node->next;
387     }
388     pthread_mutex_destroy(&node->mu);
389     memset(node, 0, sizeof(*node));
390     free(node);
391 }
392 
393 typedef struct {
394     void *(*fn)(void *);
395     void *arg;
396     sigset_t sigbits;
397 } psx_starter_t;
398 
399 /*
400  * _psx_exiting is used to cleanup the node for the thread on its exit
401  * path. This is needed for musl libc:
402  *
403  *    https://bugzilla.kernel.org/show_bug.cgi?id=208477
404  *
405  * and likely wise for glibc too:
406  *
407  *    https://sourceware.org/bugzilla/show_bug.cgi?id=12889
408  */
_psx_exiting(void * node)409 static void _psx_exiting(void *node) {
410     /*
411      * Until we are in the _PSX_EXITING state, we must not block the
412      * psx_sig interrupt for this dying thread. That is, until this
413      * exiting thread can set ref->gone to 1, this dying thread is
414      * still participating in the psx syscall distribution.
415      *
416      * See https://github.com/golang/go/issues/42494 for a situation
417      * where this code is called with psx_tracker.psx_sig blocked.
418      */
419     sigset_t sigbit, orig_sigbits;
420     sigemptyset(&sigbit);
421     pthread_sigmask(SIG_UNBLOCK, &sigbit, &orig_sigbits);
422     sigaddset(&sigbit, psx_tracker.psx_sig);
423     pthread_sigmask(SIG_UNBLOCK, &sigbit, NULL);
424 
425     /*
426      * With psx_tracker.psx_sig unblocked we can wait until this
427      * thread can enter the _PSX_EXITING state.
428      */
429     psx_new_state(_PSX_IDLE, _PSX_EXITING);
430 
431     /*
432      * We now indicate that this thread is no longer participating in
433      * the psx mechanism.
434      */
435     registered_thread_t *ref = node;
436     pthread_mutex_lock(&ref->mu);
437     ref->gone = 1;
438     pthread_mutex_unlock(&ref->mu);
439 
440     /*
441      * At this point, we can restore the calling sigmask to whatever
442      * the caller thought was appropriate for a dying thread to have.
443      */
444     pthread_sigmask(SIG_SETMASK, &orig_sigbits, NULL);
445 
446     /*
447      * Allow the rest of the psx system to carry on as per normal.
448      */
449     psx_new_state(_PSX_EXITING, _PSX_IDLE);
450 }
451 
452 /*
453  * _psx_start_fn is a trampoline for the intended start function, it
454  * is called blocked (_PSX_CREATE), but releases the block before
455  * calling starter->fn. Before releasing the block, the TLS specific
456  * attributes are initialized for use by the interrupt handler under
457  * the psx mutex, so it doesn't race with an interrupt received by
458  * this thread and the interrupt handler does not need to poll for
459  * that specific attribute to be present (which is problematic during
460  * thread shutdown).
461  */
_psx_start_fn(void * data)462 static void *_psx_start_fn(void *data) {
463     void *node = psx_do_registration();
464 
465     psx_new_state(_PSX_CREATE, _PSX_IDLE);
466 
467     psx_starter_t *starter = data;
468     pthread_sigmask(SIG_SETMASK, &starter->sigbits, NULL);
469     void *(*fn)(void *) = starter->fn;
470     void *arg = starter->arg;
471 
472     memset(data, 0, sizeof(*starter));
473     free(data);
474 
475     void *ret;
476 
477     pthread_cleanup_push(_psx_exiting, node);
478     ret = fn(arg);
479     pthread_cleanup_pop(1);
480 
481     return ret;
482 }
483 
484 /*
485  * __wrap_pthread_create is the wrapped destination of all regular
486  * pthread_create calls.
487  */
__wrap_pthread_create(pthread_t * thread,const pthread_attr_t * attr,void * (* start_routine)(void *),void * arg)488 int __wrap_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
489 			  void *(*start_routine) (void *), void *arg) {
490     psx_starter_t *starter = calloc(1, sizeof(psx_starter_t));
491     if (starter == NULL) {
492 	perror("failed at thread creation");
493 	exit(1);
494     }
495     starter->fn = start_routine;
496     starter->arg = arg;
497     /*
498      * Until we are in the _PSX_IDLE state and locked, we must not
499      * block the psx_sig interrupt for this parent thread. Arrange
500      * that parent thread and newly created one can restore signal
501      * mask.
502      */
503     sigset_t sigbit, orig_sigbits;
504     sigemptyset(&sigbit);
505     pthread_sigmask(SIG_UNBLOCK, &sigbit, &starter->sigbits);
506     sigaddset(&sigbit, psx_tracker.psx_sig);
507     pthread_sigmask(SIG_UNBLOCK, &sigbit, &orig_sigbits);
508 
509     psx_new_state(_PSX_IDLE, _PSX_CREATE);
510 
511     /*
512      * until the child thread has been blessed with its own TLS
513      * specific attribute(s) we prevent either the parent thread or
514      * the new one from experiencing a PSX interrupt.
515      */
516     pthread_sigmask(SIG_BLOCK, &sigbit, NULL);
517 
518     int ret = __real_pthread_create(thread, attr, _psx_start_fn, starter);
519     if (ret > 0) {
520 	psx_new_state(_PSX_CREATE, _PSX_IDLE);
521 	memset(starter, 0, sizeof(*starter));
522 	free(starter);
523     } /* else unlock happens in _psx_start_fn */
524 
525     /* the parent can once again receive psx interrupt signals */
526     pthread_sigmask(SIG_SETMASK, &orig_sigbits, NULL);
527 
528     return ret;
529 }
530 
531 /*
532  * __psx_immediate_syscall does one syscall using the current
533  * process.
534  */
__psx_immediate_syscall(long int syscall_nr,int count,long int * arg)535 static long int __psx_immediate_syscall(long int syscall_nr,
536 					int count, long int *arg) {
537     psx_tracker.cmd.syscall_nr = syscall_nr;
538     psx_tracker.cmd.arg1 = count > 0 ? arg[0] : 0;
539     psx_tracker.cmd.arg2 = count > 1 ? arg[1] : 0;
540     psx_tracker.cmd.arg3 = count > 2 ? arg[2] : 0;
541 
542     if (count > 3) {
543 	psx_tracker.cmd.six = 1;
544 	psx_tracker.cmd.arg4 = arg[3];
545 	psx_tracker.cmd.arg5 = count > 4 ? arg[4] : 0;
546 	psx_tracker.cmd.arg6 = count > 5 ? arg[5] : 0;
547 	return syscall(syscall_nr,
548 		      psx_tracker.cmd.arg1,
549 		      psx_tracker.cmd.arg2,
550 		      psx_tracker.cmd.arg3,
551 		      psx_tracker.cmd.arg4,
552 		      psx_tracker.cmd.arg5,
553 		      psx_tracker.cmd.arg6);
554     }
555 
556     psx_tracker.cmd.six = 0;
557     return syscall(syscall_nr, psx_tracker.cmd.arg1,
558 		   psx_tracker.cmd.arg2, psx_tracker.cmd.arg3);
559 }
560 
561 /*
562  * __psx_syscall performs the syscall on the current thread and if no
563  * error is detected it ensures that the syscall is also performed on
564  * all (other) registered threads. The return code is the value for
565  * the first invocation. It uses a trick to figure out how many
566  * arguments the user has supplied. The other half of the trick is
567  * provided by the macro psx_syscall() in the <sys/psx_syscall.h>
568  * file. The trick is the 7th optional argument (8th over all) to
569  * __psx_syscall is the count of arguments supplied to psx_syscall.
570  *
571  * User:
572  *                       psx_syscall(nr, a, b);
573  * Expanded by macro to:
574  *                       __psx_syscall(nr, a, b, 6, 5, 4, 3, 2, 1, 0);
575  * The eighth arg is now ------------------------------------^
576  */
__psx_syscall(long int syscall_nr,...)577 long int __psx_syscall(long int syscall_nr, ...) {
578     long int arg[7];
579     int i;
580 
581     va_list aptr;
582     va_start(aptr, syscall_nr);
583     for (i = 0; i < 7; i++) {
584 	arg[i] = va_arg(aptr, long int);
585     }
586     va_end(aptr);
587 
588     int count = arg[6];
589     if (count < 0 || count > 6) {
590 	errno = EINVAL;
591 	return -1;
592     }
593 
594     if (psx_tracker.has_forked) {
595 	return __psx_immediate_syscall(syscall_nr, count, arg);
596     }
597 
598     psx_new_state(_PSX_IDLE, _PSX_SETUP);
599     psx_confirm_sigaction();
600 
601     long int ret;
602 
603     ret = __psx_immediate_syscall(syscall_nr, count, arg);
604     if (ret == -1 || !psx_tracker.initialized) {
605 	psx_new_state(_PSX_SETUP, _PSX_IDLE);
606 	goto defer;
607     }
608 
609     int restore_errno = errno;
610 
611     psx_new_state(_PSX_SETUP, _PSX_SYSCALL);
612     psx_tracker.cmd.active = 1;
613 
614     pthread_t self = pthread_self();
615     registered_thread_t *next = NULL, *ref;
616 
617     psx_lock();
618     for (ref = psx_tracker.root; ref; ref = next) {
619 	next = ref->next;
620 	if (ref->thread == self) {
621 	    continue;
622 	}
623 	pthread_mutex_lock(&ref->mu);
624 	ref->pending = 1;
625 	int gone = ref->gone;
626 	if (!gone) {
627 	    gone = pthread_kill(ref->thread, psx_tracker.psx_sig) != 0;
628 	}
629 	pthread_mutex_unlock(&ref->mu);
630 	if (!gone) {
631 	    continue;
632 	}
633 	/*
634 	 * need to remove invalid thread id from linked list
635 	 */
636 	psx_do_unregister(ref);
637     }
638     psx_unlock();
639 
640     int mismatch = 0;
641     for (;;) {
642 	int waiting = 0;
643 	psx_lock();
644 	for (ref = psx_tracker.root; ref; ref = next) {
645 	    next = ref->next;
646 	    if (ref->thread == self) {
647 		continue;
648 	    }
649 
650 	    pthread_mutex_lock(&ref->mu);
651 	    int pending = ref->pending;
652 	    int gone = ref->gone;
653 	    if (!gone) {
654 		if (pending) {
655 		    gone = (pthread_kill(ref->thread, 0) != 0);
656 		} else {
657 		    mismatch |= (ref->retval != ret);
658 		}
659 	    }
660 	    pthread_mutex_unlock(&ref->mu);
661 	    if (!gone) {
662 		waiting += pending;
663 		continue;
664 	    }
665 	    /*
666 	     * need to remove invalid thread id from linked list
667 	     */
668 	    psx_do_unregister(ref);
669 	}
670 	psx_unlock();
671 	if (!waiting) {
672 	    break;
673 	}
674 	sched_yield();
675     }
676 
677     psx_tracker.cmd.active = 0;
678     if (mismatch) {
679 	psx_lock();
680 	switch (psx_tracker.sensitivity) {
681 	case PSX_IGNORE:
682 	    break;
683 	default:
684 	    fprintf(stderr, "psx_syscall result differs.\n");
685 	    if (psx_tracker.cmd.six) {
686 		fprintf(stderr, "trap:%ld a123456=[%ld,%ld,%ld,%ld,%ld,%ld]\n",
687 			psx_tracker.cmd.syscall_nr,
688 			psx_tracker.cmd.arg1,
689 			psx_tracker.cmd.arg2,
690 			psx_tracker.cmd.arg3,
691 			psx_tracker.cmd.arg4,
692 			psx_tracker.cmd.arg5,
693 			psx_tracker.cmd.arg6);
694 	    } else {
695 		fprintf(stderr, "trap:%ld a123=[%ld,%ld,%ld]\n",
696 			psx_tracker.cmd.syscall_nr,
697 			psx_tracker.cmd.arg1,
698 			psx_tracker.cmd.arg2,
699 			psx_tracker.cmd.arg3);
700 	    }
701 	    fprintf(stderr, "results:");
702 	    for (ref = psx_tracker.root; ref; ref = next) {
703 		next = ref->next;
704 		if (ref->thread == self) {
705 		    continue;
706 		}
707 		if (ret != ref->retval) {
708 		    fprintf(stderr, " %d={%ld}", ref->tid, ref->retval);
709 		}
710 	    }
711 	    fprintf(stderr, " wanted={%ld}\n", ret);
712 	    if (psx_tracker.sensitivity == PSX_WARNING) {
713 		break;
714 	    }
715 	    pthread_kill(self, SIGSYS);
716 	}
717 	psx_unlock();
718     }
719     errno = restore_errno;
720     psx_new_state(_PSX_SYSCALL, _PSX_IDLE);
721 
722 defer:
723     return ret;
724 }
725 
726 /*
727  * _psx_cleanup its called when the program exits. It is used to free
728  * any memory used by the thread tracker.
729  */
_psx_cleanup(void)730 static void _psx_cleanup(void) {
731     registered_thread_t *ref, *next;
732 
733     /*
734      * We enter the exiting state. Unlike exiting a single thread we
735      * never leave this state since this cleanup is only done at
736      * program exit.
737      */
738     psx_lock();
739     while (psx_tracker.state != _PSX_IDLE && psx_tracker.state != _PSX_INFORK) {
740 	pthread_cond_wait(&psx_tracker.cond, &psx_tracker.state_mu);
741     }
742     psx_tracker.state = _PSX_EXITING;
743     psx_unlock();
744 
745     for (ref = psx_tracker.root; ref; ref = next) {
746 	next = ref->next;
747 	psx_do_unregister(ref);
748     }
749 }
750 
751 /*
752  * Change the PSX sensitivity level. If the threads appear to have
753  * diverged in behavior, this can cause the library to notify the
754  * user.
755  */
psx_set_sensitivity(psx_sensitivity_t level)756 int psx_set_sensitivity(psx_sensitivity_t level) {
757     if (level < PSX_IGNORE || level > PSX_ERROR) {
758 	errno = EINVAL;
759 	return -1;
760     }
761     psx_lock();
762     psx_tracker.sensitivity = level;
763     psx_unlock();
764     return 0;
765 }
766