1 | /* Copyright (c) 2015, Google Inc. |
2 | * |
3 | * Permission to use, copy, modify, and/or distribute this software for any |
4 | * purpose with or without fee is hereby granted, provided that the above |
5 | * copyright notice and this permission notice appear in all copies. |
6 | * |
7 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
8 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
9 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
10 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
11 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
12 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
13 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ |
14 | |
15 | #include "internal.h" |
16 | |
17 | #if defined(OPENSSL_PTHREADS) |
18 | |
19 | #include <pthread.h> |
20 | #include <stdlib.h> |
21 | #include <string.h> |
22 | |
23 | #include <openssl/mem.h> |
24 | #include <openssl/type_check.h> |
25 | |
26 | |
27 | OPENSSL_STATIC_ASSERT(sizeof(CRYPTO_MUTEX) >= sizeof(pthread_rwlock_t), |
28 | "CRYPTO_MUTEX is too small" ); |
29 | |
30 | void CRYPTO_MUTEX_init(CRYPTO_MUTEX *lock) { |
31 | if (pthread_rwlock_init((pthread_rwlock_t *) lock, NULL) != 0) { |
32 | abort(); |
33 | } |
34 | } |
35 | |
36 | void CRYPTO_MUTEX_lock_read(CRYPTO_MUTEX *lock) { |
37 | if (pthread_rwlock_rdlock((pthread_rwlock_t *) lock) != 0) { |
38 | abort(); |
39 | } |
40 | } |
41 | |
42 | void CRYPTO_MUTEX_lock_write(CRYPTO_MUTEX *lock) { |
43 | if (pthread_rwlock_wrlock((pthread_rwlock_t *) lock) != 0) { |
44 | abort(); |
45 | } |
46 | } |
47 | |
48 | void CRYPTO_MUTEX_unlock_read(CRYPTO_MUTEX *lock) { |
49 | if (pthread_rwlock_unlock((pthread_rwlock_t *) lock) != 0) { |
50 | abort(); |
51 | } |
52 | } |
53 | |
54 | void CRYPTO_MUTEX_unlock_write(CRYPTO_MUTEX *lock) { |
55 | if (pthread_rwlock_unlock((pthread_rwlock_t *) lock) != 0) { |
56 | abort(); |
57 | } |
58 | } |
59 | |
60 | void CRYPTO_MUTEX_cleanup(CRYPTO_MUTEX *lock) { |
61 | pthread_rwlock_destroy((pthread_rwlock_t *) lock); |
62 | } |
63 | |
64 | void CRYPTO_STATIC_MUTEX_lock_read(struct CRYPTO_STATIC_MUTEX *lock) { |
65 | if (pthread_rwlock_rdlock(&lock->lock) != 0) { |
66 | abort(); |
67 | } |
68 | } |
69 | |
70 | void CRYPTO_STATIC_MUTEX_lock_write(struct CRYPTO_STATIC_MUTEX *lock) { |
71 | if (pthread_rwlock_wrlock(&lock->lock) != 0) { |
72 | abort(); |
73 | } |
74 | } |
75 | |
76 | void CRYPTO_STATIC_MUTEX_unlock_read(struct CRYPTO_STATIC_MUTEX *lock) { |
77 | if (pthread_rwlock_unlock(&lock->lock) != 0) { |
78 | abort(); |
79 | } |
80 | } |
81 | |
82 | void CRYPTO_STATIC_MUTEX_unlock_write(struct CRYPTO_STATIC_MUTEX *lock) { |
83 | if (pthread_rwlock_unlock(&lock->lock) != 0) { |
84 | abort(); |
85 | } |
86 | } |
87 | |
88 | void CRYPTO_once(CRYPTO_once_t *once, void (*init)(void)) { |
89 | if (pthread_once(once, init) != 0) { |
90 | abort(); |
91 | } |
92 | } |
93 | |
94 | static pthread_mutex_t g_destructors_lock = PTHREAD_MUTEX_INITIALIZER; |
95 | static thread_local_destructor_t g_destructors[NUM_OPENSSL_THREAD_LOCALS]; |
96 | |
97 | // thread_local_destructor is called when a thread exits. It releases thread |
98 | // local data for that thread only. |
99 | static void thread_local_destructor(void *arg) { |
100 | if (arg == NULL) { |
101 | return; |
102 | } |
103 | |
104 | thread_local_destructor_t destructors[NUM_OPENSSL_THREAD_LOCALS]; |
105 | if (pthread_mutex_lock(&g_destructors_lock) != 0) { |
106 | return; |
107 | } |
108 | OPENSSL_memcpy(destructors, g_destructors, sizeof(destructors)); |
109 | pthread_mutex_unlock(&g_destructors_lock); |
110 | |
111 | unsigned i; |
112 | void **pointers = arg; |
113 | for (i = 0; i < NUM_OPENSSL_THREAD_LOCALS; i++) { |
114 | if (destructors[i] != NULL) { |
115 | destructors[i](pointers[i]); |
116 | } |
117 | } |
118 | |
119 | OPENSSL_free(pointers); |
120 | } |
121 | |
122 | static pthread_once_t g_thread_local_init_once = PTHREAD_ONCE_INIT; |
123 | static pthread_key_t g_thread_local_key; |
124 | static int g_thread_local_key_created = 0; |
125 | |
126 | // OPENSSL_DANGEROUS_RELEASE_PTHREAD_KEY can be defined to cause |
127 | // |pthread_key_delete| to be called in a destructor function. This can be |
128 | // useful for programs that dlclose BoringSSL. |
129 | // |
130 | // Note that dlclose()ing BoringSSL is not supported and will leak memory: |
131 | // thread-local values will be leaked as well as anything initialised via a |
132 | // once. The |pthread_key_t| is destroyed because they run out very quickly, |
133 | // while the other leaks are slow, and this allows code that happens to use |
134 | // dlclose() despite all the problems to continue functioning. |
135 | // |
136 | // This is marked "dangerous" because it can cause multi-threaded processes to |
137 | // crash (even if they don't use dlclose): if the destructor runs while other |
138 | // threads are still executing then they may end up using an invalid key to |
139 | // access thread-local variables. |
140 | // |
141 | // This may be removed after February 2020. |
142 | #if defined(OPENSSL_DANGEROUS_RELEASE_PTHREAD_KEY) && \ |
143 | (defined(__GNUC__) || defined(__clang__)) |
144 | // thread_key_destructor is called when the library is unloaded with dlclose. |
145 | static void thread_key_destructor(void) __attribute__((destructor, unused)); |
146 | static void thread_key_destructor(void) { |
147 | if (g_thread_local_key_created) { |
148 | g_thread_local_key_created = 0; |
149 | pthread_key_delete(g_thread_local_key); |
150 | } |
151 | } |
152 | #endif |
153 | |
154 | static void thread_local_init(void) { |
155 | g_thread_local_key_created = |
156 | pthread_key_create(&g_thread_local_key, thread_local_destructor) == 0; |
157 | } |
158 | |
159 | void *CRYPTO_get_thread_local(thread_local_data_t index) { |
160 | CRYPTO_once(&g_thread_local_init_once, thread_local_init); |
161 | if (!g_thread_local_key_created) { |
162 | return NULL; |
163 | } |
164 | |
165 | void **pointers = pthread_getspecific(g_thread_local_key); |
166 | if (pointers == NULL) { |
167 | return NULL; |
168 | } |
169 | return pointers[index]; |
170 | } |
171 | |
172 | int CRYPTO_set_thread_local(thread_local_data_t index, void *value, |
173 | thread_local_destructor_t destructor) { |
174 | CRYPTO_once(&g_thread_local_init_once, thread_local_init); |
175 | if (!g_thread_local_key_created) { |
176 | destructor(value); |
177 | return 0; |
178 | } |
179 | |
180 | void **pointers = pthread_getspecific(g_thread_local_key); |
181 | if (pointers == NULL) { |
182 | pointers = OPENSSL_malloc(sizeof(void *) * NUM_OPENSSL_THREAD_LOCALS); |
183 | if (pointers == NULL) { |
184 | destructor(value); |
185 | return 0; |
186 | } |
187 | OPENSSL_memset(pointers, 0, sizeof(void *) * NUM_OPENSSL_THREAD_LOCALS); |
188 | if (pthread_setspecific(g_thread_local_key, pointers) != 0) { |
189 | OPENSSL_free(pointers); |
190 | destructor(value); |
191 | return 0; |
192 | } |
193 | } |
194 | |
195 | if (pthread_mutex_lock(&g_destructors_lock) != 0) { |
196 | destructor(value); |
197 | return 0; |
198 | } |
199 | g_destructors[index] = destructor; |
200 | pthread_mutex_unlock(&g_destructors_lock); |
201 | |
202 | pointers[index] = value; |
203 | return 1; |
204 | } |
205 | |
206 | #endif // OPENSSL_PTHREADS |
207 | |