https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=246462

            Bug ID: 246462
           Summary: dlopen incorrect resolution of symbols [RTLD_DEEPBIND]
           Product: Base System
           Version: 12.1-RELEASE
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Only Me
          Priority: ---
         Component: bin
          Assignee: b...@freebsd.org
          Reporter: d8zne...@aon.at

Introduction: This issue arose in the context of trying to upgrade a port
(databases/postgresql-mysql_fdw) but is actually about the behavior of
rtld/dlopen which seems to have changed (probably with the switch to
clang/llvm).

Scenario:
- System running FreeBSD 12.1-RELEASE-p4 #4 r360692M
- Ports at latest, mysql57-server and postgresql12-server installed
- Trying to upgrade databases/postgresql-mysql_fdw from its current 2.5.1 to
2.5.3

Note: databases/postgresql-mysql_fdw is a foreign data wrapper which enables a
Postgres server to access remote MySQL databases.

Scenario (continued):
- The upgrade is straightforward, just adapt the Makefile and distinfo, and it
compiles and can be installed.
- After installation, the local database is extended to be able to access the
remote MySQL database using
    CREATE EXTENSION mysql_fdw;
    CREATE_SERVER ...
    CREATE USER MAPPING ...
    GRANT USAGE ON FOREIGN SERVER ...
    CREATE SCHEMA ...
    IMPORT FOREIGN SCHEMA ...
- Then a foreign table is accessed using SELECT * FROM <foreign table>;

Result:
- When accessing the foreign table, the first access retrieves a correct
result, and then the postgres process handling the postgres database client
crashes with segmentation violation (signal 11), producing a core file.

Scenario (continued):
- Debugging the core file using lldb -c /tmp/postgres.core
/usr/local/bin/postgres

Result:
(lldb) thread backtrace
* thread #1, name = 'postgres', stop reason = signal SIGSEGV
  * frame #0: 0x00000000009002eb postgres`pfree + 11
    frame #1: 0x00000000006a50de postgres`list_delete + 206
    frame #2: 0x000000080b4f7d36 libmysqlclient.so`mysql_stmt_close + 102

Explanation: I believe what is happening here is that mysql_stmt_close calls
list_delete, but this list_delete gets resolved to the version in the postgres
binary instead of the function of the same name in libmysqlclient.so. This is
because MySQL and Postgres are using the same names for different functions of
their own, and in this case the wrong one is being called.

A while ago, when the databases/postgresql-mysql_fdw port was last upgraded
some years ago, this seemingly was not the case. Specifically, in the source
code of this port one finds the following comment:

/*
 * mysql_load_library function dynamically load the mysql's library
 * libmysqlclient.so. The only reason to load the library using dlopen
 * is that, mysql and postgres both have function with same name like
 * "list_delete", "list_delete" and "list_free" which cause compiler
 * error "duplicate function name" and erroneously linking with a function.
 * This port of the code is used to avoid the compiler error.
 *
 * #define list_delete mysql_list_delete
 * #include <mysql.h>
 * #undef list_delete
 *
 * But system crashed on function mysql_stmt_close function because
 * mysql_stmt_close internally calling "list_delete" function which
 * wrongly binds to postgres' "list_delete" function.
 *
 * The dlopen function provides a parameter "RTLD_DEEPBIND" which
 * solved the binding issue.
 *
 * RTLD_DEEPBIND:
 * Place the lookup scope of the symbols in this library ahead of the
 * global scope. This means that a self-contained library will use its
 * own symbols in preference to global symbols with the same name contained
 * in libraries that have already been loaded.
 */
bool
mysql_load_library(void)
{
#if defined(__APPLE__) || defined(__FreeBSD__)
        /*
         * Mac OS/BSD does not support RTLD_DEEPBIND, but it still
         * works without the RTLD_DEEPBIND
         */
        mysql_dll_handle = dlopen(_MYSQL_LIBNAME, RTLD_LAZY);
#else
        mysql_dll_handle = dlopen(_MYSQL_LIBNAME, RTLD_LAZY | RTLD_DEEPBIND);
#endif
        if(mysql_dll_handle == NULL)
                return false;

Conclusion: It seems that the behavior of the runtime loader changed such that
now the executable's symbols are searched before a library's symbols when
resolving references arising from that library (in this case,
libmysqlclient.so). It further seems that there are two possible resolutions:
Either re-introduce the old behavior (which made it unnecessary to use
RTLD_DEEPBIND in FreeBSD), or implement RTLD_DEEPBIND for FreeBSD.

-- Martin

-- 
You are receiving this mail because:
You are the assignee for the bug.
_______________________________________________
freebsd-bugs@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/freebsd-bugs
To unsubscribe, send any mail to "freebsd-bugs-unsubscr...@freebsd.org"

Reply via email to