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 #include <gtest/gtest.h> 18 19 #include <openssl/crypto.h> 20 #include <openssl/rand.h> 21 22 #include "test/test_util.h" 23 24 25 #if !defined(OPENSSL_NO_THREADS) 26 27 #if defined(OPENSSL_WINDOWS) 28 29 OPENSSL_MSVC_PRAGMA(warning(push, 3)) 30 #include <windows.h> 31 OPENSSL_MSVC_PRAGMA(warning(pop)) 32 33 typedef HANDLE thread_t; 34 35 static DWORD WINAPI thread_run(LPVOID arg) { 36 void (*thread_func)(void); 37 /* VC really doesn't like casting between data and function pointers. */ 38 OPENSSL_memcpy(&thread_func, &arg, sizeof(thread_func)); 39 thread_func(); 40 return 0; 41 } 42 43 static int run_thread(thread_t *out_thread, void (*thread_func)(void)) { 44 void *arg; 45 /* VC really doesn't like casting between data and function pointers. */ 46 OPENSSL_memcpy(&arg, &thread_func, sizeof(arg)); 47 48 *out_thread = CreateThread(NULL /* security attributes */, 49 0 /* default stack size */, thread_run, arg, 50 0 /* run immediately */, NULL /* ignore id */); 51 return *out_thread != NULL; 52 } 53 54 static int wait_for_thread(thread_t thread) { 55 return WaitForSingleObject(thread, INFINITE) == 0; 56 } 57 58 #else 59 60 #include <pthread.h> 61 #include <string.h> 62 #include <time.h> 63 64 typedef pthread_t thread_t; 65 66 static void *thread_run(void *arg) { 67 void (*thread_func)(void) = reinterpret_cast<void (*)(void)>(arg); 68 thread_func(); 69 return NULL; 70 } 71 72 static int run_thread(thread_t *out_thread, void (*thread_func)(void)) { 73 return pthread_create(out_thread, NULL /* default attributes */, thread_run, 74 reinterpret_cast<void *>(thread_func)) == 0; 75 } 76 77 static int wait_for_thread(thread_t thread) { 78 return pthread_join(thread, NULL) == 0; 79 } 80 81 #endif /* OPENSSL_WINDOWS */ 82 83 static unsigned g_once_init_called = 0; 84 85 static void once_init(void) { 86 g_once_init_called++; 87 88 /* Sleep briefly so one |call_once_thread| instance will call |CRYPTO_once| 89 * while the other is running this function. */ 90 #if defined(OPENSSL_WINDOWS) 91 Sleep(1 /* milliseconds */); 92 #else 93 struct timespec req; 94 OPENSSL_memset(&req, 0, sizeof(req)); 95 req.tv_nsec = 1000000; 96 nanosleep(&req, NULL); 97 #endif 98 } 99 100 static CRYPTO_once_t g_test_once = CRYPTO_ONCE_INIT; 101 102 static void call_once_thread(void) { 103 CRYPTO_once(&g_test_once, once_init); 104 } 105 106 static CRYPTO_once_t once_init_value = CRYPTO_ONCE_INIT; 107 static CRYPTO_once_t once_bss; 108 109 static struct CRYPTO_STATIC_MUTEX mutex_init_value = CRYPTO_STATIC_MUTEX_INIT; 110 static struct CRYPTO_STATIC_MUTEX mutex_bss; 111 112 static CRYPTO_EX_DATA_CLASS ex_data_class_value = CRYPTO_EX_DATA_CLASS_INIT; 113 static CRYPTO_EX_DATA_CLASS ex_data_class_bss; 114 115 TEST(ThreadTest, Once) { 116 ASSERT_EQ(0u, g_once_init_called) 117 << "g_once_init_called was non-zero at start."; 118 119 thread_t thread1, thread2; 120 ASSERT_TRUE(run_thread(&thread1, call_once_thread)); 121 ASSERT_TRUE(run_thread(&thread2, call_once_thread)); 122 ASSERT_TRUE(wait_for_thread(thread1)); 123 ASSERT_TRUE(wait_for_thread(thread2)); 124 125 CRYPTO_once(&g_test_once, once_init); 126 127 EXPECT_EQ(1u, g_once_init_called); 128 } 129 130 TEST(ThreadTest, InitZeros) { 131 if (FIPS_mode()) { 132 /* Our FIPS tooling currently requires that |CRYPTO_ONCE_INIT|, 133 * |CRYPTO_STATIC_MUTEX_INIT| and |CRYPTO_EX_DATA_CLASS| are all zeros and 134 * so can be placed in the BSS section. */ 135 EXPECT_EQ(Bytes((uint8_t *)&once_bss, sizeof(once_bss)), 136 Bytes((uint8_t *)&once_init_value, sizeof(once_init_value))); 137 EXPECT_EQ(Bytes((uint8_t *)&mutex_bss, sizeof(mutex_bss)), 138 Bytes((uint8_t *)&mutex_init_value, sizeof(mutex_init_value))); 139 EXPECT_EQ( 140 Bytes((uint8_t *)&ex_data_class_bss, sizeof(ex_data_class_bss)), 141 Bytes((uint8_t *)&ex_data_class_value, sizeof(ex_data_class_value))); 142 } 143 } 144 145 static int g_test_thread_ok = 0; 146 static unsigned g_destructor_called_count = 0; 147 148 static void thread_local_destructor(void *arg) { 149 if (arg == NULL) { 150 return; 151 } 152 153 unsigned *count = reinterpret_cast<unsigned*>(arg); 154 (*count)++; 155 } 156 157 TEST(ThreadTest, ThreadLocal) { 158 ASSERT_EQ(nullptr, CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_TEST)) 159 << "Thread-local data was non-NULL at start."; 160 161 thread_t thread; 162 ASSERT_TRUE(run_thread(&thread, []() { 163 if (CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_TEST) != NULL || 164 !CRYPTO_set_thread_local(OPENSSL_THREAD_LOCAL_TEST, 165 &g_destructor_called_count, 166 thread_local_destructor) || 167 CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_TEST) != 168 &g_destructor_called_count) { 169 return; 170 } 171 172 g_test_thread_ok = 1; 173 })); 174 ASSERT_TRUE(wait_for_thread(thread)); 175 176 EXPECT_TRUE(g_test_thread_ok) << "Thread-local data didn't work in thread."; 177 EXPECT_EQ(1u, g_destructor_called_count); 178 179 // Create a no-op thread to test test that the thread destructor function 180 // works even if thread-local storage wasn't used for a thread. 181 ASSERT_TRUE(run_thread(&thread, []() {})); 182 ASSERT_TRUE(wait_for_thread(thread)); 183 } 184 185 TEST(ThreadTest, RandState) { 186 /* In FIPS mode, rand.c maintains a linked-list of thread-local data because 187 * we're required to clear it on process exit. This test exercises removing a 188 * value from that list. */ 189 uint8_t buf[1]; 190 RAND_bytes(buf, sizeof(buf)); 191 192 thread_t thread; 193 ASSERT_TRUE(run_thread(&thread, []() { 194 uint8_t buf2[1]; 195 RAND_bytes(buf2, sizeof(buf2)); 196 })); 197 ASSERT_TRUE(wait_for_thread(thread)); 198 } 199 200 #endif /* !OPENSSL_NO_THREADS */ 201