Custom upgrade: chain load liblttng-ust-{fd,fork}.so.0 with dlopen
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Wed, 15 Jun 2022 15:13:35 +0000 (11:13 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fri, 30 Sep 2022 18:33:34 +0000 (14:33 -0400)
dlopen liblttng-ust.so.0 in the constructor of the interposer librairies
and explicitly call the symbols from this library when appropriate.

As a side-note, chain linking the interposer ld_preload librairies on
their previous SONAME0 versions doesn't work as expected because the
order of the symbol resolution with dlsym always favors the preloaded
library symbols. This is why explicit use of dlopen/dlsym is favored
instead.

Change-Id: Ie8802134c3037cfd431a949f469d3e64e958888b
Signed-off-by: Michael Jeanson <mjeanson@efficios.com>
configure.ac
src/lib/lttng-ust-common/fd-tracker.c
src/lib/lttng-ust-fd/lttng-ust-fd.c
src/lib/lttng-ust-fork/ustfork.c

index 4dfc011a3adf269588fdfbbbb1b71cfa5c0e698b..4026155b1bde24cb092ff418943fd211d9a1bdbb 100644 (file)
@@ -577,7 +577,7 @@ AM_CONDITIONAL([HAVE_CMAKE], [test "x$CMAKE" != "x"])
 AM_CONDITIONAL([HAVE_CXX], [test "$HAVE_CXX11" = "1"])
 AM_CONDITIONAL([HAVE_JAVAH], [test "x$JAVAH" != "x"])
 AM_CONDITIONAL([HAVE_PERF_EVENT], [test "x$ac_cv_header_linux_perf_event_h" = "xyes"])
-
+AM_CONDITIONAL([ENABLE_LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS], AE_IS_FEATURE_ENABLED([custom-upgrade-conflicting-symbols]))
 
 ##                                             ##
 ## Substitute variables for use in Makefile.am ##
index 12fcd9cb4e0dd1981fa9f1b6097144665fc7e72b..d61cfbc98c26ab1df06e423e154113b329a24c6b 100644 (file)
@@ -21,6 +21,7 @@
 #include <pthread.h>
 #include <signal.h>
 #include <stdbool.h>
+#include <dlfcn.h>
 #include <urcu/compiler.h>
 #include <urcu/tls-compat.h>
 #include <urcu/system.h>
@@ -301,6 +302,35 @@ static void lttng_ust_delete_fd_from_tracker_orig(int fd)
        DEL_FD_FROM_SET(fd, lttng_fd_set);
 }
 
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+static int (*__lttng_ust_safe_close_fd)(int fd, int (*close_cb)(int fd)) = NULL;
+
+static
+void *_init_lttng_ust_safe_close_fd(void)
+{
+       if (__lttng_ust_safe_close_fd == NULL) {
+               __lttng_ust_safe_close_fd = dlsym(RTLD_DEFAULT, "lttng_ust_safe_close_fd");
+
+               if (__lttng_ust_safe_close_fd == NULL) {
+                       fprintf(stderr, "%s\n", dlerror());
+               }
+       }
+
+       return __lttng_ust_safe_close_fd;
+}
+
+static int lttng_ust_safe_close_fd_chain(int fd, int (*close_cb)(int fd))
+{
+       if (_init_lttng_ust_safe_close_fd()) {
+               /* Chain on ust-2.12 preload */
+               return __lttng_ust_safe_close_fd(fd, close_cb);
+       } else {
+               /* Fallback to libc symbol */
+               return close_cb(fd);
+       }
+}
+#endif
+
 /*
  * Interface allowing applications to close arbitrary file descriptors.
  * We check if it is owned by lttng-ust, and return -1, errno=EBADF
@@ -322,21 +352,59 @@ static int lttng_ust_safe_close_fd_orig(int fd, int (*close_cb)(int fd))
         * If called from lttng-ust, we directly call close without
         * validating whether the FD is part of the tracked set.
         */
-       if (URCU_TLS(ust_fd_mutex_nest))
+       if (URCU_TLS(ust_fd_mutex_nest)) {
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+               return lttng_ust_safe_close_fd_chain(fd, close_cb);
+#else
                return close_cb(fd);
+#endif
+       }
 
        lttng_ust_lock_fd_tracker();
        if (IS_FD_VALID(fd) && IS_FD_SET(fd, lttng_fd_set)) {
                ret = -1;
                errno = EBADF;
        } else {
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+               ret = lttng_ust_safe_close_fd_chain(fd, close_cb);
+#else
                ret = close_cb(fd);
+#endif
        }
        lttng_ust_unlock_fd_tracker();
 
        return ret;
 }
 
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+static int (*__lttng_ust_safe_fclose_stream)(FILE *stream, int (*fclose_cb)(FILE *stream)) = NULL;
+
+static
+void *_init_lttng_ust_safe_fclose_stream(void)
+{
+       if (__lttng_ust_safe_fclose_stream == NULL) {
+               __lttng_ust_safe_fclose_stream = dlsym(RTLD_DEFAULT, "lttng_ust_safe_fclose_stream");
+
+               if (__lttng_ust_safe_fclose_stream == NULL) {
+                       fprintf(stderr, "%s\n", dlerror());
+               }
+       }
+
+       return __lttng_ust_safe_fclose_stream;
+}
+
+static int lttng_ust_safe_fclose_stream_chain(FILE *stream, int (*fclose_cb)(FILE *stream))
+{
+       if (_init_lttng_ust_safe_fclose_stream()) {
+               /* Chain on ust-2.12 preload */
+               return __lttng_ust_safe_fclose_stream(stream, fclose_cb);
+       } else {
+               /* Fallback to libc symbol */
+               return fclose_cb(stream);
+       }
+}
+#endif
+
 /*
  * Interface allowing applications to close arbitrary streams.
  * We check if it is owned by lttng-ust, and return -1, errno=EBADF
@@ -358,8 +426,13 @@ static int lttng_ust_safe_fclose_stream_orig(FILE *stream, int (*fclose_cb)(FILE
         * If called from lttng-ust, we directly call fclose without
         * validating whether the FD is part of the tracked set.
         */
-       if (URCU_TLS(ust_fd_mutex_nest))
+       if (URCU_TLS(ust_fd_mutex_nest)) {
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+               return lttng_ust_safe_fclose_stream_chain(stream, fclose_cb);
+#else
                return fclose_cb(stream);
+#endif
+       }
 
        fd = fileno(stream);
 
@@ -368,7 +441,11 @@ static int lttng_ust_safe_fclose_stream_orig(FILE *stream, int (*fclose_cb)(FILE
                ret = -1;
                errno = EBADF;
        } else {
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+               ret = lttng_ust_safe_fclose_stream_chain(stream, fclose_cb);
+#else
                ret = fclose_cb(stream);
+#endif
        }
        lttng_ust_unlock_fd_tracker();
 
index d2ebcfbc38be862b6effffdc490f7a7d0ce968cb..c58ebdb71bf084316bae330febfa0e0ee4d0c81b 100644 (file)
@@ -66,6 +66,19 @@ void _lttng_ust_fd_ctor(void)
 static
 void _lttng_ust_fd_ctor(void)
 {
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+       void *handle = NULL;
+
+       /*
+        * Load ust-2.12 in the global symbol namespace.
+        */
+       handle = dlopen("liblttng-ust.so.0", RTLD_GLOBAL | RTLD_NOW);
+       if (!handle) {
+               fprintf(stderr, "liblttng-ust-fd.so.1: Failed to dlopen liblttng-ust.so.0: %s\n", dlerror());
+               abort();
+       }
+#endif
+
        lttng_ust_common_ctor();
 
        /*
index 321ffc30c0fd993d7be43a62fa9063fbe3a2e5ca..ec6974b0cbf020c396c26540095a9a9e3d66565b 100644 (file)
 
 #include <lttng/ust-fork.h>
 
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+static int (*__ust_before_fork)(sigset_t *save_sigset) = NULL;
+static int (*__ust_after_fork_child)(sigset_t *restore_sigset) = NULL;
+static int (*__ust_after_fork_parent)(sigset_t *restore_sigset) = NULL;
+
+static void (*__ust_after_setns)(void) = NULL;
+static void (*__ust_after_unshare)(void) = NULL;
+static void (*__ust_after_setuid)(void) = NULL;
+static void (*__ust_after_setgid)(void) = NULL;
+static void (*__ust_after_seteuid)(void) = NULL;
+static void (*__ust_after_setegid)(void) = NULL;
+static void (*__ust_after_setreuid)(void) = NULL;
+static void (*__ust_after_setregid)(void) = NULL;
+static void (*__ust_after_setresuid)(void) = NULL;
+static void (*__ust_after_setresgid)(void) = NULL;
+
+static
+void *_init_ust_before_fork(void)
+{
+       if (__ust_before_fork == NULL) {
+               __ust_before_fork = dlsym(RTLD_DEFAULT, "ust_before_fork");
+
+               if (__ust_before_fork == NULL) {
+                       fprintf(stderr, "%s\n", dlerror());
+               }
+       }
+
+       return __ust_before_fork;
+}
+
+static
+void *_init_ust_after_fork_child(void)
+{
+       if (__ust_after_fork_child == NULL) {
+               __ust_after_fork_child = dlsym(RTLD_DEFAULT, "ust_after_fork_child");
+
+               if (__ust_after_fork_child == NULL) {
+                       fprintf(stderr, "%s\n", dlerror());
+               }
+       }
+
+       return __ust_after_fork_child;
+}
+
+static
+void *_init_ust_after_fork_parent(void)
+{
+       if (__ust_after_fork_parent == NULL) {
+               __ust_after_fork_parent = dlsym(RTLD_DEFAULT, "ust_after_fork_parent");
+
+               if (__ust_after_fork_parent == NULL) {
+                       fprintf(stderr, "%s\n", dlerror());
+               }
+       }
+
+       return __ust_after_fork_parent;
+}
+
+static
+void *_init_ust_after_setns(void)
+{
+       if (__ust_after_setns == NULL) {
+               __ust_after_setns = dlsym(RTLD_DEFAULT, "ust_after_setns");
+
+               if (__ust_after_setns == NULL) {
+                       fprintf(stderr, "%s\n", dlerror());
+               }
+       }
+
+       return __ust_after_setns;
+}
+
+static
+void *_init_ust_after_unshare(void)
+{
+       if (__ust_after_unshare == NULL) {
+               __ust_after_unshare = dlsym(RTLD_DEFAULT, "ust_after_unshare");
+
+               if (__ust_after_unshare == NULL) {
+                       fprintf(stderr, "%s\n", dlerror());
+               }
+       }
+
+       return __ust_after_unshare;
+}
+
+static
+void *_init_ust_after_setuid(void)
+{
+       if (__ust_after_setuid == NULL) {
+               __ust_after_setuid = dlsym(RTLD_DEFAULT, "ust_after_setuid");
+
+               if (__ust_after_setuid == NULL) {
+                       fprintf(stderr, "%s\n", dlerror());
+               }
+       }
+
+       return __ust_after_setuid;
+}
+
+static
+void *_init_ust_after_setgid(void)
+{
+       if (__ust_after_setgid == NULL) {
+               __ust_after_setgid = dlsym(RTLD_DEFAULT, "ust_after_setgid");
+
+               if (__ust_after_setgid == NULL) {
+                       fprintf(stderr, "%s\n", dlerror());
+               }
+       }
+
+       return __ust_after_setgid;
+}
+
+static
+void *_init_ust_after_seteuid(void)
+{
+       if (__ust_after_seteuid == NULL) {
+               __ust_after_seteuid = dlsym(RTLD_DEFAULT, "ust_after_seteuid");
+
+               if (__ust_after_seteuid == NULL) {
+                       fprintf(stderr, "%s\n", dlerror());
+               }
+       }
+
+       return __ust_after_seteuid;
+}
+
+static
+void *_init_ust_after_setegid(void)
+{
+       if (__ust_after_setegid == NULL) {
+               __ust_after_setegid = dlsym(RTLD_DEFAULT, "ust_after_setegid");
+
+               if (__ust_after_setegid == NULL) {
+                       fprintf(stderr, "%s\n", dlerror());
+               }
+       }
+
+       return __ust_after_setegid;
+}
+
+static
+void *_init_ust_after_setreuid(void)
+{
+       if (__ust_after_setreuid == NULL) {
+               __ust_after_setreuid = dlsym(RTLD_DEFAULT, "ust_after_setreuid");
+
+               if (__ust_after_setreuid == NULL) {
+                       fprintf(stderr, "%s\n", dlerror());
+               }
+       }
+
+       return __ust_after_setreuid;
+}
+
+static
+void *_init_ust_after_setregid(void)
+{
+       if (__ust_after_setregid == NULL) {
+               __ust_after_setregid = dlsym(RTLD_DEFAULT, "ust_after_setregid");
+
+               if (__ust_after_setregid == NULL) {
+                       fprintf(stderr, "%s\n", dlerror());
+               }
+       }
+
+       return __ust_after_setregid;
+}
+
+static
+void *_init_ust_after_setresuid(void)
+{
+       if (__ust_after_setresuid == NULL) {
+               __ust_after_setresuid = dlsym(RTLD_DEFAULT, "ust_after_setresuid");
+
+               if (__ust_after_setresuid == NULL) {
+                       fprintf(stderr, "%s\n", dlerror());
+               }
+       }
+
+       return __ust_after_setresuid;
+}
+
+static
+void *_init_ust_after_setresgid(void)
+{
+       if (__ust_after_setresgid == NULL) {
+               __ust_after_setresgid = dlsym(RTLD_DEFAULT, "ust_after_setresgid");
+
+               if (__ust_after_setresgid == NULL) {
+                       fprintf(stderr, "%s\n", dlerror());
+               }
+       }
+
+       return __ust_after_setresgid;
+}
+
+static
+void _lttng_ust_fork_ctor(void)
+       __attribute__((constructor));
+static
+void _lttng_ust_fork_ctor(void)
+{
+       void *handle = NULL;
+
+       /*
+        * Load ust-2.12 in the global symbol namespace.
+        */
+       handle = dlopen("liblttng-ust.so.0", RTLD_GLOBAL | RTLD_NOW);
+       if (!handle) {
+               fprintf(stderr, "liblttng-ust-fork.so.1: Failed to dlopen liblttng-ust.so.0: %s\n", dlerror());
+               abort();
+       }
+}
+#endif
+
 pid_t fork(void)
 {
        static pid_t (*plibc_func)(void) = NULL;
@@ -35,14 +252,30 @@ pid_t fork(void)
        }
 
        lttng_ust_before_fork(&sigset);
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+       if (_init_ust_before_fork()) {
+               __ust_before_fork(&sigset);
+       }
+#endif
+
        /* Do the real fork */
        retval = plibc_func();
        saved_errno = errno;
        if (retval == 0) {
                /* child */
                lttng_ust_after_fork_child(&sigset);
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+               if (_init_ust_after_fork_child()) {
+                       __ust_after_fork_child(&sigset);
+               }
+#endif
        } else {
                lttng_ust_after_fork_parent(&sigset);
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+               if (_init_ust_after_fork_parent()) {
+                       __ust_after_fork_parent(&sigset);
+               }
+#endif
        }
        errno = saved_errno;
        return retval;
@@ -65,15 +298,31 @@ int daemon(int nochdir, int noclose)
        }
 
        lttng_ust_before_fork(&sigset);
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+       if (_init_ust_before_fork()) {
+               __ust_before_fork(&sigset);
+       }
+#endif
+
        /* Do the real daemon call */
        retval = plibc_func(nochdir, noclose);
        saved_errno = errno;
        if (retval == 0) {
                /* child, parent called _exit() directly */
                lttng_ust_after_fork_child(&sigset);
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+               if (_init_ust_after_fork_child()) {
+                       __ust_after_fork_child(&sigset);
+               }
+#endif
        } else {
                /* on error in the parent */
                lttng_ust_after_fork_parent(&sigset);
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+               if (_init_ust_after_fork_parent()) {
+                       __ust_after_fork_parent(&sigset);
+               }
+#endif
        }
        errno = saved_errno;
        return retval;
@@ -99,6 +348,11 @@ int setuid(uid_t uid)
        saved_errno = errno;
 
        lttng_ust_after_setuid();
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+       if (_init_ust_after_setuid()) {
+               __ust_after_setuid();
+       }
+#endif
 
        errno = saved_errno;
        return retval;
@@ -124,6 +378,11 @@ int setgid(gid_t gid)
        saved_errno = errno;
 
        lttng_ust_after_setgid();
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+       if (_init_ust_after_setgid()) {
+               __ust_after_setgid();
+       }
+#endif
 
        errno = saved_errno;
        return retval;
@@ -149,6 +408,11 @@ int seteuid(uid_t euid)
        saved_errno = errno;
 
        lttng_ust_after_seteuid();
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+       if (_init_ust_after_seteuid()) {
+               __ust_after_seteuid();
+       }
+#endif
 
        errno = saved_errno;
        return retval;
@@ -174,6 +438,11 @@ int setegid(gid_t egid)
        saved_errno = errno;
 
        lttng_ust_after_setegid();
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+       if (_init_ust_after_setegid()) {
+               __ust_after_setegid();
+       }
+#endif
 
        errno = saved_errno;
        return retval;
@@ -199,6 +468,11 @@ int setreuid(uid_t ruid, uid_t euid)
        saved_errno = errno;
 
        lttng_ust_after_setreuid();
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+       if (_init_ust_after_setreuid()) {
+               __ust_after_setreuid();
+       }
+#endif
 
        errno = saved_errno;
        return retval;
@@ -224,6 +498,11 @@ int setregid(gid_t rgid, gid_t egid)
        saved_errno = errno;
 
        lttng_ust_after_setregid();
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+       if (_init_ust_after_setregid()) {
+               __ust_after_setregid();
+       }
+#endif
 
        errno = saved_errno;
        return retval;
@@ -245,6 +524,11 @@ static int clone_fn(void *arg)
 
        /* clone is now done and we are in child */
        lttng_ust_after_fork_child(&info->sigset);
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+       if (_init_ust_after_fork_child()) {
+               __ust_after_fork_child(&info->sigset);
+       }
+#endif
        return info->fn(info->arg);
 }
 
@@ -290,11 +574,21 @@ int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...)
                struct ustfork_clone_info info = { .fn = fn, .arg = arg };
 
                lttng_ust_before_fork(&info.sigset);
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+               if (_init_ust_before_fork()) {
+                       __ust_before_fork(&info.sigset);
+               }
+#endif
                retval = plibc_func(clone_fn, child_stack, flags, &info,
                                ptid, tls, ctid);
                saved_errno = errno;
                /* The child doesn't get here. */
                lttng_ust_after_fork_parent(&info.sigset);
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+               if (_init_ust_after_fork_parent()) {
+                       __ust_after_fork_parent(&info.sigset);
+               }
+#endif
        }
        errno = saved_errno;
        return retval;
@@ -320,6 +614,11 @@ int setns(int fd, int nstype)
        saved_errno = errno;
 
        lttng_ust_after_setns();
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+       if (_init_ust_after_setns()) {
+               __ust_after_setns();
+       }
+#endif
 
        errno = saved_errno;
        return retval;
@@ -345,6 +644,11 @@ int unshare(int flags)
        saved_errno = errno;
 
        lttng_ust_after_unshare();
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+       if (_init_ust_after_unshare()) {
+               __ust_after_unshare();
+       }
+#endif
 
        errno = saved_errno;
        return retval;
@@ -370,6 +674,11 @@ int setresuid(uid_t ruid, uid_t euid, uid_t suid)
        saved_errno = errno;
 
        lttng_ust_after_setresuid();
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+       if (_init_ust_after_setresuid()) {
+               __ust_after_setresuid();
+       }
+#endif
 
        errno = saved_errno;
        return retval;
@@ -395,6 +704,11 @@ int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
        saved_errno = errno;
 
        lttng_ust_after_setresgid();
+#if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
+       if (_init_ust_after_setresgid()) {
+               __ust_after_setresgid();
+       }
+#endif
 
        errno = saved_errno;
        return retval;
This page took 0.032233 seconds and 5 git commands to generate.