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