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