#include <sys/types.h>
#include <sys/socket.h>
#include <sys/prctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <ust/tracepoint.h>
#include <ust/tracepoint-internal.h>
#include <ust/ust.h>
+#include "ltt-tracer-core.h"
/*
* Has lttng ust comm constructor been called ?
*/
struct sock_info {
const char *name;
- char sock_path[PATH_MAX];
- int socket;
pthread_t ust_listener; /* listener thread */
int root_handle;
int constructor_sem_posted;
int allowed;
+ int global;
+
+ char sock_path[PATH_MAX];
+ int socket;
+
+ char wait_shm_path[PATH_MAX];
+ char *wait_shm_mmap;
};
/* Socket from app (connect) to session daemon (listen) for communication */
struct sock_info global_apps = {
.name = "global",
- .sock_path = DEFAULT_GLOBAL_APPS_UNIX_SOCK,
- .socket = -1,
+ .global = 1,
+
.root_handle = -1,
.allowed = 1,
+
+ .sock_path = DEFAULT_GLOBAL_APPS_UNIX_SOCK,
+ .socket = -1,
+
+ .wait_shm_path = DEFAULT_GLOBAL_APPS_WAIT_SHM_PATH,
};
/* TODO: allow global_apps_sock_path override */
struct sock_info local_apps = {
.name = "local",
- .socket = -1,
+ .global = 0,
.root_handle = -1,
.allowed = 0, /* Check setuid bit first */
+
+ .socket = -1,
};
extern void ltt_ring_buffer_client_overwrite_init(void);
int setup_local_apps(void)
{
const char *home_dir;
+ uid_t uid;
+ uid = getuid();
/*
* Disallow per-user tracing for setuid binaries.
*/
- if (getuid() != geteuid()) {
+ if (uid != geteuid()) {
local_apps.allowed = 0;
return 0;
} else {
return -ENOENT;
snprintf(local_apps.sock_path, PATH_MAX,
DEFAULT_HOME_APPS_UNIX_SOCK, home_dir);
+ snprintf(local_apps.wait_shm_path, PATH_MAX,
+ DEFAULT_HOME_APPS_WAIT_SHM_PATH, uid);
return 0;
}
if (sock_info->socket != -1) {
ret = close(sock_info->socket);
if (ret) {
- ERR("Error closing local apps socket");
+ ERR("Error closing apps socket");
}
sock_info->socket = -1;
}
}
sock_info->root_handle = -1;
}
+ sock_info->constructor_sem_posted = 0;
+ if (sock_info->wait_shm_mmap) {
+ ret = munmap(sock_info->wait_shm_mmap, sysconf(_SC_PAGE_SIZE));
+ if (ret) {
+ ERR("Error unmapping wait shm");
+ }
+ sock_info->wait_shm_mmap = NULL;
+ }
+}
+
+/*
+ * Using fork to set umask to 0777 in the child process (not
+ * multi-thread safe).
+ */
+static
+int get_wait_shm(struct sock_info *sock_info, size_t mmap_size)
+{
+ int wait_shm_fd, ret;
+ int read_mode;
+ pid_t pid;
+
+ /*
+ * At this point, we should be able to open it for
+ * reading. If it fails, then it's because there is
+ * something wrong: bail out in that case.
+ */
+ read_mode = S_IRUSR | S_IRGRP;
+ if (sock_info->global)
+ read_mode |= S_IROTH;
+
+ /*
+ * Try to open read-only. If it is set read-only, it
+ * means the shm size has been already set with
+ * ftruncate. Note: all processes creating shm need to
+ * call ftruncate on the shm before restricting its
+ * access rights to read-only. The shm should never be
+ * unlinked. It a rogue process try to create a non-accessible
+ * shm or to unlink it, the worse-case scenario is that we don't
+ * use the shm wakeup method and sleep/retry instead.
+ */
+ wait_shm_fd = shm_open(sock_info->wait_shm_path,
+ O_RDONLY, read_mode);
+ if (wait_shm_fd >= 0) {
+ goto end;
+ } else if (wait_shm_fd < 0 && errno != ENOENT) {
+ /*
+ * Real-only open did not work. It's a failure
+ * that prohibits using shm.
+ */
+ ERR("Error opening shm %s", sock_info->wait_shm_path);
+ goto end;
+ }
+
+ /*
+ * If the open failed because the file did not exist, try
+ * creating it ourself.
+ */
+ pid = fork();
+ if (pid > 0) {
+ int status;
+
+ /*
+ * Parent: wait for child to return, in which case the
+ * shared memory map will have been created.
+ */
+ pid = wait(&status);
+ if (!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, read_mode);
+ if (wait_shm_fd < 0) {
+ /*
+ * Real-only open did not work. It's a failure
+ * that prohibits using shm.
+ */
+ ERR("Error opening shm %s", sock_info->wait_shm_path);
+ goto end;
+ }
+ goto end;
+ } else if (pid == 0) {
+ int create_mode;
+
+ /* Child */
+ create_mode = S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP;
+ if (sock_info->global)
+ create_mode |= S_IROTH | S_IWOTH;
+ /*
+ * We're alone in a child process, so we can modify the
+ * process-wide umask.
+ */
+ umask(create_mode);
+ /*
+ * First try creating shm (or get rw access). We need to start
+ * by this because of the ftruncate vs concurrent map race.
+ * We need to give write access to everyone because of the
+ * ftruncate vs mmap race too. 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,
+ O_RDWR | O_CREAT, create_mode);
+ if (wait_shm_fd >= 0) {
+ ret = ftruncate(wait_shm_fd, mmap_size);
+ if (ret) {
+ PERROR("ftruncate");
+ exit(EXIT_FAILURE);
+ }
+ ret = fchmod(wait_shm_fd, read_mode);
+ if (ret) {
+ PERROR("fchmod");
+ exit(EXIT_FAILURE);
+ }
+ exit(EXIT_SUCCESS);
+ }
+ if (errno != EACCES) {
+ ERR("Error opening shm %s", sock_info->wait_shm_path);
+ exit(EXIT_FAILURE);
+ }
+ /*
+ * The shm exists, but we cannot open it RW. It means it
+ * has already been setup and ftruncated, so we can
+ * let the child exit.
+ */
+ exit(EXIT_SUCCESS);
+ } else {
+ return -1;
+ }
+end:
+ return wait_shm_fd;
+}
+
+static
+char *get_map_shm(struct sock_info *sock_info)
+{
+ size_t mmap_size = sysconf(_SC_PAGE_SIZE);
+ int wait_shm_fd, ret;
+ char *wait_shm_mmap;
+
+ wait_shm_fd = get_wait_shm(sock_info, mmap_size);
+ if (wait_shm_fd < 0) {
+ goto error;
+ }
+ wait_shm_mmap = mmap(NULL, mmap_size, PROT_READ,
+ MAP_SHARED, wait_shm_fd, 0);
+ if (wait_shm_mmap == MAP_FAILED) {
+ PERROR("mmap");
+ goto error;
+ }
+ /* close shm fd immediately after taking the mmap reference */
+ ret = close(wait_shm_fd);
+ if (ret) {
+ ERR("Error closing fd");
+ }
+ return wait_shm_mmap;
+
+error:
+ return NULL;
+}
+
+static
+void wait_for_sessiond(struct sock_info *sock_info)
+{
+ ust_lock();
+ if (lttng_ust_comm_should_quit) {
+ goto quit;
+ }
+ if (!sock_info->wait_shm_mmap) {
+ sock_info->wait_shm_mmap = get_map_shm(sock_info);
+ if (!sock_info->wait_shm_mmap)
+ goto error;
+ }
+ ust_unlock();
+
+ DBG("Waiting for %s apps sessiond", sock_info->name);
+ /* Wait for futex wakeup TODO */
+ sleep(5);
+
+ return;
+
+quit:
+ ust_unlock();
+ return;
+
+error:
+ ust_unlock();
+ /* Error handling: fallback on a 5 seconds sleep. */
+ sleep(5);
+ return;
}
/*
sock_info->socket = -1;
}
- /* Check for sessiond availability with pipe TODO */
-
/* Register */
ret = lttcomm_connect_unix_sock(sock_info->sock_path);
if (ret < 0) {
ret = handle_register_done(sock_info);
assert(!ret);
ust_unlock();
- sleep(5);
+
+ /* Wait for sessiond availability with pipe */
+ wait_for_sessiond(sock_info);
goto restart;
}
ret = handle_register_done(sock_info);
assert(!ret);
ust_unlock();
- sleep(5);
+ wait_for_sessiond(sock_info);
goto restart;
}
ust_unlock();
/* Release urcu mutexes */
rcu_bp_after_fork_child();
lttng_ust_cleanup(0);
- lttng_ust_init();
/* Release mutexes and reenable signals */
ust_after_fork_common(fork_info);
+ lttng_ust_init();
}