From 40dde2d5c15721fe22bce7ed4272f2db454883f4 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 19 Jun 2022 16:41:59 +0200 Subject: [PATCH] MEDIUM: debug: add a tainted flag when a shared library is loaded Several bug reports were caused by shared libraries being loaded by other libraries or some Lua code. Such libraries could define alternate symbols or include dependencies to alternate versions of a library used by haproxy, making it very hard to understand backtraces and analyze the issue. Let's intercept dlopen() and set a new TAINTED_SHARED_LIBS flag when it succeeds, so that "show info" makes it visible that some external libs were added. The redefinition is based on the definition of RTLD_DEFAULT or RTLD_NEXT that were previously used to detect that dlsym() is usable, since we need it as well. This should be sufficient to catch most situations. --- include/haproxy/bug.h | 1 + src/tools.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/include/haproxy/bug.h b/include/haproxy/bug.h index 85d048d55..a4980af8a 100644 --- a/include/haproxy/bug.h +++ b/include/haproxy/bug.h @@ -200,6 +200,7 @@ enum tainted_flags { TAINTED_CLI_EXPERIMENTAL_MODE = 0x00000008, TAINTED_WARN = 0x00000010, /* a WARN_ON triggered */ TAINTED_BUG = 0x00000020, /* a BUG_ON triggered */ + TAINTED_SHARED_LIBS = 0x00000040, /* a shared library was loaded */ }; /* this is a bit field made of TAINTED_*, and is declared in haproxy.c */ diff --git a/src/tools.c b/src/tools.c index 74903efda..5a3502750 100644 --- a/src/tools.c +++ b/src/tools.c @@ -5802,6 +5802,36 @@ int openssl_compare_current_name(const char *name) return 1; } +#if defined(RTLD_DEFAULT) || defined(RTLD_NEXT) +/* redefine dlopen() so that we can detect unexpected replacement of some + * critical symbols, typically init/alloc/free functions coming from alternate + * libraries. When called, a tainted flag is set (TAINTED_SHARED_LIBS). + */ +void *dlopen(const char *filename, int flags) +{ + static void *(*_dlopen)(const char *filename, int flags); + void *ret; + + if (!_dlopen) { + _dlopen = get_sym_next_addr("dlopen"); + if (!_dlopen || _dlopen == dlopen) { + _dlopen = NULL; + return NULL; + } + } + + + /* now open the requested lib */ + ret = _dlopen(filename, flags); + if (!ret) + return ret; + + mark_tainted(TAINTED_SHARED_LIBS); + + return ret; +} +#endif + static int init_tools_per_thread() { /* Let's make each thread start from a different position */