• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
thread_run(LPVOID arg)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 
run_thread(thread_t * out_thread,void (* thread_func)(void))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 
wait_for_thread(thread_t thread)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 
thread_run(void * arg)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 
run_thread(thread_t * out_thread,void (* thread_func)(void))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 
wait_for_thread(thread_t thread)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 
once_init(void)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 
call_once_thread(void)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 
TEST(ThreadTest,Once)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 
TEST(ThreadTest,InitZeros)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 
thread_local_destructor(void * arg)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 
TEST(ThreadTest,ThreadLocal)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 
TEST(ThreadTest,RandState)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