X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=src%2Flib%2Flttng-ust%2Flttng-ust-comm.c;h=9745c18246690b35e778cb19b5e593452cb5e141;hb=3287f48be61ef3491aff0a80b7185ac57b3d8a5d;hp=10883e9675b6374f42bfa38d0b7529eb8cbc05e1;hpb=a987943be74e59e0383b7a5b4b5fa2c47c3ab578;p=lttng-ust.git diff --git a/src/lib/lttng-ust/lttng-ust-comm.c b/src/lib/lttng-ust/lttng-ust-comm.c index 10883e96..9745c182 100644 --- a/src/lib/lttng-ust/lttng-ust-comm.c +++ b/src/lib/lttng-ust/lttng-ust-comm.c @@ -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; @@ -257,15 +257,22 @@ struct sock_info { int root_handle; int registration_done; int allowed; - int global; + bool multi_user; int thread_active; char sock_path[PATH_MAX]; 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,9 +281,29 @@ 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", - .global = 1, + .multi_user = true, .root_handle = -1, .registration_done = 0, @@ -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,11 +322,9 @@ static struct sock_info global_apps = { .procname[0] = '\0' }; -/* TODO: allow global_apps_sock_path override */ - static struct sock_info local_apps = { .name = "local", - .global = 0, + .multi_user = false, .root_handle = -1, .registration_done = 0, .allowed = 0, /* Check setuid bit first */ @@ -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,45 +411,84 @@ const char *get_lttng_home_dir(void) return (const char *) lttng_ust_getenv("HOME"); } +/* + * Returns the LTTNG_UST_APP_PATH path. If environment variable exists + * and contains a ':', the first path before the ':' separator is returned. + * The return value should be freed by the caller if it is not NULL. + */ +static +char *get_lttng_ust_app_path(void) +{ + const char *env_val = lttng_ust_getenv("LTTNG_UST_APP_PATH"); + char *val = NULL; + char *sep = NULL; + if (env_val == NULL) + goto error; + sep = strchr((char*)env_val, ':'); + if (sep) { + /* + * Split into multiple paths using ':' as a separator. + * There is no escaping of the ':' separator. + */ + WARN("':' separator in LTTNG_UST_APP_PATH, only the first path will be used."); + val = zmalloc(sep - env_val + 1); + if (!val) { + PERROR("zmalloc get_lttng_ust_app_path"); + goto error; + } + memcpy(val, env_val, sep - env_val); + val[sep - env_val] = '\0'; + } else { + val = strdup(env_val); + if (!val) { + PERROR("strdup"); + goto error; + } + } + +error: + return val; +} + /* * Force a read (imply TLS allocation for dlopen) of TLS variables. */ static -void lttng_nest_count_alloc_tls(void) +void lttng_ust_nest_count_alloc_tls(void) { - asm volatile ("" : : "m" (URCU_TLS(lttng_ust_nest_count))); + __asm__ __volatile__ ("" : : "m" (URCU_TLS(lttng_ust_nest_count))); } static void lttng_ust_mutex_nest_alloc_tls(void) { - asm volatile ("" : : "m" (URCU_TLS(ust_mutex_nest))); + __asm__ __volatile__ ("" : : "m" (URCU_TLS(ust_mutex_nest))); } /* * Allocate lttng-ust urcu TLS. */ static -void lttng_lttng_ust_urcu_alloc_tls(void) +void lttng_ust_urcu_alloc_tls(void) { (void) lttng_ust_urcu_read_ongoing(); } -void lttng_ust_alloc_tls(void) +void lttng_ust_common_init_thread(int flags) { - lttng_lttng_ust_urcu_alloc_tls(); + lttng_ust_urcu_alloc_tls(); lttng_ringbuffer_alloc_tls(); - lttng_vtid_alloc_tls(); - lttng_nest_count_alloc_tls(); - lttng_procname_alloc_tls(); + lttng_ust_vtid_init_thread(flags); + lttng_ust_nest_count_alloc_tls(); + lttng_ust_procname_init_thread(flags); lttng_ust_mutex_nest_alloc_tls(); - lttng_ust_perf_counter_alloc_tls(); + lttng_ust_perf_counter_init_thread(flags); lttng_ust_common_alloc_tls(); - lttng_cgroup_ns_alloc_tls(); - lttng_ipc_ns_alloc_tls(); - lttng_net_ns_alloc_tls(); - lttng_time_ns_alloc_tls(); - lttng_uts_ns_alloc_tls(); + lttng_ust_cgroup_ns_init_thread(flags); + lttng_ust_ipc_ns_init_thread(flags); + lttng_ust_net_ns_init_thread(flags); + lttng_ust_time_ns_init_thread(flags); + lttng_ust_uts_ns_init_thread(flags); lttng_ust_ring_buffer_client_discard_alloc_tls(); lttng_ust_ring_buffer_client_discard_rt_alloc_tls(); lttng_ust_ring_buffer_client_overwrite_alloc_tls(); @@ -446,7 +513,9 @@ void lttng_ust_init_thread(void) * ensure those are initialized before a signal handler nesting over * this thread attempts to use them. */ - lttng_ust_alloc_tls(); + lttng_ust_common_init_thread(LTTNG_UST_INIT_THREAD_MASK); + + lttng_ust_urcu_register_thread(); } int lttng_get_notify_socket(void *owner) @@ -478,12 +547,72 @@ void print_cmd(int cmd, int handle) lttng_ust_obj_get_name(handle), handle); } +static +int setup_ust_apps(void) +{ + char *ust_app_path = NULL; + 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: + if (ust_app_path) + free(ust_app_path); + 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."); @@ -497,6 +626,7 @@ int setup_global_apps(void) error: return ret; } + static int setup_local_apps(void) { @@ -506,6 +636,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. @@ -1518,6 +1655,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 @@ -1536,7 +1682,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; @@ -1582,21 +1728,21 @@ open_write: pid = fork(); URCU_TLS(lttng_ust_nest_count)--; if (pid > 0) { - int status; + int status, wait_ret; /* * Parent: wait for child to return, in which case the * shared memory map will have been created. */ - pid = wait(&status); - if (pid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) { + wait_ret = waitpid(pid, &status, 0); + if (wait_ret < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) { wait_shm_fd = -1; goto end; } /* * 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 @@ -1611,7 +1757,7 @@ open_write: /* Child */ create_mode = S_IRUSR | S_IWUSR | S_IRGRP; - if (sock_info->global) + if (sock_info->multi_user) create_mode |= S_IROTH | S_IWGRP | S_IWOTH; /* * We're alone in a child process, so we can modify the @@ -1623,7 +1769,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); @@ -1641,7 +1787,7 @@ open_write: * sessiond will be able to override all rights and wake * us up. */ - if (!sock_info->global && errno != EACCES) { + if (!sock_info->multi_user && errno != EACCES) { ERR("Error opening shm %s", sock_info->wait_shm_path); _exit(EXIT_FAILURE); } @@ -1654,7 +1800,7 @@ open_write: return -1; } end: - if (wait_shm_fd >= 0 && !sock_info->global) { + if (wait_shm_fd >= 0 && !sock_info->multi_user) { struct stat statbuf; /* @@ -1757,18 +1903,25 @@ void wait_for_sessiond(struct sock_info *sock_info) DBG("Waiting for %s apps sessiond", sock_info->name); /* Wait for futex wakeup */ - if (uatomic_read((int32_t *) sock_info->wait_shm_mmap)) - goto end_wait; - - while (lttng_ust_futex_async((int32_t *) sock_info->wait_shm_mmap, - FUTEX_WAIT, 0, NULL, NULL, 0)) { + while (!uatomic_read((int32_t *) sock_info->wait_shm_mmap)) { + if (!lttng_ust_futex_async((int32_t *) sock_info->wait_shm_mmap, FUTEX_WAIT, 0, NULL, NULL, 0)) { + /* + * Prior queued wakeups queued by unrelated code + * using the same address can cause futex wait to + * return 0 even through the futex value is still + * 0 (spurious wakeups). Check the value again + * in user-space to validate whether it really + * differs from 0. + */ + continue; + } switch (errno) { - case EWOULDBLOCK: + case EAGAIN: /* Value already changed. */ goto end_wait; case EINTR: /* Retry if interrupted by signal. */ - break; /* Get out of switch. */ + break; /* Get out of switch. Check again. */ case EFAULT: wait_poll_fallback = 1; DBG( @@ -1808,7 +1961,7 @@ void *ust_listener_thread(void *arg) int sock, ret, prev_connect_failed = 0, has_waited = 0, fd; long timeout; - lttng_ust_alloc_tls(); + lttng_ust_common_init_thread(0); /* * If available, add '-ust' to the end of this thread's * process name @@ -2176,7 +2329,7 @@ void lttng_ust_ctor(void) * to be the dynamic linker mutex) and ust_lock, taken within * the ust lock. */ - lttng_ust_alloc_tls(); + lttng_ust_common_init_thread(0); lttng_ust_loaded = 1; @@ -2249,6 +2402,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); @@ -2281,6 +2439,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, @@ -2360,8 +2531,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; /* @@ -2411,6 +2584,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) { @@ -2490,7 +2672,7 @@ void lttng_ust_before_fork(sigset_t *save_sigset) int ret; /* Allocate lttng-ust TLS. */ - lttng_ust_alloc_tls(); + lttng_ust_common_init_thread(0); if (URCU_TLS(lttng_ust_nest_count)) return;