From 4628484ae860b8cf506427e864c7d1933da32777 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Mon, 15 Dec 2014 20:24:46 -0500 Subject: [PATCH] Move file creation/unlink from liblttng-ust-ctl to consumerd MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Mathieu Desnoyers Signed-off-by: Jérémie Galarneau --- src/bin/lttng-sessiond/ust-registry.c | 14 +- src/bin/lttng-sessiond/ust-registry.h | 4 + src/common/consumer.h | 2 + src/common/runas.c | 58 ++++++++ src/common/runas.h | 2 + src/common/ust-consumer/ust-consumer.c | 191 ++++++++++++++++++++++--- 6 files changed, 249 insertions(+), 22 deletions(-) diff --git a/src/bin/lttng-sessiond/ust-registry.c b/src/bin/lttng-sessiond/ust-registry.c index f9ddd25a5..2ba41ed45 100644 --- a/src/bin/lttng-sessiond/ust-registry.c +++ b/src/bin/lttng-sessiond/ust-registry.c @@ -572,6 +572,8 @@ int ust_registry_session_init(struct ust_registry_session **sessionp, session->long_alignment = long_alignment; session->byte_order = byte_order; session->metadata_fd = -1; + session->uid = euid; + session->gid = egid; strncpy(session->root_shm_path, root_shm_path, sizeof(session->root_shm_path)); session->root_shm_path[sizeof(session->root_shm_path) - 1] = '\0'; @@ -591,16 +593,18 @@ int ust_registry_session_init(struct ust_registry_session **sessionp, S_IRWXU | S_IRWXG, euid, egid); if (ret) { + errno = -ret; PERROR("run_as_mkdir_recursive"); goto error; } } if (session->metadata_path[0]) { /* Create metadata file */ - ret = open(session->metadata_path, + ret = run_as_open(session->metadata_path, O_WRONLY | O_CREAT | O_EXCL, - S_IRUSR | S_IWUSR); + S_IRUSR | S_IWUSR, euid, egid); if (ret < 0) { + errno = -ret; PERROR("Opening metadata file"); goto error; } @@ -675,7 +679,8 @@ void ust_registry_session_destroy(struct ust_registry_session *reg) if (ret) { PERROR("close"); } - ret = unlink(reg->metadata_path); + ret = run_as_unlink(reg->metadata_path, + reg->uid, reg->gid); if (ret) { PERROR("unlink"); } @@ -684,6 +689,7 @@ void ust_registry_session_destroy(struct ust_registry_session *reg) /* * Try deleting the directory hierarchy. */ - (void) utils_recursive_rmdir(reg->root_shm_path); + (void) run_as_recursive_rmdir(reg->root_shm_path, + reg->uid, reg->gid); } } diff --git a/src/bin/lttng-sessiond/ust-registry.h b/src/bin/lttng-sessiond/ust-registry.h index 91a0534e9..77d4d9195 100644 --- a/src/bin/lttng-sessiond/ust-registry.h +++ b/src/bin/lttng-sessiond/ust-registry.h @@ -87,6 +87,10 @@ struct ust_registry_session { * deletes its sessions. */ unsigned int metadata_closed; + + /* User and group owning the session. */ + uid_t uid; + gid_t gid; }; struct ust_registry_channel { diff --git a/src/common/consumer.h b/src/common/consumer.h index 7f885370e..509e24e01 100644 --- a/src/common/consumer.h +++ b/src/common/consumer.h @@ -207,6 +207,8 @@ struct lttng_consumer_channel { /* Timer value in usec for live streaming. */ unsigned int live_timer_interval; + int *stream_fds; + int nr_stream_fds; char root_shm_path[PATH_MAX]; char shm_path[PATH_MAX]; }; diff --git a/src/common/runas.c b/src/common/runas.c index 471bb2204..9d9091638 100644 --- a/src/common/runas.c +++ b/src/common/runas.c @@ -79,6 +79,14 @@ struct run_as_open_data { mode_t mode; }; +struct run_as_unlink_data { + const char *path; +}; + +struct run_as_recursive_rmdir_data { + const char *path; +}; + #ifdef VALGRIND static int use_clone(void) @@ -130,6 +138,34 @@ int _open(void *_data) return open(data->path, data->flags, data->mode); } +static +int _unlink(void *_data) +{ + int ret; + struct run_as_unlink_data *data = _data; + + ret = unlink(data->path); + if (ret < 0) { + ret = -errno; + } + + return ret; +} + +static +int _recursive_rmdir(void *_data) +{ + int ret; + struct run_as_recursive_rmdir_data *data = _data; + + ret = utils_recursive_rmdir(data->path); + if (ret < 0) { + ret = -errno; + } + + return ret; +} + static int child_run_as(void *_data) { @@ -341,3 +377,25 @@ int run_as_open(const char *path, int flags, mode_t mode, uid_t uid, gid_t gid) data.mode = mode; return run_as(_open, &data, uid, gid); } + +LTTNG_HIDDEN +int run_as_unlink(const char *path, uid_t uid, gid_t gid) +{ + struct run_as_unlink_data data; + + DBG3("unlink() %s with for uid %d and gid %d", + path, uid, gid); + data.path = path; + return run_as(_unlink, &data, uid, gid); +} + +LTTNG_HIDDEN +int run_as_recursive_rmdir(const char *path, uid_t uid, gid_t gid) +{ + struct run_as_recursive_rmdir_data data; + + DBG3("recursive_rmdir() %s with for uid %d and gid %d", + path, uid, gid); + data.path = path; + return run_as(_recursive_rmdir, &data, uid, gid); +} diff --git a/src/common/runas.h b/src/common/runas.h index 9840eb056..dc25322cc 100644 --- a/src/common/runas.h +++ b/src/common/runas.h @@ -25,6 +25,8 @@ int run_as_mkdir_recursive(const char *path, mode_t mode, uid_t uid, gid_t gid); int run_as_mkdir(const char *path, mode_t mode, uid_t uid, gid_t gid); int run_as_open(const char *path, int flags, mode_t mode, uid_t uid, gid_t gid); +int run_as_unlink(const char *path, uid_t uid, gid_t gid); +int run_as_recursive_rmdir(const char *path, uid_t uid, gid_t gid); /* * We need to lock pthread exit, which deadlocks __nptl_setxid in the diff --git a/src/common/ust-consumer/ust-consumer.c b/src/common/ust-consumer/ust-consumer.c index 6898bb115..fbc3bbb43 100644 --- a/src/common/ust-consumer/ust-consumer.c +++ b/src/common/ust-consumer/ust-consumer.c @@ -47,6 +47,8 @@ #include "ust-consumer.h" +#define UINT_MAX_STR_LEN 11 /* includes \0 */ + extern struct lttng_consumer_global_data consumer_data; extern int consumer_poll_timeout; extern volatile int consumer_quit; @@ -81,10 +83,6 @@ static void destroy_channel(struct lttng_consumer_channel *channel) if (channel->uchan) { lttng_ustconsumer_del_channel(channel); } - /* Try to rmdir all directories under shm_path root. */ - if (channel->root_shm_path[0]) { - (void) utils_recursive_rmdir(channel->root_shm_path); - } free(channel); } @@ -246,6 +244,26 @@ error: return ret; } +static +int get_stream_shm_path(char *stream_shm_path, const char *shm_path, int cpu) +{ + char cpu_nr[UINT_MAX_STR_LEN]; /* unsigned int max len */ + int ret; + + strncpy(stream_shm_path, shm_path, PATH_MAX); + stream_shm_path[PATH_MAX - 1] = '\0'; + ret = snprintf(cpu_nr, UINT_MAX_STR_LEN, "%u", cpu); + if (ret != 1) { + ret = -1; + goto end; + } + strncat(stream_shm_path, cpu_nr, + PATH_MAX - strlen(stream_shm_path) - 1); + ret = 0; +end: + return ret; +} + /* * Create streams for the given channel using liblttng-ust-ctl. * @@ -346,20 +364,87 @@ error_alloc: return ret; } +/* + * create_posix_shm is never called concurrently within a process. + */ +static +int create_posix_shm(void) +{ + char tmp_name[NAME_MAX]; + int shmfd, ret; + + ret = snprintf(tmp_name, NAME_MAX, "/ust-shm-consumer-%d", getpid()); + if (ret < 0) { + PERROR("snprintf"); + return -1; + } + /* + * Allocate shm, and immediately unlink its shm oject, keeping + * only the file descriptor as a reference to the object. + * We specifically do _not_ use the / at the beginning of the + * pathname so that some OS implementations can keep it local to + * the process (POSIX leaves this implementation-defined). + */ + shmfd = shm_open(tmp_name, O_CREAT | O_EXCL | O_RDWR, 0700); + if (shmfd < 0) { + PERROR("shm_open"); + goto error_shm_open; + } + ret = shm_unlink(tmp_name); + if (ret < 0 && errno != ENOENT) { + PERROR("shm_unlink"); + goto error_shm_release; + } + return shmfd; + +error_shm_release: + ret = close(shmfd); + if (ret) { + PERROR("close"); + } +error_shm_open: + return -1; +} + +static int open_ust_stream_fd(struct lttng_consumer_channel *channel, + struct ustctl_consumer_channel_attr *attr, + int cpu) +{ + char shm_path[PATH_MAX]; + int ret; + + if (!channel->shm_path[0]) { + return create_posix_shm(); + } + ret = get_stream_shm_path(shm_path, channel->shm_path, cpu); + if (ret) { + goto error_shm_path; + } + return run_as_open(shm_path, + O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, + channel->uid, channel->gid); + +error_shm_path: + return -1; +} + /* * Create an UST channel with the given attributes and send it to the session * daemon using the ust ctl API. * * Return 0 on success or else a negative value. */ -static int create_ust_channel(struct ustctl_consumer_channel_attr *attr, - struct ustctl_consumer_channel **chanp) +static int create_ust_channel(struct lttng_consumer_channel *channel, + struct ustctl_consumer_channel_attr *attr, + struct ustctl_consumer_channel **ust_chanp) { - int ret; - struct ustctl_consumer_channel *channel; + int ret, nr_stream_fds, i, j; + int *stream_fds; + struct ustctl_consumer_channel *ust_channel; + assert(channel); assert(attr); - assert(chanp); + assert(ust_chanp); DBG3("Creating channel to ustctl with attr: [overwrite: %d, " "subbuf_size: %" PRIu64 ", num_subbuf: %" PRIu64 ", " @@ -368,17 +453,65 @@ static int create_ust_channel(struct ustctl_consumer_channel_attr *attr, attr->num_subbuf, attr->switch_timer_interval, attr->read_timer_interval, attr->output, attr->type); - channel = ustctl_create_channel(attr); - if (!channel) { + if (channel->type == CONSUMER_CHANNEL_TYPE_METADATA) + nr_stream_fds = 1; + else + nr_stream_fds = ustctl_get_nr_stream_per_channel(); + stream_fds = zmalloc(nr_stream_fds * sizeof(*stream_fds)); + if (!stream_fds) { + ret = -1; + goto error_alloc; + } + for (i = 0; i < nr_stream_fds; i++) { + stream_fds[i] = open_ust_stream_fd(channel, attr, i); + if (stream_fds[i] < 0) { + ret = -1; + goto error_open; + } + } + ust_channel = ustctl_create_channel(attr, stream_fds, nr_stream_fds); + if (!ust_channel) { ret = -1; goto error_create; } - - *chanp = channel; + channel->nr_stream_fds = nr_stream_fds; + channel->stream_fds = stream_fds; + *ust_chanp = ust_channel; return 0; error_create: +error_open: + for (j = i - 1; j >= 0; j--) { + int closeret; + + closeret = close(stream_fds[j]); + if (closeret) { + PERROR("close"); + } + if (channel->shm_path[0]) { + char shm_path[PATH_MAX]; + + closeret = get_stream_shm_path(shm_path, + channel->shm_path, j); + if (closeret) { + ERR("Cannot get stream shm path"); + } + closeret = run_as_unlink(shm_path, + channel->uid, channel->gid); + if (closeret) { + errno = -closeret; + PERROR("unlink %s", shm_path); + } + } + } + /* Try to rmdir all directories under shm_path root. */ + if (channel->root_shm_path[0]) { + (void) run_as_recursive_rmdir(channel->root_shm_path, + channel->uid, channel->gid); + } + free(stream_fds); +error_alloc: return ret; } @@ -532,7 +665,7 @@ static int ask_channel(struct lttng_consumer_local_data *ctx, int sock, channel->nb_init_stream_left = 0; /* The reply msg status is handled in the following call. */ - ret = create_ust_channel(attr, &channel->uchan); + ret = create_ust_channel(channel, attr, &channel->uchan); if (ret < 0) { goto end; } @@ -1238,9 +1371,6 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx, attr.read_timer_interval = msg.u.ask_channel.read_timer_interval; attr.chan_id = msg.u.ask_channel.chan_id; memcpy(attr.uuid, msg.u.ask_channel.uuid, sizeof(attr.uuid)); - strncpy(attr.shm_path, channel->shm_path, - sizeof(attr.shm_path)); - attr.shm_path[sizeof(attr.shm_path) - 1] = '\0'; /* Match channel buffer type to the UST abi. */ switch (msg.u.ask_channel.output) { @@ -1675,6 +1805,8 @@ void lttng_ustconsumer_on_stream_hangup(struct lttng_consumer_stream *stream) void lttng_ustconsumer_del_channel(struct lttng_consumer_channel *chan) { + int i; + assert(chan); assert(chan->uchan); @@ -1683,9 +1815,32 @@ void lttng_ustconsumer_del_channel(struct lttng_consumer_channel *chan) } consumer_metadata_cache_destroy(chan); ustctl_destroy_channel(chan->uchan); + for (i = 0; i < chan->nr_stream_fds; i++) { + int ret; + + ret = close(chan->stream_fds[i]); + if (ret) { + PERROR("close"); + } + if (chan->shm_path[0]) { + char shm_path[PATH_MAX]; + + ret = get_stream_shm_path(shm_path, chan->shm_path, i); + if (ret) { + ERR("Cannot get stream shm path"); + } + ret = run_as_unlink(shm_path, chan->uid, chan->gid); + if (ret) { + errno = -ret; + PERROR("unlink %s", shm_path); + } + } + } + free(chan->stream_fds); /* Try to rmdir all directories under shm_path root. */ if (chan->root_shm_path[0]) { - (void) utils_recursive_rmdir(chan->root_shm_path); + (void) run_as_recursive_rmdir(chan->root_shm_path, + chan->uid, chan->gid); } } -- 2.34.1