Introduce LTTNG_UST_APP_PATH environment variable
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fri, 20 Oct 2023 19:20:45 +0000 (15:20 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Tue, 6 Feb 2024 21:19:24 +0000 (16:19 -0500)
Introduce an environment to specify a path under which unix sockets
used for the communication between the application (tracee) instrumented
with `liblttng-ust` and the LTTng session and consumer daemons (part of
the LTTng-tools project) are located. When `$LTTNG_UST_APP_PATH` is
specified, only this path is considered for connecting to a session
daemon. Setting this environment variable disables connection to root
and per-user session daemons.

The `$LTTNG_UST_APP_PATH` target directory must exist and be accessible
by the user before the application is executed for tracing to work.

This environment variable affects the Java and Python agents in the same
way.

This environment variable on the LTTng-UST application side is meant to
be used with a new LTTNG_UST_CTL_PATH on the lttng sessiond side.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Change-Id: I4784f4565514a9771827603bd0bebabbeb37a7ad

doc/man/lttng-ust.3.txt
src/common/getenv.c
src/lib/lttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/LttngTcpSessiondClient.java
src/lib/lttng-ust/lttng-ust-comm.c
src/python-lttngust/lttngust/agent.py

index ad1fbbf4bd2a081d26fe3c1ddeccd654ac24c11e..081388961f4994553a4b80083c4e0427ed5a1af4 100644 (file)
@@ -1482,15 +1482,22 @@ int main(int argc, char* argv[])
 
 ENVIRONMENT VARIABLES
 ---------------------
+`LTTNG_UST_APP_PATH`::
+    Path under which unix sockets used for the communication between
+    the application (tracee) instrumented with `liblttng-ust` and the
+    LTTng session and consumer daemons (part of the LTTng-tools project)
+    are located. When `$LTTNG_UST_APP_PATH` is specified, only this path
+    is considered for connecting to a session daemon. The
+    `$LTTNG_UST_APP_PATH` target directory must exist and be accessible
+    by the user before the application is executed for tracing to work.
+    Setting this environment variable disables connection to root and
+    per-user session daemons.
+
 `LTTNG_HOME`::
     Alternative user's home directory. This variable is useful when the
     user running the instrumented application has a non-writable home
-    directory.
-+
-Unix sockets used for the communication between `liblttng-ust` and the
-LTTng session and consumer daemons (part of the LTTng-tools project)
-are located in a specific directory under `$LTTNG_HOME` (or `$HOME` if
-`$LTTNG_HOME` is not set).
+    directory. This path is where unix sockets for communication with
+    the per-user session daemon are located.
 
 `LTTNG_UST_ALLOW_BLOCKING`::
     If set, allow the application to retry event tracing when there's
index 55e6ad7cc5a069130ffb2172890752ef3e0d22c6..7f7b85349fe597654b4a2c4700a0e392478275ed 100644 (file)
@@ -49,6 +49,7 @@ static struct lttng_env lttng_env[] = {
        { "LTTNG_UST_ALLOW_BLOCKING", LTTNG_ENV_SECURE, NULL, },
        { "HOME", LTTNG_ENV_SECURE, NULL, },
        { "LTTNG_HOME", LTTNG_ENV_SECURE, NULL, },
+       { "LTTNG_UST_APP_PATH", LTTNG_ENV_SECURE, NULL, },
 };
 
 static
index cb84087af6a42fc81aa434dd7ec1018098c3e567..95376044a0116e52a6eb9f26656d391ac30e9a62 100644 (file)
@@ -170,20 +170,32 @@ public class LttngTcpSessiondClient implements Runnable {
        }
 
        private void connectToSessiond() throws IOException {
-               int rootPort = getPortFromFile(ROOT_PORT_FILE);
-               int userPort = getPortFromFile(getHomePath() + USER_PORT_FILE);
+               int portToUse;
 
                /*
-                * Check for the edge case of both files existing but pointing to the
-                * same port. In this case, let the root client handle it.
+                * The environment variable LTTNG_UST_APP_PATH disables
+                * connection to per-user and root session daemons.
                 */
-               if ((rootPort != 0) && (rootPort == userPort) && (!isRoot)) {
-                       log("User and root config files both point to port " + rootPort +
-                                       ". Letting the root client handle it.");
-                       throw new IOException();
-               }
+               String lttngUstAppPath = getUstAppPath();
+
+               if (lttngUstAppPath != null) {
+                       portToUse = getPortFromFile(lttngUstAppPath + USER_PORT_FILE);
+               } else {
+                       int rootPort = getPortFromFile(ROOT_PORT_FILE);
+                       int userPort = getPortFromFile(getHomePath() + USER_PORT_FILE);
+
+                       /*
+                        * Check for the edge case of both files existing but pointing to the
+                        * same port. In this case, let the root client handle it.
+                        */
+                       if ((rootPort != 0) && (rootPort == userPort) && (!isRoot)) {
+                               log("User and root config files both point to port " + rootPort +
+                                               ". Letting the root client handle it.");
+                               throw new IOException();
+                       }
 
-               int portToUse = (isRoot ? rootPort : userPort);
+                       portToUse = (isRoot ? rootPort : userPort);
+               }
 
                if (portToUse == 0) {
                        /* No session daemon available. Stop and retry later. */
@@ -195,17 +207,20 @@ public class LttngTcpSessiondClient implements Runnable {
                this.outToSessiond = new DataOutputStream(sessiondSock.getOutputStream());
        }
 
+       private static String getUstAppPath() {
+               return System.getenv("LTTNG_UST_APP_PATH");
+       }
+
        private static String getHomePath() {
                /*
                 * The environment variable LTTNG_HOME overrides HOME if
-                * defined.
+                * set.
                 */
-               String homePath = System.getenv("LTTNG_HOME");
-
-               if (homePath == null) {
-                       homePath = System.getProperty("user.home");
+               String lttngHomePath = System.getenv("LTTNG_HOME");
+               if (lttngHomePath != null) {
+                       return lttngHomePath;
                }
-               return homePath;
+               return System.getProperty("user.home");
        }
 
        /**
index ccf2a9b816e00920f92850a927bbdf6205c944b6..229e457a428ff9fa1c3781700b3f5f8eec4f532c 100644 (file)
@@ -234,10 +234,10 @@ void ust_unlock(void)
  */
 static sem_t constructor_wait;
 /*
- * Doing this for both the global and local sessiond.
+ * Doing this for the ust_app, global and local sessiond.
  */
 enum {
-       sem_count_initial_value = 4,
+       sem_count_initial_value = 6,
 };
 
 static int sem_count = sem_count_initial_value;
@@ -264,8 +264,15 @@ struct sock_info {
        int socket;
        int notify_socket;
 
+       /*
+        * If wait_shm_is_file is true, use standard open to open and
+        * create the shared memory used for waiting on session daemon.
+        * Otherwise, use shm_open to create this file.
+        */
+       bool wait_shm_is_file;
        char wait_shm_path[PATH_MAX];
        char *wait_shm_mmap;
+
        /* Keep track of lazy state dump not performed yet. */
        int statedump_pending;
        int initial_statedump_done;
@@ -274,6 +281,26 @@ struct sock_info {
 };
 
 /* Socket from app (connect) to session daemon (listen) for communication */
+static struct sock_info ust_app = {
+       .name = "ust_app",
+       .multi_user = true,
+
+       .root_handle = -1,
+       .registration_done = 0,
+       .allowed = 0,
+       .thread_active = 0,
+
+       .socket = -1,
+       .notify_socket = -1,
+
+       .wait_shm_is_file = true,
+
+       .statedump_pending = 0,
+       .initial_statedump_done = 0,
+       .procname[0] = '\0'
+};
+
+
 static struct sock_info global_apps = {
        .name = "global",
        .multi_user = true,
@@ -287,6 +314,7 @@ static struct sock_info global_apps = {
        .socket = -1,
        .notify_socket = -1,
 
+       .wait_shm_is_file = false,
        .wait_shm_path = "/" LTTNG_UST_WAIT_FILENAME,
 
        .statedump_pending = 0,
@@ -294,8 +322,6 @@ static struct sock_info global_apps = {
        .procname[0] = '\0'
 };
 
-/* TODO: allow global_apps_sock_path override */
-
 static struct sock_info local_apps = {
        .name = "local",
        .multi_user = false,
@@ -307,6 +333,8 @@ static struct sock_info local_apps = {
        .socket = -1,
        .notify_socket = -1,
 
+       .wait_shm_is_file = false,
+
        .statedump_pending = 0,
        .initial_statedump_done = 0,
        .procname[0] = '\0'
@@ -383,6 +411,12 @@ const char *get_lttng_home_dir(void)
        return (const char *) lttng_ust_getenv("HOME");
 }
 
+static
+const char *get_lttng_ust_app_path(void)
+{
+       return (const char *) lttng_ust_getenv("LTTNG_UST_APP_PATH");
+}
+
 /*
  * Force a read (imply TLS allocation for dlopen) of TLS variables.
  */
@@ -480,12 +514,70 @@ void print_cmd(int cmd, int handle)
                lttng_ust_obj_get_name(handle), handle);
 }
 
+static
+int setup_ust_apps(void)
+{
+       const char *ust_app_path;
+       int ret = 0;
+       uid_t uid;
+
+       assert(!ust_app.wait_shm_mmap);
+
+       uid = getuid();
+       /*
+        * Disallow ust apps tracing for setuid binaries, because we
+        * cannot use the environment variables anyway.
+        */
+       if (uid != geteuid()) {
+               DBG("UST app tracing disabled for setuid binary.");
+               assert(ust_app.allowed == 0);
+               ret = 0;
+               goto end;
+       }
+       ust_app_path = get_lttng_ust_app_path();
+       if (!ust_app_path) {
+               DBG("LTTNG_UST_APP_PATH environment variable not set.");
+               assert(ust_app.allowed == 0);
+               ret = -ENOENT;
+               goto end;
+       }
+       /*
+        * The LTTNG_UST_APP_PATH env. var. disables global and local
+        * sessiond connections.
+        */
+       ust_app.allowed = 1;
+       snprintf(ust_app.sock_path, PATH_MAX, "%s/%s",
+               ust_app_path, LTTNG_UST_SOCK_FILENAME);
+       snprintf(ust_app.wait_shm_path, PATH_MAX, "%s/%s",
+               ust_app_path,
+               LTTNG_UST_WAIT_FILENAME);
+
+       ust_app.wait_shm_mmap = get_map_shm(&ust_app);
+       if (!ust_app.wait_shm_mmap) {
+               WARN("Unable to get map shm for ust_app. Disabling LTTng-UST ust_app tracing.");
+               ust_app.allowed = 0;
+               ret = -EIO;
+               goto end;
+       }
+
+       lttng_pthread_getname_np(ust_app.procname, LTTNG_UST_CONTEXT_PROCNAME_LEN);
+end:
+       return ret;
+}
+
 static
 int setup_global_apps(void)
 {
        int ret = 0;
        assert(!global_apps.wait_shm_mmap);
 
+       /*
+        * The LTTNG_UST_APP_PATH env. var. disables global sessiond
+        * connections.
+        */
+       if (ust_app.allowed)
+               return 0;
+
        global_apps.wait_shm_mmap = get_map_shm(&global_apps);
        if (!global_apps.wait_shm_mmap) {
                WARN("Unable to get map shm for global apps. Disabling LTTng-UST global tracing.");
@@ -499,6 +591,7 @@ int setup_global_apps(void)
 error:
        return ret;
 }
+
 static
 int setup_local_apps(void)
 {
@@ -508,6 +601,13 @@ int setup_local_apps(void)
 
        assert(!local_apps.wait_shm_mmap);
 
+       /*
+        * The LTTNG_UST_APP_PATH env. var. disables local sessiond
+        * connections.
+        */
+       if (ust_app.allowed)
+               return 0;
+
        uid = getuid();
        /*
         * Disallow per-user tracing for setuid binaries.
@@ -1520,6 +1620,15 @@ void cleanup_sock_info(struct sock_info *sock_info, int exiting)
        }
 }
 
+static
+int wait_shm_open(struct sock_info *sock_info, int flags, mode_t mode)
+{
+       if (sock_info->wait_shm_is_file)
+               return open(sock_info->wait_shm_path, flags, mode);
+       else
+               return shm_open(sock_info->wait_shm_path, flags, mode);
+}
+
 /*
  * Using fork to set umask in the child process (not multi-thread safe).
  * We deal with the shm_open vs ftruncate race (happening when the
@@ -1538,7 +1647,7 @@ int get_wait_shm(struct sock_info *sock_info, size_t mmap_size)
        /*
         * Try to open read-only.
         */
-       wait_shm_fd = shm_open(sock_info->wait_shm_path, O_RDONLY, 0);
+       wait_shm_fd = wait_shm_open(sock_info, O_RDONLY, 0);
        if (wait_shm_fd >= 0) {
                int32_t tmp_read;
                ssize_t len;
@@ -1598,7 +1707,7 @@ open_write:
                /*
                 * Try to open read-only again after creation.
                 */
-               wait_shm_fd = shm_open(sock_info->wait_shm_path, O_RDONLY, 0);
+               wait_shm_fd = wait_shm_open(sock_info, O_RDONLY, 0);
                if (wait_shm_fd < 0) {
                        /*
                         * Real-only open did not work. It's a failure
@@ -1625,7 +1734,7 @@ open_write:
                 * We don't do an exclusive open, because we allow other
                 * processes to create+ftruncate it concurrently.
                 */
-               wait_shm_fd = shm_open(sock_info->wait_shm_path,
+               wait_shm_fd = wait_shm_open(sock_info,
                                O_RDWR | O_CREAT, create_mode);
                if (wait_shm_fd >= 0) {
                        ret = ftruncate(wait_shm_fd, mmap_size);
@@ -2258,6 +2367,11 @@ void lttng_ust_ctor(void)
                PERROR("sem_init");
        }
 
+       ret = setup_ust_apps();
+       if (ret) {
+               assert(ust_app.allowed == 0);
+               DBG("ust_app setup returned %d", ret);
+       }
        ret = setup_global_apps();
        if (ret) {
                assert(global_apps.allowed == 0);
@@ -2290,6 +2404,19 @@ void lttng_ust_ctor(void)
                ERR("pthread_attr_setdetachstate: %s", strerror(ret));
        }
 
+       if (ust_app.allowed) {
+               pthread_mutex_lock(&ust_exit_mutex);
+               ret = pthread_create(&ust_app.ust_listener, &thread_attr,
+                               ust_listener_thread, &ust_app);
+               if (ret) {
+                       ERR("pthread_create ust_app: %s", strerror(ret));
+               }
+               ust_app.thread_active = 1;
+               pthread_mutex_unlock(&ust_exit_mutex);
+       } else {
+               handle_register_done(&ust_app);
+       }
+
        if (global_apps.allowed) {
                pthread_mutex_lock(&ust_exit_mutex);
                ret = pthread_create(&global_apps.ust_listener, &thread_attr,
@@ -2369,8 +2496,10 @@ void lttng_ust_ctor(void)
 static
 void lttng_ust_cleanup(int exiting)
 {
+       cleanup_sock_info(&ust_app, exiting);
        cleanup_sock_info(&global_apps, exiting);
        cleanup_sock_info(&local_apps, exiting);
+       ust_app.allowed = 0;
        local_apps.allowed = 0;
        global_apps.allowed = 0;
        /*
@@ -2420,6 +2549,15 @@ void lttng_ust_exit(void)
 
        pthread_mutex_lock(&ust_exit_mutex);
        /* cancel threads */
+       if (ust_app.thread_active) {
+               ret = pthread_cancel(ust_app.ust_listener);
+               if (ret) {
+                       ERR("Error cancelling ust listener thread: %s",
+                               strerror(ret));
+               } else {
+                       ust_app.thread_active = 0;
+               }
+       }
        if (global_apps.thread_active) {
                ret = pthread_cancel(global_apps.ust_listener);
                if (ret) {
index 66dbbd5e2b5efc00f5cc8b263f2f1aeffc29f94f..69caad69492d66d0e7b1a2a4a83c530c3547fea8 100644 (file)
@@ -266,6 +266,8 @@ def _get_port_from_file(path):
 
     return port
 
+def _get_ust_app_path():
+    return os.getenv('LTTNG_UST_APP_PATH')
 
 def _get_user_home_path():
     # $LTTNG_HOME overrides $HOME if it exists
@@ -298,15 +300,25 @@ def _init_threads():
     'lttng'.encode().decode()
 
     _initialized = True
-    sys_port = _get_port_from_file('/var/run/lttng/agent.port')
-    user_port_file = os.path.join(_get_user_home_path(), '.lttng', 'agent.port')
-    user_port = _get_port_from_file(user_port_file)
+
+    # The LTTNG_UST_APP_PATH environment variables disables connections
+    # to the global and per-user session daemons.
+    if _get_ust_app_path() is not None:
+        ust_app_port_file = os.path.join(_get_ust_app_path(), 'agent.port')
+        ust_app_port = _get_port_from_file(ust_app_port_file)
+        sys_port = None
+        user_port = None
+        dbg._pdebug('ust_app session daemon port: {}'.format(ust_app_port))
+    else:
+        sys_port = _get_port_from_file('/var/run/lttng/agent.port')
+        user_port_file = os.path.join(_get_user_home_path(), '.lttng', 'agent.port')
+        user_port = _get_port_from_file(user_port_file)
+        dbg._pdebug('system session daemon port: {}'.format(sys_port))
+        dbg._pdebug('user session daemon port: {}'.format(user_port))
+
     reg_queue = queue.Queue()
     reg_expecting = 0
 
-    dbg._pdebug('system session daemon port: {}'.format(sys_port))
-    dbg._pdebug('user session daemon port: {}'.format(user_port))
-
     if sys_port == user_port and sys_port is not None:
         # The two session daemon ports are the same. This is not normal.
         # Connect to only one.
@@ -314,6 +326,16 @@ def _init_threads():
         sys_port = None
 
     try:
+     if ust_app_port is not None:
+            dbg._pdebug('creating ust_app client thread')
+            t = threading.Thread(target=_client_thread_target,
+                                 args=('ust_app', ust_app_port, reg_queue))
+            t.name = 'ust_app'
+            t.daemon = True
+            t.start()
+            dbg._pdebug('created and started ust_app client thread')
+            reg_expecting += 1
+
         if sys_port is not None:
             dbg._pdebug('creating system client thread')
             t = threading.Thread(target=_client_thread_target,
This page took 0.031694 seconds and 4 git commands to generate.