1 #include <pthread.h>
2 #include <signal.h>
3 #include <setjmp.h>
4 #include <errno.h>
5 #include <assert.h>
6
7 static sigjmp_buf env;
8
9 /*
10 * Starting with glibc 2.20 some pthread calls may execute
11 * an xend instruction unconditionally when a lock is used in
12 * a way that is invalid so defined a sigill handler that can
13 * convert these invalid instructions to a normal error.
14 */
sigill_handler(int signum,siginfo_t * siginfo,void * sigcontext)15 static void sigill_handler( int signum, siginfo_t *siginfo, void *sigcontext ) {
16 unsigned char *pc = siginfo->si_addr;
17 assert( pc[0] == 0x0f && pc[1] == 0x01 && pc[2] == 0xd5 );
18 siglongjmp( env, EPERM );
19 }
20
21 /*
22 * Same as above, but in case we do recognize the xend,
23 * but detect it is invalid (used outside a transaction)
24 * and generate a segv. Unfortunately then si_addr is,
25 * just zero, so we cannot add an assert/sanity check.
26 */
segv_handler(int signum,siginfo_t * siginfo,void * sigcontext)27 static void segv_handler( int signum, siginfo_t *siginfo, void *sigcontext ) {
28 siglongjmp( env, EPERM );
29 }
30
31 /*
32 * Wrapper for pthread_rwlock_unlock which may execute xend
33 * unconditionally when used on a lock that is not locked.
34 *
35 * Note that we return 0 instead of EPERM because that is what
36 * glibc normally does - error reporting is optional.
37 */
safe_pthread_rwlock_unlock(pthread_rwlock_t * rwlock)38 static int safe_pthread_rwlock_unlock( pthread_rwlock_t *rwlock ) {
39 struct sigaction sa_ill, sa_segv;
40 struct sigaction oldsa_ill, oldsa_segv;
41 int r;
42
43 sa_ill.sa_handler = NULL;
44 sa_ill.sa_sigaction = sigill_handler;
45 sigemptyset( &sa_ill.sa_mask );
46 sa_ill.sa_flags = SA_SIGINFO;
47
48 sigaction( SIGILL, &sa_ill, &oldsa_ill );
49
50 sa_segv.sa_handler = NULL;
51 sa_segv.sa_sigaction = segv_handler;
52 sigemptyset( &sa_segv.sa_mask );
53 sa_segv.sa_flags = SA_SIGINFO;
54
55 sigaction( SIGSEGV, &sa_segv, &oldsa_segv );
56
57 if ( ( r = sigsetjmp( env, 1 ) ) == 0 ) {
58 r = pthread_rwlock_unlock( rwlock );
59 } else {
60 r = 0;
61 }
62
63 sigaction( SIGILL, &oldsa_ill, NULL );
64 sigaction( SIGSEGV, &oldsa_segv, NULL );
65
66 return r;
67 }
68
69 #define pthread_rwlock_unlock safe_pthread_rwlock_unlock
70