]>
Commit | Line | Data |
---|---|---|
b987d748 | 1 | /* |
72a7a702 | 2 | * Copyright 2016-2019 The OpenSSL Project Authors. All Rights Reserved. |
b987d748 MC |
3 | * |
4 | * Licensed under the OpenSSL license (the "License"). You may not use | |
5 | * this file except in compliance with the License. You can obtain a copy | |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
8 | */ | |
9 | ||
10 | #include <stdio.h> | |
11 | #include <string.h> | |
12 | #include <stdlib.h> | |
13 | #include <openssl/opensslv.h> | |
bdd07c78 RS |
14 | #include <openssl/ssl.h> |
15 | #include <openssl/ossl_typ.h> | |
b71fa7b3 | 16 | #include "internal/dso_conf.h" |
b987d748 | 17 | |
4af14b7b MK |
18 | typedef void DSO; |
19 | ||
b987d748 MC |
20 | typedef const SSL_METHOD * (*TLS_method_t)(void); |
21 | typedef SSL_CTX * (*SSL_CTX_new_t)(const SSL_METHOD *meth); | |
22 | typedef void (*SSL_CTX_free_t)(SSL_CTX *); | |
f5f3dfd5 MC |
23 | typedef int (*OPENSSL_init_crypto_t)(uint64_t, void *); |
24 | typedef int (*OPENSSL_atexit_t)(void (*handler)(void)); | |
b987d748 MC |
25 | typedef unsigned long (*ERR_get_error_t)(void); |
26 | typedef unsigned long (*OpenSSL_version_num_t)(void); | |
26db3246 | 27 | typedef DSO * (*DSO_dsobyaddr_t)(void (*addr)(void), int flags); |
4af14b7b | 28 | typedef int (*DSO_free_t)(DSO *dso); |
b987d748 | 29 | |
e0011aa8 RS |
30 | typedef enum test_types_en { |
31 | CRYPTO_FIRST, | |
32 | SSL_FIRST, | |
4af14b7b | 33 | JUST_CRYPTO, |
f5f3dfd5 MC |
34 | DSO_REFTEST, |
35 | NO_ATEXIT | |
e0011aa8 RS |
36 | } TEST_TYPE; |
37 | ||
38 | static TEST_TYPE test_type; | |
39 | static const char *path_crypto; | |
40 | static const char *path_ssl; | |
f5f3dfd5 | 41 | static const char *path_atexit; |
e0011aa8 | 42 | |
b987d748 MC |
43 | #ifdef DSO_DLFCN |
44 | ||
45 | # include <dlfcn.h> | |
46 | ||
e0011aa8 RS |
47 | # define SHLIB_INIT NULL |
48 | ||
bdd07c78 RS |
49 | typedef void *SHLIB; |
50 | typedef void *SHLIB_SYM; | |
b987d748 | 51 | |
62dd3351 | 52 | static int shlib_load(const char *filename, SHLIB *lib) |
b987d748 | 53 | { |
ea5def14 MK |
54 | int dl_flags = (RTLD_GLOBAL|RTLD_LAZY); |
55 | #ifdef _AIX | |
56 | if (filename[strlen(filename) - 1] == ')') | |
57 | dl_flags |= RTLD_MEMBER; | |
58 | #endif | |
59 | *lib = dlopen(filename, dl_flags); | |
bdd07c78 | 60 | return *lib == NULL ? 0 : 1; |
b987d748 MC |
61 | } |
62 | ||
63 | static int shlib_sym(SHLIB lib, const char *symname, SHLIB_SYM *sym) | |
64 | { | |
65 | *sym = dlsym(lib, symname); | |
b987d748 MC |
66 | return *sym != NULL; |
67 | } | |
68 | ||
69 | static int shlib_close(SHLIB lib) | |
70 | { | |
bdd07c78 | 71 | return dlclose(lib) != 0 ? 0 : 1; |
b987d748 | 72 | } |
bdd07c78 | 73 | #endif |
b987d748 | 74 | |
bdd07c78 | 75 | #ifdef DSO_WIN32 |
b987d748 MC |
76 | |
77 | # include <windows.h> | |
78 | ||
e0011aa8 RS |
79 | # define SHLIB_INIT 0 |
80 | ||
b987d748 | 81 | typedef HINSTANCE SHLIB; |
bdd07c78 | 82 | typedef void *SHLIB_SYM; |
b987d748 | 83 | |
62dd3351 | 84 | static int shlib_load(const char *filename, SHLIB *lib) |
b987d748 MC |
85 | { |
86 | *lib = LoadLibraryA(filename); | |
bdd07c78 | 87 | return *lib == NULL ? 0 : 1; |
b987d748 MC |
88 | } |
89 | ||
90 | static int shlib_sym(SHLIB lib, const char *symname, SHLIB_SYM *sym) | |
91 | { | |
92 | *sym = (SHLIB_SYM)GetProcAddress(lib, symname); | |
b987d748 MC |
93 | return *sym != NULL; |
94 | } | |
95 | ||
96 | static int shlib_close(SHLIB lib) | |
97 | { | |
bdd07c78 | 98 | return FreeLibrary(lib) == 0 ? 0 : 1; |
b987d748 | 99 | } |
b987d748 MC |
100 | #endif |
101 | ||
b987d748 | 102 | |
e0011aa8 | 103 | #if defined(DSO_DLFCN) || defined(DSO_WIN32) |
bdd07c78 | 104 | |
6b97cc6e MC |
105 | static int atexit_handler_done = 0; |
106 | ||
f5f3dfd5 MC |
107 | static void atexit_handler(void) |
108 | { | |
109 | FILE *atexit_file = fopen(path_atexit, "w"); | |
110 | ||
111 | if (atexit_file == NULL) | |
112 | return; | |
113 | ||
114 | fprintf(atexit_file, "atexit() run\n"); | |
115 | fclose(atexit_file); | |
6b97cc6e | 116 | atexit_handler_done++; |
f5f3dfd5 MC |
117 | } |
118 | ||
bdd07c78 | 119 | static int test_lib(void) |
b987d748 | 120 | { |
bdd07c78 RS |
121 | SHLIB ssllib = SHLIB_INIT; |
122 | SHLIB cryptolib = SHLIB_INIT; | |
b987d748 MC |
123 | SSL_CTX *ctx; |
124 | union { | |
bdd07c78 | 125 | void (*func)(void); |
b987d748 | 126 | SHLIB_SYM sym; |
bdd07c78 RS |
127 | } symbols[3]; |
128 | TLS_method_t myTLS_method; | |
129 | SSL_CTX_new_t mySSL_CTX_new; | |
130 | SSL_CTX_free_t mySSL_CTX_free; | |
131 | ERR_get_error_t myERR_get_error; | |
132 | OpenSSL_version_num_t myOpenSSL_version_num; | |
f5f3dfd5 | 133 | OPENSSL_atexit_t myOPENSSL_atexit; |
bdd07c78 RS |
134 | int result = 0; |
135 | ||
136 | switch (test_type) { | |
137 | case JUST_CRYPTO: | |
d6399c85 | 138 | case DSO_REFTEST: |
f5f3dfd5 | 139 | case NO_ATEXIT: |
bdd07c78 | 140 | case CRYPTO_FIRST: |
8ec0a2fe MC |
141 | if (!shlib_load(path_crypto, &cryptolib)) { |
142 | fprintf(stderr, "Failed to load libcrypto\n"); | |
bdd07c78 | 143 | goto end; |
8ec0a2fe MC |
144 | } |
145 | if (test_type != CRYPTO_FIRST) | |
146 | break; | |
147 | /* Fall through */ | |
148 | ||
bdd07c78 | 149 | case SSL_FIRST: |
8ec0a2fe MC |
150 | if (!shlib_load(path_ssl, &ssllib)) { |
151 | fprintf(stderr, "Failed to load libssl\n"); | |
152 | goto end; | |
153 | } | |
154 | if (test_type != SSL_FIRST) | |
155 | break; | |
156 | if (!shlib_load(path_crypto, &cryptolib)) { | |
157 | fprintf(stderr, "Failed to load libcrypto\n"); | |
bdd07c78 | 158 | goto end; |
8ec0a2fe | 159 | } |
bdd07c78 | 160 | break; |
b987d748 MC |
161 | } |
162 | ||
f5f3dfd5 MC |
163 | if (test_type == NO_ATEXIT) { |
164 | OPENSSL_init_crypto_t myOPENSSL_init_crypto; | |
165 | ||
166 | if (!shlib_sym(cryptolib, "OPENSSL_init_crypto", &symbols[0].sym)) { | |
167 | fprintf(stderr, "Failed to load OPENSSL_init_crypto symbol\n"); | |
168 | goto end; | |
169 | } | |
170 | myOPENSSL_init_crypto = (OPENSSL_init_crypto_t)symbols[0].func; | |
171 | if (!myOPENSSL_init_crypto(OPENSSL_INIT_NO_ATEXIT, NULL)) { | |
172 | fprintf(stderr, "Failed to initialise libcrypto\n"); | |
173 | goto end; | |
174 | } | |
175 | } | |
176 | ||
177 | if (test_type != JUST_CRYPTO | |
178 | && test_type != DSO_REFTEST | |
179 | && test_type != NO_ATEXIT) { | |
8ec0a2fe MC |
180 | if (!shlib_sym(ssllib, "TLS_method", &symbols[0].sym) |
181 | || !shlib_sym(ssllib, "SSL_CTX_new", &symbols[1].sym) | |
182 | || !shlib_sym(ssllib, "SSL_CTX_free", &symbols[2].sym)) { | |
183 | fprintf(stderr, "Failed to load libssl symbols\n"); | |
bdd07c78 | 184 | goto end; |
8ec0a2fe | 185 | } |
bdd07c78 RS |
186 | myTLS_method = (TLS_method_t)symbols[0].func; |
187 | mySSL_CTX_new = (SSL_CTX_new_t)symbols[1].func; | |
188 | mySSL_CTX_free = (SSL_CTX_free_t)symbols[2].func; | |
8ec0a2fe MC |
189 | ctx = mySSL_CTX_new(myTLS_method()); |
190 | if (ctx == NULL) { | |
191 | fprintf(stderr, "Failed to create SSL_CTX\n"); | |
bdd07c78 | 192 | goto end; |
8ec0a2fe | 193 | } |
bdd07c78 | 194 | mySSL_CTX_free(ctx); |
b987d748 MC |
195 | } |
196 | ||
8ec0a2fe | 197 | if (!shlib_sym(cryptolib, "ERR_get_error", &symbols[0].sym) |
f5f3dfd5 MC |
198 | || !shlib_sym(cryptolib, "OpenSSL_version_num", &symbols[1].sym) |
199 | || !shlib_sym(cryptolib, "OPENSSL_atexit", &symbols[2].sym)) { | |
8ec0a2fe | 200 | fprintf(stderr, "Failed to load libcrypto symbols\n"); |
bdd07c78 | 201 | goto end; |
8ec0a2fe | 202 | } |
bdd07c78 | 203 | myERR_get_error = (ERR_get_error_t)symbols[0].func; |
8ec0a2fe MC |
204 | if (myERR_get_error() != 0) { |
205 | fprintf(stderr, "Unexpected ERR_get_error() response\n"); | |
bdd07c78 | 206 | goto end; |
8ec0a2fe | 207 | } |
00c8f1b0 | 208 | |
bdd07c78 | 209 | myOpenSSL_version_num = (OpenSSL_version_num_t)symbols[1].func; |
8ec0a2fe MC |
210 | if (myOpenSSL_version_num() != OPENSSL_VERSION_NUMBER) { |
211 | fprintf(stderr, "Invalid library version number\n"); | |
bdd07c78 | 212 | goto end; |
8ec0a2fe | 213 | } |
bdd07c78 | 214 | |
f5f3dfd5 MC |
215 | myOPENSSL_atexit = (OPENSSL_atexit_t)symbols[2].func; |
216 | if (!myOPENSSL_atexit(atexit_handler)) { | |
217 | fprintf(stderr, "Failed to register atexit handler\n"); | |
218 | goto end; | |
219 | } | |
220 | ||
4af14b7b MK |
221 | if (test_type == DSO_REFTEST) { |
222 | # ifdef DSO_DLFCN | |
84e68a1b RL |
223 | DSO_dsobyaddr_t myDSO_dsobyaddr; |
224 | DSO_free_t myDSO_free; | |
225 | ||
4af14b7b MK |
226 | /* |
227 | * This is resembling the code used in ossl_init_base() and | |
228 | * OPENSSL_atexit() to block unloading the library after dlclose(). | |
229 | * We are not testing this on Windows, because it is done there in a | |
230 | * completely different way. Especially as a call to DSO_dsobyaddr() | |
231 | * will always return an error, because DSO_pathbyaddr() is not | |
232 | * implemented there. | |
233 | */ | |
8ec0a2fe MC |
234 | if (!shlib_sym(cryptolib, "DSO_dsobyaddr", &symbols[0].sym) |
235 | || !shlib_sym(cryptolib, "DSO_free", &symbols[1].sym)) { | |
236 | fprintf(stderr, "Unable to load DSO symbols\n"); | |
4af14b7b | 237 | goto end; |
8ec0a2fe | 238 | } |
4af14b7b MK |
239 | |
240 | myDSO_dsobyaddr = (DSO_dsobyaddr_t)symbols[0].func; | |
241 | myDSO_free = (DSO_free_t)symbols[1].func; | |
242 | ||
243 | { | |
244 | DSO *hndl; | |
245 | /* use known symbol from crypto module */ | |
8ec0a2fe MC |
246 | hndl = myDSO_dsobyaddr((void (*)(void))myERR_get_error, 0); |
247 | if (hndl == NULL) { | |
248 | fprintf(stderr, "DSO_dsobyaddr() failed\n"); | |
4af14b7b | 249 | goto end; |
8ec0a2fe | 250 | } |
cfaad171 | 251 | myDSO_free(hndl); |
4af14b7b MK |
252 | } |
253 | # endif /* DSO_DLFCN */ | |
254 | } | |
255 | ||
6b97cc6e MC |
256 | if (!shlib_close(cryptolib)) { |
257 | fprintf(stderr, "Failed to close libcrypto\n"); | |
258 | goto end; | |
259 | } | |
8ec0a2fe | 260 | |
6b97cc6e MC |
261 | if (test_type == CRYPTO_FIRST || test_type == SSL_FIRST) { |
262 | if (!shlib_close(ssllib)) { | |
8ec0a2fe MC |
263 | fprintf(stderr, "Failed to close libssl\n"); |
264 | goto end; | |
265 | } | |
6b97cc6e | 266 | } |
8ec0a2fe | 267 | |
6b97cc6e MC |
268 | # if defined(OPENSSL_NO_PINSHARED) \ |
269 | && defined(__GLIBC__) \ | |
270 | && defined(__GLIBC_PREREQ) \ | |
271 | && defined(OPENSSL_SYS_LINUX) | |
272 | # if __GLIBC_PREREQ(2, 3) | |
273 | /* | |
274 | * If we didn't pin the so then we are hopefully on a platform that supports | |
275 | * running atexit() on so unload. If not we might crash. We know this is | |
276 | * true on linux since glibc 2.2.3 | |
277 | */ | |
278 | if (test_type != NO_ATEXIT && atexit_handler_done != 1) { | |
279 | fprintf(stderr, "atexit() handler did not run\n"); | |
280 | goto end; | |
b987d748 | 281 | } |
6b97cc6e MC |
282 | # endif |
283 | # endif | |
b987d748 | 284 | |
bdd07c78 RS |
285 | result = 1; |
286 | end: | |
287 | return result; | |
288 | } | |
e0011aa8 RS |
289 | #endif |
290 | ||
b987d748 | 291 | |
8ec0a2fe MC |
292 | /* |
293 | * shlibloadtest should not use the normal test framework because we don't want | |
294 | * it to link against libcrypto (which the framework uses). The point of the | |
295 | * test is to check dynamic loading and unloading of libcrypto/libssl. | |
296 | */ | |
297 | int main(int argc, char *argv[]) | |
bdd07c78 | 298 | { |
8ec0a2fe MC |
299 | const char *p; |
300 | ||
f5f3dfd5 MC |
301 | if (argc != 5) { |
302 | fprintf(stderr, "Incorrect number of arguments\n"); | |
8ec0a2fe MC |
303 | return 1; |
304 | } | |
305 | ||
306 | p = argv[1]; | |
b987d748 | 307 | |
ad887416 | 308 | if (strcmp(p, "-crypto_first") == 0) { |
bdd07c78 | 309 | test_type = CRYPTO_FIRST; |
ad887416 | 310 | } else if (strcmp(p, "-ssl_first") == 0) { |
bdd07c78 | 311 | test_type = SSL_FIRST; |
ad887416 | 312 | } else if (strcmp(p, "-just_crypto") == 0) { |
bdd07c78 | 313 | test_type = JUST_CRYPTO; |
4af14b7b | 314 | } else if (strcmp(p, "-dso_ref") == 0) { |
d6399c85 | 315 | test_type = DSO_REFTEST; |
f5f3dfd5 MC |
316 | } else if (strcmp(p, "-no_atexit") == 0) { |
317 | test_type = NO_ATEXIT; | |
bdd07c78 | 318 | } else { |
f5f3dfd5 | 319 | fprintf(stderr, "Unrecognised argument\n"); |
8ec0a2fe MC |
320 | return 1; |
321 | } | |
322 | path_crypto = argv[2]; | |
323 | path_ssl = argv[3]; | |
f5f3dfd5 | 324 | path_atexit = argv[4]; |
8ec0a2fe MC |
325 | if (path_crypto == NULL || path_ssl == NULL) { |
326 | fprintf(stderr, "Invalid libcrypto/libssl path\n"); | |
327 | return 1; | |
b987d748 MC |
328 | } |
329 | ||
e0011aa8 | 330 | #if defined(DSO_DLFCN) || defined(DSO_WIN32) |
8ec0a2fe MC |
331 | if (!test_lib()) |
332 | return 1; | |
e0011aa8 | 333 | #endif |
8ec0a2fe | 334 | return 0; |
b987d748 | 335 | } |