X-Git-Url: http://git.lttng.org./?a=blobdiff_plain;f=liblttng-ust-ctl%2Fustctl.c;h=39860ebf011870e7a9601f72d8f3b996c3e4cdc1;hb=1a3b8784434bb597b623100a591aeeb835fccf16;hp=75b32fe527c8fa9d32af7c9f0be501ddb892045d;hpb=c785c634a51956094130218c2bffeff32756cb69;p=lttng-ust.git diff --git a/liblttng-ust-ctl/ustctl.c b/liblttng-ust-ctl/ustctl.c index 75b32fe5..39860ebf 100644 --- a/liblttng-ust-ctl/ustctl.c +++ b/liblttng-ust-ctl/ustctl.c @@ -18,6 +18,10 @@ #define _GNU_SOURCE #include +#include +#include + +#include #include #include #include @@ -33,6 +37,7 @@ #include "../liblttng-ust/wait.h" #include "../liblttng-ust/lttng-rb-clients.h" #include "../liblttng-ust/clock.h" +#include "../liblttng-ust/getenv.h" /* * Number of milliseconds to retry before failing metadata writes on @@ -75,8 +80,6 @@ extern void lttng_ring_buffer_client_discard_exit(void); extern void lttng_ring_buffer_client_discard_rt_exit(void); extern void lttng_ring_buffer_metadata_client_exit(void); -volatile enum ust_loglevel ust_loglevel; - int ustctl_release_handle(int sock, int handle) { struct ustcomm_ust_msg lum; @@ -109,8 +112,10 @@ int ustctl_release_object(int sock, struct lttng_ust_object_data *data) ret = -errno; return ret; } + data->u.channel.wakeup_fd = -1; } free(data->u.channel.data); + data->u.channel.data = NULL; break; case LTTNG_UST_OBJECT_TYPE_STREAM: if (data->u.stream.shm_fd >= 0) { @@ -119,6 +124,7 @@ int ustctl_release_object(int sock, struct lttng_ust_object_data *data) ret = -errno; return ret; } + data->u.stream.shm_fd = -1; } if (data->u.stream.wakeup_fd >= 0) { ret = close(data->u.stream.wakeup_fd); @@ -126,6 +132,7 @@ int ustctl_release_object(int sock, struct lttng_ust_object_data *data) ret = -errno; return ret; } + data->u.stream.wakeup_fd = -1; } break; case LTTNG_UST_OBJECT_TYPE_EVENT: @@ -212,34 +219,86 @@ int ustctl_create_event(int sock, struct lttng_ust_event *ev, return 0; } -int ustctl_add_context(int sock, struct lttng_ust_context *ctx, +int ustctl_add_context(int sock, struct lttng_ust_context_attr *ctx, struct lttng_ust_object_data *obj_data, struct lttng_ust_object_data **_context_data) { struct ustcomm_ust_msg lum; struct ustcomm_ust_reply lur; - struct lttng_ust_object_data *context_data; + struct lttng_ust_object_data *context_data = NULL; + char *buf = NULL; + size_t len; int ret; - if (!obj_data || !_context_data) - return -EINVAL; + if (!obj_data || !_context_data) { + ret = -EINVAL; + goto end; + } context_data = zmalloc(sizeof(*context_data)); - if (!context_data) - return -ENOMEM; + if (!context_data) { + ret = -ENOMEM; + goto end; + } context_data->type = LTTNG_UST_OBJECT_TYPE_CONTEXT; memset(&lum, 0, sizeof(lum)); lum.handle = obj_data->handle; lum.cmd = LTTNG_UST_CONTEXT; - lum.u.context = *ctx; - ret = ustcomm_send_app_cmd(sock, &lum, &lur); - if (ret) { - free(context_data); - return ret; + + lum.u.context.ctx = ctx->ctx; + switch (ctx->ctx) { + case LTTNG_UST_CONTEXT_PERF_THREAD_COUNTER: + lum.u.context.u.perf_counter = ctx->u.perf_counter; + break; + case LTTNG_UST_CONTEXT_APP_CONTEXT: + { + size_t provider_name_len = strlen( + ctx->u.app_ctx.provider_name) + 1; + size_t ctx_name_len = strlen(ctx->u.app_ctx.ctx_name) + 1; + + lum.u.context.u.app_ctx.provider_name_len = provider_name_len; + lum.u.context.u.app_ctx.ctx_name_len = ctx_name_len; + + len = provider_name_len + ctx_name_len; + buf = zmalloc(len); + if (!buf) { + ret = -ENOMEM; + goto end; + } + memcpy(buf, ctx->u.app_ctx.provider_name, + provider_name_len); + memcpy(buf + provider_name_len, ctx->u.app_ctx.ctx_name, + ctx_name_len); + break; + } + default: + break; + } + ret = ustcomm_send_app_msg(sock, &lum); + if (ret) + goto end; + if (buf) { + /* send var len ctx_name */ + ret = ustcomm_send_unix_sock(sock, buf, len); + if (ret < 0) { + goto end; + } + if (ret != len) { + ret = -EINVAL; + goto end; + } + } + ret = ustcomm_recv_app_reply(sock, &lur, lum.handle, lum.cmd); + if (ret < 0) { + goto end; } context_data->handle = -1; DBG("Context created successfully"); *_context_data = context_data; + context_data = NULL; +end: + free(context_data); + free(buf); return ret; } @@ -1003,7 +1062,8 @@ struct ustctl_consumer_channel * attr->switch_timer_interval, attr->read_timer_interval, attr->uuid, attr->chan_id, - stream_fds, nr_stream_fds); + stream_fds, nr_stream_fds, + attr->blocking_timeout); if (!chan->chan) { goto chan_error; } @@ -1071,7 +1131,7 @@ int ustctl_write_metadata_to_channel( chan->ops->packet_avail_size(chan->chan, chan->handle), len - pos); lib_ring_buffer_ctx_init(&ctx, chan->chan, NULL, reserve_len, - sizeof(char), -1, chan->handle); + sizeof(char), -1, chan->handle, NULL); /* * We don't care about metadata buffer's records lost * count, because we always retry here. Report error if @@ -1118,7 +1178,7 @@ ssize_t ustctl_write_one_packet_to_channel( chan->ops->packet_avail_size(chan->chan, chan->handle), len); lib_ring_buffer_ctx_init(&ctx, chan->chan, NULL, reserve_len, - sizeof(char), -1, chan->handle); + sizeof(char), -1, chan->handle, NULL); ret = chan->ops->event_reserve(&ctx, 0); if (ret != 0) { DBG("LTTng: event reservation failed"); @@ -1447,6 +1507,25 @@ int ustctl_snapshot(struct ustctl_consumer_stream *stream) &buf->prod_snapshot, consumer_chan->chan->handle); } +/* + * Get a snapshot of the current ring buffer producer and consumer positions + * even if the consumed and produced positions are contained within the same + * subbuffer. + */ +int ustctl_snapshot_sample_positions(struct ustctl_consumer_stream *stream) +{ + struct lttng_ust_lib_ring_buffer *buf; + struct ustctl_consumer_channel *consumer_chan; + + if (!stream) + return -EINVAL; + buf = stream->buf; + consumer_chan = stream->chan; + return lib_ring_buffer_snapshot_sample_positions(buf, + &buf->cons_snapshot, &buf->prod_snapshot, + consumer_chan->chan->handle); +} + /* Get the consumer position (iteration start) */ int ustctl_snapshot_get_consumed(struct ustctl_consumer_stream *stream, unsigned long *pos) @@ -1516,6 +1595,19 @@ void ustctl_flush_buffer(struct ustctl_consumer_stream *stream, consumer_chan->chan->handle); } +void ustctl_clear_buffer(struct ustctl_consumer_stream *stream) +{ + struct lttng_ust_lib_ring_buffer *buf; + struct ustctl_consumer_channel *consumer_chan; + + assert(stream); + buf = stream->buf; + consumer_chan = stream->chan; + lib_ring_buffer_switch_slow(buf, SWITCH_ACTIVE, + consumer_chan->chan->handle); + lib_ring_buffer_clear_reader(buf, consumer_chan->chan->handle); +} + static struct lttng_ust_client_lib_ring_buffer_client_cb *get_client_cb( struct lttng_ust_lib_ring_buffer *buf, @@ -1656,7 +1748,41 @@ int ustctl_get_current_timestamp(struct ustctl_consumer_stream *stream, return client_cb->current_timestamp(buf, handle, ts); } -#if defined(__x86_64__) || defined(__i386__) +int ustctl_get_sequence_number(struct ustctl_consumer_stream *stream, + uint64_t *seq) +{ + struct lttng_ust_client_lib_ring_buffer_client_cb *client_cb; + struct lttng_ust_lib_ring_buffer *buf; + struct lttng_ust_shm_handle *handle; + + if (!stream || !seq) + return -EINVAL; + buf = stream->buf; + handle = stream->chan->chan->handle; + client_cb = get_client_cb(buf, handle); + if (!client_cb || !client_cb->sequence_number) + return -ENOSYS; + return client_cb->sequence_number(buf, handle, seq); +} + +int ustctl_get_instance_id(struct ustctl_consumer_stream *stream, + uint64_t *id) +{ + struct lttng_ust_client_lib_ring_buffer_client_cb *client_cb; + struct lttng_ust_lib_ring_buffer *buf; + struct lttng_ust_shm_handle *handle; + + if (!stream || !id) + return -EINVAL; + buf = stream->buf; + handle = stream->chan->chan->handle; + client_cb = get_client_cb(buf, handle); + if (!client_cb) + return -ENOSYS; + return client_cb->instance_id(buf, handle, id); +} + +#ifdef LTTNG_UST_HAVE_PERF_EVENT int ustctl_has_perf_counters(void) { @@ -1672,6 +1798,105 @@ int ustctl_has_perf_counters(void) #endif +#ifdef __linux__ +/* + * Override application pid/uid/gid with unix socket credentials. If + * the application announced a pid matching our view, it means it is + * within the same pid namespace, so expose the ppid provided by the + * application. + */ +static +int get_cred(int sock, + const struct ustctl_reg_msg *reg_msg, + uint32_t *pid, + uint32_t *ppid, + uint32_t *uid, + uint32_t *gid) +{ + struct ucred ucred; + socklen_t ucred_len = sizeof(struct ucred); + int ret; + + ret = getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &ucred, &ucred_len); + if (ret) { + return -LTTNG_UST_ERR_PEERCRED; + } + DBG("Unix socket peercred [ pid: %u, uid: %u, gid: %u ], " + "application registered claiming [ pid: %u, ppid: %u, uid: %u, gid: %u ]", + ucred.pid, ucred.uid, ucred.gid, + reg_msg->pid, reg_msg->ppid, reg_msg->uid, reg_msg->gid); + if (!ucred.pid) { + ERR("Unix socket credential pid=0. Refusing application in distinct, non-nested pid namespace."); + return -LTTNG_UST_ERR_PEERCRED_PID; + } + *pid = ucred.pid; + *uid = ucred.uid; + *gid = ucred.gid; + if (ucred.pid == reg_msg->pid) { + *ppid = reg_msg->ppid; + } else { + *ppid = 0; + } + return 0; +} +#elif defined(__FreeBSD__) +#include +#include + +/* + * Override application uid/gid with unix socket credentials. Use the + * first group of the cr_groups. + * Use the pid and ppid provided by the application on registration. + */ +static +int get_cred(int sock, + const struct ustctl_reg_msg *reg_msg, + uint32_t *pid, + uint32_t *ppid, + uint32_t *uid, + uint32_t *gid) +{ + struct xucred xucred; + socklen_t xucred_len = sizeof(struct xucred); + int ret; + + ret = getsockopt(sock, SOL_SOCKET, LOCAL_PEERCRED, &xucred, &xucred_len); + if (ret) { + return -LTTNG_UST_ERR_PEERCRED; + } + if (xucred.cr_version != XUCRED_VERSION || xucred.cr_ngroups < 1) { + return -LTTNG_UST_ERR_PEERCRED; + } + DBG("Unix socket peercred [ uid: %u, gid: %u ], " + "application registered claiming [ pid: %d, ppid: %d, uid: %u, gid: %u ]", + xucred.cr_uid, xucred.cr_groups[0], + reg_msg->pid, reg_msg->ppid, reg_msg->uid, reg_msg->gid); + *pid = reg_msg->pid; + *ppid = reg_msg->ppid; + *uid = xucred.cr_uid; + *gid = xucred.cr_groups[0]; + return 0; +} +#else +#warning "Using insecure fallback: trusting user id provided by registered applications. Please consider implementing use of unix socket credentials on your platform." +static +int get_cred(int sock, + const struct ustctl_reg_msg *reg_msg, + uint32_t *pid, + uint32_t *ppid, + uint32_t *uid, + uint32_t *gid) +{ + DBG("Application registered claiming [ pid: %u, ppid: %d, uid: %u, gid: %u ]", + reg_msg->pid, reg_msg->ppid, reg_msg->uid, reg_msg->gid); + *pid = reg_msg->pid; + *ppid = reg_msg->ppid; + *uid = reg_msg->uid; + *gid = reg_msg->gid; + return 0; +} +#endif + /* * Returns 0 on success, negative error value on error. */ @@ -1722,10 +1947,6 @@ int ustctl_recv_reg_msg(int sock, } *major = reg_msg.major; *minor = reg_msg.minor; - *pid = reg_msg.pid; - *ppid = reg_msg.ppid; - *uid = reg_msg.uid; - *gid = reg_msg.gid; *bits_per_long = reg_msg.bits_per_long; *uint8_t_alignment = reg_msg.uint8_t_alignment; *uint16_t_alignment = reg_msg.uint16_t_alignment; @@ -1736,8 +1957,7 @@ int ustctl_recv_reg_msg(int sock, if (reg_msg.major != LTTNG_UST_ABI_MAJOR_VERSION) { return -LTTNG_UST_ERR_UNSUP_MAJOR; } - - return 0; + return get_cred(sock, ®_msg, pid, ppid, uid, gid); } int ustctl_recv_notify(int sock, enum ustctl_notify_cmd *notify_cmd) @@ -2097,10 +2317,28 @@ int ustctl_reply_register_channel(int sock, return 0; } +/* Regenerate the statedump. */ +int ustctl_regenerate_statedump(int sock, int handle) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + int ret; + + memset(&lum, 0, sizeof(lum)); + lum.handle = handle; + lum.cmd = LTTNG_UST_SESSION_STATEDUMP; + ret = ustcomm_send_app_cmd(sock, &lum, &lur); + if (ret) + return ret; + DBG("Regenerated statedump for handle %u", handle); + return 0; +} + static __attribute__((constructor)) void ustctl_init(void) { init_usterr(); + lttng_ust_getenv_init(); /* Needs init_usterr() to be completed. */ lttng_ust_clock_init(); lttng_ring_buffer_metadata_client_init(); lttng_ring_buffer_client_overwrite_init();