1 /* 2 * Copyright 2016-2019 The OpenSSL Project Authors. All Rights Reserved. 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> 14 #include <openssl/ssl.h> 15 #include <openssl/ossl_typ.h> 16 #include "crypto/dso_conf.h" 17 18 typedef void DSO; 19 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 *); 23 typedef int (*OPENSSL_init_crypto_t)(uint64_t, void *); 24 typedef int (*OPENSSL_atexit_t)(void (*handler)(void)); 25 typedef unsigned long (*ERR_get_error_t)(void); 26 typedef unsigned long (*OpenSSL_version_num_t)(void); 27 typedef DSO * (*DSO_dsobyaddr_t)(void (*addr)(void), int flags); 28 typedef int (*DSO_free_t)(DSO *dso); 29 30 typedef enum test_types_en { 31 CRYPTO_FIRST, 32 SSL_FIRST, 33 JUST_CRYPTO, 34 DSO_REFTEST, 35 NO_ATEXIT 36 } TEST_TYPE; 37 38 static TEST_TYPE test_type; 39 static const char *path_crypto; 40 static const char *path_ssl; 41 static const char *path_atexit; 42 43 #ifdef DSO_DLFCN 44 45 # include <dlfcn.h> 46 47 # define SHLIB_INIT NULL 48 49 typedef void *SHLIB; 50 typedef void *SHLIB_SYM; 51 52 static int shlib_load(const char *filename, SHLIB *lib) 53 { 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); 60 return *lib == NULL ? 0 : 1; 61 } 62 63 static int shlib_sym(SHLIB lib, const char *symname, SHLIB_SYM *sym) 64 { 65 *sym = dlsym(lib, symname); 66 return *sym != NULL; 67 } 68 69 static int shlib_close(SHLIB lib) 70 { 71 return dlclose(lib) != 0 ? 0 : 1; 72 } 73 #endif 74 75 #ifdef DSO_WIN32 76 77 # include <windows.h> 78 79 # define SHLIB_INIT 0 80 81 typedef HINSTANCE SHLIB; 82 typedef void *SHLIB_SYM; 83 84 static int shlib_load(const char *filename, SHLIB *lib) 85 { 86 *lib = LoadLibraryA(filename); 87 return *lib == NULL ? 0 : 1; 88 } 89 90 static int shlib_sym(SHLIB lib, const char *symname, SHLIB_SYM *sym) 91 { 92 *sym = (SHLIB_SYM)GetProcAddress(lib, symname); 93 return *sym != NULL; 94 } 95 96 static int shlib_close(SHLIB lib) 97 { 98 return FreeLibrary(lib) == 0 ? 0 : 1; 99 } 100 #endif 101 102 103 #if defined(DSO_DLFCN) || defined(DSO_WIN32) 104 105 static int atexit_handler_done = 0; 106 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); 116 atexit_handler_done++; 117 } 118 119 static int test_lib(void) 120 { 121 SHLIB ssllib = SHLIB_INIT; 122 SHLIB cryptolib = SHLIB_INIT; 123 SSL_CTX *ctx; 124 union { 125 void (*func)(void); 126 SHLIB_SYM sym; 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; 133 OPENSSL_atexit_t myOPENSSL_atexit; 134 int result = 0; 135 136 switch (test_type) { 137 case JUST_CRYPTO: 138 case DSO_REFTEST: 139 case NO_ATEXIT: 140 case CRYPTO_FIRST: 141 if (!shlib_load(path_crypto, &cryptolib)) { 142 fprintf(stderr, "Failed to load libcrypto\n"); 143 goto end; 144 } 145 if (test_type != CRYPTO_FIRST) 146 break; 147 /* Fall through */ 148 149 case SSL_FIRST: 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"); 158 goto end; 159 } 160 break; 161 } 162 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) { 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"); 184 goto end; 185 } 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; 189 ctx = mySSL_CTX_new(myTLS_method()); 190 if (ctx == NULL) { 191 fprintf(stderr, "Failed to create SSL_CTX\n"); 192 goto end; 193 } 194 mySSL_CTX_free(ctx); 195 } 196 197 if (!shlib_sym(cryptolib, "ERR_get_error", &symbols[0].sym) 198 || !shlib_sym(cryptolib, "OpenSSL_version_num", &symbols[1].sym) 199 || !shlib_sym(cryptolib, "OPENSSL_atexit", &symbols[2].sym)) { 200 fprintf(stderr, "Failed to load libcrypto symbols\n"); 201 goto end; 202 } 203 myERR_get_error = (ERR_get_error_t)symbols[0].func; 204 if (myERR_get_error() != 0) { 205 fprintf(stderr, "Unexpected ERR_get_error() response\n"); 206 goto end; 207 } 208 209 myOpenSSL_version_num = (OpenSSL_version_num_t)symbols[1].func; 210 if (myOpenSSL_version_num() != OPENSSL_VERSION_NUMBER) { 211 fprintf(stderr, "Invalid library version number\n"); 212 goto end; 213 } 214 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 221 if (test_type == DSO_REFTEST) { 222 # ifdef DSO_DLFCN 223 DSO_dsobyaddr_t myDSO_dsobyaddr; 224 DSO_free_t myDSO_free; 225 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 */ 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"); 237 goto end; 238 } 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 */ 246 hndl = myDSO_dsobyaddr((void (*)(void))myERR_get_error, 0); 247 if (hndl == NULL) { 248 fprintf(stderr, "DSO_dsobyaddr() failed\n"); 249 goto end; 250 } 251 myDSO_free(hndl); 252 } 253 # endif /* DSO_DLFCN */ 254 } 255 256 if (!shlib_close(cryptolib)) { 257 fprintf(stderr, "Failed to close libcrypto\n"); 258 goto end; 259 } 260 261 if (test_type == CRYPTO_FIRST || test_type == SSL_FIRST) { 262 if (!shlib_close(ssllib)) { 263 fprintf(stderr, "Failed to close libssl\n"); 264 goto end; 265 } 266 } 267 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; 281 } 282 # endif 283 # endif 284 285 result = 1; 286 end: 287 return result; 288 } 289 #endif 290 291 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[]) 298 { 299 const char *p; 300 301 if (argc != 5) { 302 fprintf(stderr, "Incorrect number of arguments\n"); 303 return 1; 304 } 305 306 p = argv[1]; 307 308 if (strcmp(p, "-crypto_first") == 0) { 309 test_type = CRYPTO_FIRST; 310 } else if (strcmp(p, "-ssl_first") == 0) { 311 test_type = SSL_FIRST; 312 } else if (strcmp(p, "-just_crypto") == 0) { 313 test_type = JUST_CRYPTO; 314 } else if (strcmp(p, "-dso_ref") == 0) { 315 test_type = DSO_REFTEST; 316 } else if (strcmp(p, "-no_atexit") == 0) { 317 test_type = NO_ATEXIT; 318 } else { 319 fprintf(stderr, "Unrecognised argument\n"); 320 return 1; 321 } 322 path_crypto = argv[2]; 323 path_ssl = argv[3]; 324 path_atexit = argv[4]; 325 if (path_crypto == NULL || path_ssl == NULL) { 326 fprintf(stderr, "Invalid libcrypto/libssl path\n"); 327 return 1; 328 } 329 330 #if defined(DSO_DLFCN) || defined(DSO_WIN32) 331 if (!test_lib()) 332 return 1; 333 #endif 334 return 0; 335 } 336