You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kudu.apache.org by to...@apache.org on 2018/02/28 09:09:12 UTC
kudu git commit: KUDU-2328. Fix crash at startup with OpenSSL FIPS
mode
Repository: kudu
Updated Branches:
refs/heads/master 3b2df01c0 -> e9448dac5
KUDU-2328. Fix crash at startup with OpenSSL FIPS mode
The wrapping of libdl functions added by commit
d9e7037138646e3efb331af98c6982de13294c4b has a problem if any other
dynamic initializer calls dlopen or dlclose. It turns out that OpenSSL
in FIPS mode does indeed do that, leading to a crash with a stack like:
#0 0x0000000000000000 in ?? ()
#1 0x0000000001b45d23 in dlopen ()
#2 0x00007f1f444967ba in ?? () from /lib64/libcrypto.so.1.0.0
#3 0x00007f1f44496857 in ?? () from /lib64/libcrypto.so.1.0.0
#4 0x00007f1f44496bfe in FIPS_module_mode_set () from /lib64/libcrypto.so.1.0.0
#5 0x00007f1f4437216c in FIPS_mode_set () from /lib64/libcrypto.so.1.0.0
#6 0x00007f1f4436eb60 in OPENSSL_init_library () from /lib64/libcrypto.so.1.0.0
#7 0x00007f1f450a2c0a in call_init.part () from /lib64/ld-linux-x86-64.so.2
#8 0x00007f1f450a2cf3 in _dl_init () from /lib64/ld-linux-x86-64.so.2
#9 0x00007f1f4509518a in _dl_start_user () from /lib64/ld-linux-x86-64.so.2
The fix takes the same approach we already used to workaround a similar issue
with the ASAN runtime, but generalizes it to all of our wrapped functions.
Change-Id: I10a04126411f51b4d8e290a6b061aa585aad0769
Reviewed-on: http://gerrit.cloudera.org:8080/9460
Tested-by: Todd Lipcon <to...@apache.org>
Reviewed-by: Alexey Serbin <as...@cloudera.com>
Project: http://git-wip-us.apache.org/repos/asf/kudu/repo
Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/e9448dac
Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/e9448dac
Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/e9448dac
Branch: refs/heads/master
Commit: e9448dac5d4d70a4c6e05c3d8e98c4c5d8c3fc14
Parents: 3b2df01
Author: Todd Lipcon <to...@apache.org>
Authored: Tue Feb 27 23:41:17 2018 -0800
Committer: Todd Lipcon <to...@apache.org>
Committed: Wed Feb 28 09:08:55 2018 +0000
----------------------------------------------------------------------
src/kudu/util/debug/unwind_safeness.cc | 38 ++++++++++++++++++++---------
1 file changed, 27 insertions(+), 11 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/kudu/blob/e9448dac/src/kudu/util/debug/unwind_safeness.cc
----------------------------------------------------------------------
diff --git a/src/kudu/util/debug/unwind_safeness.cc b/src/kudu/util/debug/unwind_safeness.cc
index 3339189..4e233ef 100644
--- a/src/kudu/util/debug/unwind_safeness.cc
+++ b/src/kudu/util/debug/unwind_safeness.cc
@@ -32,8 +32,6 @@
#include <glog/logging.h>
-#include "kudu/gutil/port.h"
-
#define CALL_ORIG(func_name, ...) \
((decltype(&func_name))g_orig_ ## func_name)(__VA_ARGS__)
@@ -41,6 +39,10 @@ typedef int (*dl_iterate_phdr_cbtype)(struct dl_phdr_info *, size_t, void *);
namespace {
+// Whether InitializeIfNecessary() has been called.
+bool g_initted;
+
+// The original versions of our wrapped functions.
void* g_orig_dlopen;
void* g_orig_dlclose;
#ifndef __APPLE__
@@ -68,13 +70,32 @@ void *dlsym_or_die(const char *sym) {
return ret;
}
+// Initialize the global variables which store the original references. This is
+// set up as a constructor so that we're guaranteed to call this before main()
+// while we are still single-threaded.
+//
+// NOTE: We _also_ call explicitly this from each of the wrappers, because
+// there are some cases where the constructors of dynamic libraries may call
+// dlopen, and there is no guarantee that our own constructor runs before
+// the constructor of other libraries.
+//
+// A couple examples of the above:
+//
+// 1) In ASAN builds, the sanitizer runtime ends up calling dl_iterate_phdr from its
+// initialization.
+// 2) OpenSSL in FIPS mode calls dlopen() within its constructor.
__attribute__((constructor))
-void Init(void) {
+void InitIfNecessary() {
+ // Dynamic library initialization is always single-threaded, so there's no
+ // need for any synchronization here.
+ if (g_initted) return;
+
g_orig_dlopen = dlsym_or_die("dlopen");
g_orig_dlclose = dlsym_or_die("dlclose");
#ifndef __APPLE__ // This function doesn't exist on macOS.
g_orig_dl_iterate_phdr = dlsym_or_die("dl_iterate_phdr");
#endif
+ g_initted = true;
}
} // anonymous namespace
@@ -92,11 +113,13 @@ bool SafeToUnwindStack() {
extern "C" {
void *dlopen(const char *filename, int flag) { // NOLINT
+ InitIfNecessary();
ScopedBumpDepth d;
return CALL_ORIG(dlopen, filename, flag);
}
int dlclose(void *handle) { // NOLINT
+ InitIfNecessary();
ScopedBumpDepth d;
return CALL_ORIG(dlclose, handle);
}
@@ -105,14 +128,7 @@ int dlclose(void *handle) { // NOLINT
// function and blocks signals while calling it.
#if !defined(THREAD_SANITIZER) && !defined(__APPLE__)
int dl_iterate_phdr(dl_iterate_phdr_cbtype callback, void *data) { // NOLINT
- // In ASAN builds, the sanitizer runtime ends up calling dl_iterate_phdr from its
- // initialization, which runs before our own constructor functions. In that case, we
- // need to call Init() from here rather than via the normal path. There's no need to
- // worry about thread-safety since this all happens single-threaded during startup.
- if (PREDICT_FALSE(!g_orig_dl_iterate_phdr)) {
- Init();
- }
-
+ InitIfNecessary();
ScopedBumpDepth d;
return CALL_ORIG(dl_iterate_phdr, callback, data);
}