mirror of
https://github.com/openssl/openssl.git
synced 2025-01-18 13:44:20 +08:00
Add dladdr() for AIX
Although it deviates from the actual prototype of DSO_dsobyaddr(), this is now ISO C compliant and gcc -Wpedantic accepts the code. Added DATA segment checking to catch ptrgl virtual addresses. Avoid memleaks with every AIX/dladdr() call. Removed debug-fprintf()s. Added test case for DSO_dsobyaddr(), which will eventually call dladdr(). Removed unecessary AIX ifdefs again. The implementation can only lookup function symbols, no data symbols. Added PIC-flag to aix*-cc build targets. As AIX is missing a dladdr() implementation it is currently uncertain our exit()-handlers can still be called when the application exits. After dlclose() the whole library might have been unloaded already. Signed-off-by: Matthias Kraft <makr@gmx.eu> Reviewed-by: Richard Levitte <levitte@openssl.org> Reviewed-by: Rich Salz <rsalz@openssl.org> (Merged from https://github.com/openssl/openssl/pull/5668)
This commit is contained in:
parent
d316cdcf6d
commit
4af14b7b01
@ -1212,6 +1212,7 @@ my %targets = (
|
||||
perlasm_scheme => "aix32",
|
||||
dso_scheme => "dlfcn",
|
||||
shared_target => "aix-shared",
|
||||
shared_cflag => "-qpic",
|
||||
shared_ldflag => "-G",
|
||||
shared_extension => ".so.\$(SHLIB_VERSION_NUMBER)",
|
||||
arflags => "-X32 r",
|
||||
@ -1232,6 +1233,7 @@ my %targets = (
|
||||
perlasm_scheme => "aix64",
|
||||
dso_scheme => "dlfcn",
|
||||
shared_target => "aix-shared",
|
||||
shared_cflag => "-qpic",
|
||||
shared_ldflag => "-G",
|
||||
shared_extension => ".so.\$(SHLIB_VERSION_NUMBER)",
|
||||
arflags => "-X64 r",
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved.
|
||||
* Copyright 2000-2018 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the OpenSSL license (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
@ -26,7 +26,7 @@
|
||||
# endif
|
||||
# include <dlfcn.h>
|
||||
# define HAVE_DLINFO 1
|
||||
# if defined(_AIX) || defined(__CYGWIN__) || \
|
||||
# if defined(__CYGWIN__) || \
|
||||
defined(__SCO_VERSION__) || defined(_SCO_ELF) || \
|
||||
(defined(__osf__) && !defined(RTLD_NEXT)) || \
|
||||
(defined(__OpenBSD__) && !defined(RTLD_SELF)) || \
|
||||
@ -308,6 +308,73 @@ static int dladdr(void *address, Dl_info *dl)
|
||||
}
|
||||
# endif /* __sgi */
|
||||
|
||||
# ifdef _AIX
|
||||
/*-
|
||||
* See IBM's AIX Version 7.2, Technical Reference:
|
||||
* Base Operating System and Extensions, Volume 1 and 2
|
||||
* https://www.ibm.com/support/knowledgecenter/ssw_aix_72/com.ibm.aix.base/technicalreferences.htm
|
||||
*/
|
||||
# include <sys/ldr.h>
|
||||
# include <errno.h>
|
||||
/* ~ 64 * (sizeof(struct ld_info) + _XOPEN_PATH_MAX + _XOPEN_NAME_MAX) */
|
||||
# define DLFCN_LDINFO_SIZE 86976
|
||||
typedef struct Dl_info {
|
||||
const char *dli_fname;
|
||||
} Dl_info;
|
||||
/*
|
||||
* This dladdr()-implementation will also find the ptrgl (Pointer Glue) virtual
|
||||
* address of a function, which is just located in the DATA segment instead of
|
||||
* the TEXT segment.
|
||||
*/
|
||||
static int dladdr(void *addr, Dl_info *dl)
|
||||
{
|
||||
unsigned int found = 0;
|
||||
struct ld_info *ldinfos, *next_ldi, *this_ldi;
|
||||
|
||||
if ((ldinfos = (struct ld_info *)OPENSSL_malloc(DLFCN_LDINFO_SIZE)) == NULL) {
|
||||
errno = ENOMEM;
|
||||
dl->dli_fname = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((loadquery(L_GETINFO, (void *)ldinfos, DLFCN_LDINFO_SIZE)) < 0) {
|
||||
/*-
|
||||
* Error handling is done through errno and dlerror() reading errno:
|
||||
* ENOMEM (ldinfos buffer is too small),
|
||||
* EINVAL (invalid flags),
|
||||
* EFAULT (invalid ldinfos ptr)
|
||||
*/
|
||||
OPENSSL_free((void *)ldinfos);
|
||||
dl->dli_fname = NULL;
|
||||
return 0;
|
||||
}
|
||||
next_ldi = ldinfos;
|
||||
|
||||
do {
|
||||
this_ldi = next_ldi;
|
||||
if (((addr >= this_ldi->ldinfo_textorg)
|
||||
&& (addr < (this_ldi->ldinfo_textorg + this_ldi->ldinfo_textsize)))
|
||||
|| ((addr >= this_ldi->ldinfo_dataorg)
|
||||
&& (addr <
|
||||
(this_ldi->ldinfo_dataorg + this_ldi->ldinfo_datasize)))) {
|
||||
found = 1;
|
||||
/*
|
||||
* Ignoring the possibility of a member name and just returning
|
||||
* the path name. See docs: sys/ldr.h, loadquery() and
|
||||
* dlopen()/RTLD_MEMBER.
|
||||
*/
|
||||
if ((dl->dli_fname =
|
||||
OPENSSL_strdup(this_ldi->ldinfo_filename)) == NULL)
|
||||
errno = ENOMEM;
|
||||
} else {
|
||||
next_ldi = (char *)this_ldi + this_ldi->ldinfo_next;
|
||||
}
|
||||
} while (this_ldi->ldinfo_next && !found);
|
||||
OPENSSL_free((void *)ldinfos);
|
||||
return (found && dl->dli_fname != NULL);
|
||||
}
|
||||
# endif /* _AIX */
|
||||
|
||||
static int dlfcn_pathbyaddr(void *addr, char *path, int sz)
|
||||
{
|
||||
# ifdef HAVE_DLINFO
|
||||
@ -326,12 +393,19 @@ static int dlfcn_pathbyaddr(void *addr, char *path, int sz)
|
||||
|
||||
if (dladdr(addr, &dli)) {
|
||||
len = (int)strlen(dli.dli_fname);
|
||||
if (sz <= 0)
|
||||
if (sz <= 0) {
|
||||
# ifdef _AIX
|
||||
OPENSSL_free(dli.dli_fname);
|
||||
# endif
|
||||
return len + 1;
|
||||
}
|
||||
if (len >= sz)
|
||||
len = sz - 1;
|
||||
memcpy(path, dli.dli_fname, len);
|
||||
path[len++] = 0;
|
||||
# ifdef _AIX
|
||||
OPENSSL_free(dli.dli_fname);
|
||||
# endif
|
||||
return len;
|
||||
}
|
||||
|
||||
|
@ -119,6 +119,15 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_base)
|
||||
|
||||
ERR_set_mark();
|
||||
dso = DSO_dsobyaddr(&base_inited, DSO_FLAG_NO_UNLOAD_ON_FREE);
|
||||
# ifdef OPENSSL_INIT_DEBUG
|
||||
fprintf(stderr, "OPENSSL_INIT: obtained DSO reference? %s\n",
|
||||
(dso == NULL ? "No!" : "Yes."));
|
||||
/*
|
||||
* In case of No!, it is uncertain our exit()-handlers can still be
|
||||
* called. After dlclose() the whole library might have been unloaded
|
||||
* already.
|
||||
*/
|
||||
# endif
|
||||
DSO_free(dso);
|
||||
ERR_pop_to_mark();
|
||||
}
|
||||
@ -685,6 +694,12 @@ int OPENSSL_atexit(void (*handler)(void))
|
||||
|
||||
ERR_set_mark();
|
||||
dso = DSO_dsobyaddr(handlersym.sym, DSO_FLAG_NO_UNLOAD_ON_FREE);
|
||||
# ifdef OPENSSL_INIT_DEBUG
|
||||
fprintf(stderr,
|
||||
"OPENSSL_INIT: OPENSSL_atexit: obtained DSO reference? %s\n",
|
||||
(dso == NULL ? "No!" : "Yes."));
|
||||
/* See same code above in ossl_init_base() for an explanation. */
|
||||
# endif
|
||||
DSO_free(dso);
|
||||
ERR_pop_to_mark();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
#! /usr/bin/env perl
|
||||
# Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
|
||||
# Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the OpenSSL license (the "License"). You may not use
|
||||
# this file except in compliance with the License. You can obtain a copy
|
||||
@ -20,7 +20,7 @@ use configdata;
|
||||
|
||||
plan skip_all => "Test only supported in a shared build" if disabled("shared");
|
||||
|
||||
plan tests => 3;
|
||||
plan tests => 4;
|
||||
|
||||
my $libcrypto_idx = $unified_info{rename}->{libcrypto} // "libcrypto";
|
||||
my $libssl_idx = $unified_info{rename}->{libssl} // "libssl";
|
||||
@ -35,4 +35,6 @@ ok(run(test(["shlibloadtest", "-ssl_first", $libcrypto, $libssl])),
|
||||
"running shlibloadtest -ssl_first");
|
||||
ok(run(test(["shlibloadtest", "-just_crypto", $libcrypto, $libssl])),
|
||||
"running shlibloadtest -just_crypto");
|
||||
ok(run(test(["shlibloadtest", "-dso_ref", $libcrypto, $libssl])),
|
||||
"running shlibloadtest -dso_ref");
|
||||
|
||||
|
@ -15,16 +15,21 @@
|
||||
#include <openssl/ossl_typ.h>
|
||||
#include "testutil.h"
|
||||
|
||||
typedef void DSO;
|
||||
|
||||
typedef const SSL_METHOD * (*TLS_method_t)(void);
|
||||
typedef SSL_CTX * (*SSL_CTX_new_t)(const SSL_METHOD *meth);
|
||||
typedef void (*SSL_CTX_free_t)(SSL_CTX *);
|
||||
typedef unsigned long (*ERR_get_error_t)(void);
|
||||
typedef unsigned long (*OpenSSL_version_num_t)(void);
|
||||
typedef DSO * (*DSO_dsobyaddr_t)(void (*addr)(), int flags);
|
||||
typedef int (*DSO_free_t)(DSO *dso);
|
||||
|
||||
typedef enum test_types_en {
|
||||
CRYPTO_FIRST,
|
||||
SSL_FIRST,
|
||||
JUST_CRYPTO
|
||||
JUST_CRYPTO,
|
||||
DSO_REFTEST
|
||||
} TEST_TYPE;
|
||||
|
||||
static TEST_TYPE test_type;
|
||||
@ -102,6 +107,8 @@ static int test_lib(void)
|
||||
SSL_CTX_free_t mySSL_CTX_free;
|
||||
ERR_get_error_t myERR_get_error;
|
||||
OpenSSL_version_num_t myOpenSSL_version_num;
|
||||
DSO_dsobyaddr_t myDSO_dsobyaddr;
|
||||
DSO_free_t myDSO_free;
|
||||
int result = 0;
|
||||
|
||||
switch (test_type) {
|
||||
@ -119,9 +126,13 @@ static int test_lib(void)
|
||||
|| !TEST_true(shlib_load(path_crypto, &cryptolib)))
|
||||
goto end;
|
||||
break;
|
||||
case DSO_REFTEST:
|
||||
if (!TEST_true(shlib_load(path_crypto, &cryptolib)))
|
||||
goto end;
|
||||
break;
|
||||
}
|
||||
|
||||
if (test_type != JUST_CRYPTO) {
|
||||
if (test_type != JUST_CRYPTO && test_type != DSO_REFTEST) {
|
||||
if (!TEST_true(shlib_sym(ssllib, "TLS_method", &symbols[0].sym))
|
||||
|| !TEST_true(shlib_sym(ssllib, "SSL_CTX_new", &symbols[1].sym))
|
||||
|| !TEST_true(shlib_sym(ssllib, "SSL_CTX_free", &symbols[2].sym)))
|
||||
@ -157,6 +168,34 @@ static int test_lib(void)
|
||||
OPENSSL_VERSION_NUMBER & ~COMPATIBILITY_MASK)
|
||||
goto end;
|
||||
|
||||
if (test_type == DSO_REFTEST) {
|
||||
# ifdef DSO_DLFCN
|
||||
/*
|
||||
* This is resembling the code used in ossl_init_base() and
|
||||
* OPENSSL_atexit() to block unloading the library after dlclose().
|
||||
* We are not testing this on Windows, because it is done there in a
|
||||
* completely different way. Especially as a call to DSO_dsobyaddr()
|
||||
* will always return an error, because DSO_pathbyaddr() is not
|
||||
* implemented there.
|
||||
*/
|
||||
if (!TEST_true(shlib_sym(cryptolib, "DSO_dsobyaddr", &symbols[0].sym))
|
||||
|| !TEST_true(shlib_sym(cryptolib, "DSO_free",
|
||||
&symbols[1].sym)))
|
||||
goto end;
|
||||
|
||||
myDSO_dsobyaddr = (DSO_dsobyaddr_t)symbols[0].func;
|
||||
myDSO_free = (DSO_free_t)symbols[1].func;
|
||||
|
||||
{
|
||||
DSO *hndl;
|
||||
/* use known symbol from crypto module */
|
||||
if (!TEST_ptr(hndl = DSO_dsobyaddr((void (*)())ERR_get_error, 0)))
|
||||
goto end;
|
||||
DSO_free(hndl);
|
||||
}
|
||||
# endif /* DSO_DLFCN */
|
||||
}
|
||||
|
||||
switch (test_type) {
|
||||
case JUST_CRYPTO:
|
||||
if (!TEST_true(shlib_close(cryptolib)))
|
||||
@ -172,6 +211,10 @@ static int test_lib(void)
|
||||
|| !TEST_true(shlib_close(cryptolib)))
|
||||
goto end;
|
||||
break;
|
||||
case DSO_REFTEST:
|
||||
if (!TEST_true(shlib_close(cryptolib)))
|
||||
goto end;
|
||||
break;
|
||||
}
|
||||
|
||||
result = 1;
|
||||
@ -191,6 +234,8 @@ int setup_tests(void)
|
||||
test_type = SSL_FIRST;
|
||||
} else if (strcmp(p, "-just_crypto") == 0) {
|
||||
test_type = JUST_CRYPTO;
|
||||
} else if (strcmp(p, "-dso_ref") == 0) {
|
||||
test_type = JUST_CRYPTO;
|
||||
} else {
|
||||
TEST_error("Unrecognised argument");
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user