}
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. */
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");
}
/**
*/
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;
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;
};
/* 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,
.socket = -1,
.notify_socket = -1,
+ .wait_shm_is_file = false,
.wait_shm_path = "/" LTTNG_UST_WAIT_FILENAME,
.statedump_pending = 0,
.procname[0] = '\0'
};
-/* TODO: allow global_apps_sock_path override */
-
static struct sock_info local_apps = {
.name = "local",
.multi_user = false,
.socket = -1,
.notify_socket = -1,
+ .wait_shm_is_file = false,
+
.statedump_pending = 0,
.initial_statedump_done = 0,
.procname[0] = '\0'
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.
*/
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.");
error:
return ret;
}
+
static
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.
}
}
+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
/*
* 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;
/*
* 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
* 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);
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);
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,
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;
/*
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) {
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
'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.
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,