#include "common/dynamic-array.h"
#include "common/payload.h"
#include "common/payload-view.h"
+#include "common/fd-handle.h"
#include "common/sessiond-comm/sessiond-comm.h"
+#include "common/payload.h"
+#include "common/payload-view.h"
#include "lttng/lttng-error.h"
#include "lttng/tracker.h"
#include <common/compat/getenv.h>
#include <signal.h>
#include <stddef.h>
#include <sys/stat.h>
+#include <unistd.h>
#include "client.h"
#include "lttng-sessiond.h"
.data_size = payload_len,
};
- lttng_dynamic_buffer_set_size(&cmd_ctx->reply_payload.buffer, 0);
+ ret = lttng_dynamic_buffer_set_size(&cmd_ctx->reply_payload.buffer, 0);
+ if (ret) {
+ goto end;
+ }
+
+ lttng_dynamic_pointer_array_clear(&cmd_ctx->reply_payload._fd_handles);
cmd_ctx->lttng_msg_size = total_msg_size;
return ret;
}
+static int setup_empty_lttng_msg(struct command_ctx *cmd_ctx)
+{
+ int ret;
+ const struct lttcomm_lttng_msg llm = {};
+
+ ret = lttng_dynamic_buffer_set_size(&cmd_ctx->reply_payload.buffer, 0);
+ if (ret) {
+ goto end;
+ }
+
+ /* Append place-holder reply header. */
+ ret = lttng_dynamic_buffer_append(
+ &cmd_ctx->reply_payload.buffer, &llm, sizeof(llm));
+ if (ret) {
+ goto end;
+ }
+
+ cmd_ctx->lttng_msg_size = sizeof(llm);
+end:
+ return ret;
+}
+
+static void update_lttng_msg(struct command_ctx *cmd_ctx, size_t cmd_header_len,
+ size_t payload_len)
+{
+ const size_t header_len = sizeof(struct lttcomm_lttng_msg);
+ const size_t total_msg_size = header_len + cmd_header_len + payload_len;
+ const struct lttcomm_lttng_msg llm = {
+ .cmd_type = cmd_ctx->lsm.cmd_type,
+ .pid = cmd_ctx->lsm.domain.attr.pid,
+ .cmd_header_size = cmd_header_len,
+ .data_size = payload_len,
+ };
+ struct lttcomm_lttng_msg *p_llm;
+
+ assert(cmd_ctx->reply_payload.buffer.size >= sizeof(llm));
+
+ p_llm = (typeof(p_llm)) cmd_ctx->reply_payload.buffer.data;
+
+ /* Update existing header. */
+ memcpy(p_llm, &llm, sizeof(llm));
+
+ cmd_ctx->lttng_msg_size = total_msg_size;
+}
+
/*
* Start the thread_manage_consumer. This must be done after a lttng-consumerd
* exec or it will fail.
struct ltt_session *session;
const struct ltt_session_list *session_list = session_get_list();
- DBG("Counting number of available session for UID %d GID %d",
- uid, gid);
+ DBG("Counting number of available session for UID %d", uid);
cds_list_for_each_entry(session, &session_list->head, list) {
if (!session_get(session)) {
continue;
}
session_lock(session);
/* Only count the sessions the user can control. */
- if (session_access_ok(session, uid, gid) &&
+ if (session_access_ok(session, uid) &&
!session->destroyed) {
i++;
}
static int receive_userspace_probe(struct command_ctx *cmd_ctx, int sock,
int *sock_error, struct lttng_event *event)
{
- int fd, ret;
+ int fd = -1, ret;
struct lttng_userspace_probe_location *probe_location;
- const struct lttng_userspace_probe_location_lookup_method *lookup = NULL;
- struct lttng_dynamic_buffer probe_location_buffer;
- struct lttng_buffer_view buffer_view;
+ struct lttng_payload probe_location_payload;
+ struct fd_handle *handle = NULL;
/*
- * Create a buffer to store the serialized version of the probe
+ * Create a payload to store the serialized version of the probe
* location.
*/
- lttng_dynamic_buffer_init(&probe_location_buffer);
- ret = lttng_dynamic_buffer_set_size(&probe_location_buffer,
+ lttng_payload_init(&probe_location_payload);
+
+ ret = lttng_dynamic_buffer_set_size(&probe_location_payload.buffer,
cmd_ctx->lsm.u.enable.userspace_probe_location_len);
if (ret) {
ret = LTTNG_ERR_NOMEM;
/*
* Receive the probe location.
*/
- ret = lttcomm_recv_unix_sock(sock, probe_location_buffer.data,
- probe_location_buffer.size);
+ ret = lttcomm_recv_unix_sock(sock, probe_location_payload.buffer.data,
+ probe_location_payload.buffer.size);
if (ret <= 0) {
DBG("Nothing recv() from client var len data... continuing");
*sock_error = 1;
- lttng_dynamic_buffer_reset(&probe_location_buffer);
- ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
- goto error;
- }
-
- buffer_view = lttng_buffer_view_from_dynamic_buffer(
- &probe_location_buffer, 0, probe_location_buffer.size);
-
- /*
- * Extract the probe location from the serialized version.
- */
- ret = lttng_userspace_probe_location_create_from_buffer(
- &buffer_view, &probe_location);
- if (ret < 0) {
- WARN("Failed to create a userspace probe location from the received buffer");
- lttng_dynamic_buffer_reset( &probe_location_buffer);
ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
goto error;
}
goto error;
}
- /*
- * Set the file descriptor received from the client through the unix
- * socket in the probe location.
- */
- lookup = lttng_userspace_probe_location_get_lookup_method(probe_location);
- if (!lookup) {
- ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
+ handle = fd_handle_create(fd);
+ if (!handle) {
+ ret = LTTNG_ERR_NOMEM;
goto error;
}
- /*
- * From the kernel tracer's perspective, all userspace probe event types
- * are all the same: a file and an offset.
- */
- switch (lttng_userspace_probe_location_lookup_method_get_type(lookup)) {
- case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF:
- ret = lttng_userspace_probe_location_function_set_binary_fd(
- probe_location, fd);
- break;
- case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT:
- ret = lttng_userspace_probe_location_tracepoint_set_binary_fd(
- probe_location, fd);
- break;
- default:
- ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
+ /* Transferred to the handle. */
+ fd = -1;
+
+ ret = lttng_payload_push_fd_handle(&probe_location_payload, handle);
+ if (ret) {
+ ERR("Failed to add userspace probe file descriptor to payload");
+ ret = LTTNG_ERR_NOMEM;
goto error;
}
- if (ret) {
+ fd_handle_put(handle);
+ handle = NULL;
+
+ {
+ struct lttng_payload_view view = lttng_payload_view_from_payload(
+ &probe_location_payload, 0, -1);
+
+ /* Extract the probe location from the serialized version. */
+ ret = lttng_userspace_probe_location_create_from_payload(
+ &view, &probe_location);
+ }
+ if (ret < 0) {
+ WARN("Failed to create a userspace probe location from the received buffer");
ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
goto error;
}
goto error;
}
- lttng_dynamic_buffer_reset(&probe_location_buffer);
error:
+ if (fd >= 0) {
+ if (close(fd)) {
+ PERROR("Failed to close userspace probe location binary fd");
+ }
+ }
+
+ fd_handle_put(handle);
+ lttng_payload_reset(&probe_location_payload);
return ret;
}
+static enum lttng_error_code receive_lttng_trigger(struct command_ctx *cmd_ctx,
+ int sock,
+ int *sock_error,
+ struct lttng_trigger **_trigger)
+{
+ int ret;
+ size_t trigger_len;
+ ssize_t sock_recv_len;
+ enum lttng_error_code ret_code;
+ struct lttng_payload trigger_payload;
+ struct lttng_trigger *trigger;
+
+ lttng_payload_init(&trigger_payload);
+ trigger_len = (size_t) cmd_ctx->lsm.u.trigger.length;
+ ret = lttng_dynamic_buffer_set_size(
+ &trigger_payload.buffer, trigger_len);
+ if (ret) {
+ ret_code = LTTNG_ERR_NOMEM;
+ goto end;
+ }
+
+ sock_recv_len = lttcomm_recv_unix_sock(
+ sock, trigger_payload.buffer.data, trigger_len);
+ if (sock_recv_len < 0 || sock_recv_len != trigger_len) {
+ ERR("Failed to receive trigger in command payload");
+ *sock_error = 1;
+ ret_code = LTTNG_ERR_INVALID_PROTOCOL;
+ goto end;
+ }
+
+ /* Receive fds, if any. */
+ if (cmd_ctx->lsm.fd_count > 0) {
+ sock_recv_len = lttcomm_recv_payload_fds_unix_sock(
+ sock, cmd_ctx->lsm.fd_count, &trigger_payload);
+ if (sock_recv_len > 0 &&
+ sock_recv_len != cmd_ctx->lsm.fd_count * sizeof(int)) {
+ ERR("Failed to receive all file descriptors for trigger in command payload: expected fd count = %u, ret = %d",
+ cmd_ctx->lsm.fd_count, (int) ret);
+ ret_code = LTTNG_ERR_INVALID_PROTOCOL;
+ *sock_error = 1;
+ goto end;
+ } else if (sock_recv_len <= 0) {
+ ERR("Failed to receive file descriptors for trigger in command payload: expected fd count = %u, ret = %d",
+ cmd_ctx->lsm.fd_count, (int) ret);
+ ret_code = LTTNG_ERR_FATAL;
+ *sock_error = 1;
+ goto end;
+ }
+ }
+
+ /* Deserialize trigger. */
+ {
+ struct lttng_payload_view view =
+ lttng_payload_view_from_payload(
+ &trigger_payload, 0, -1);
+
+ if (lttng_trigger_create_from_payload(&view, &trigger) !=
+ trigger_len) {
+ ERR("Invalid trigger received as part of command payload");
+ ret_code = LTTNG_ERR_INVALID_TRIGGER;
+ goto end;
+ }
+ }
+
+ *_trigger = trigger;
+ ret_code = LTTNG_OK;
+
+end:
+ return ret_code;
+}
+
/*
* Version of setup_lttng_msg() without command header.
*/
static int send_unix_sock(int sock, struct lttng_payload_view *view)
{
int ret;
+ const int fd_count = lttng_payload_view_get_fd_handle_count(view);
/* Check valid length */
if (view->buffer.size == 0) {
goto end;
}
- if (lttng_dynamic_array_get_count(&view->_fds) > 0) {
- ret = lttcomm_send_fds_unix_sock(sock,
- (const int *) view->_fds.buffer.data,
- lttng_dynamic_array_get_count(&view->_fds));
+ if (fd_count > 0) {
+ ret = lttcomm_send_payload_view_fds_unix_sock(sock, view);
+ if (ret < 0) {
+ goto end;
+ }
}
end:
int *sock_error)
{
int ret = LTTNG_OK;
- int need_tracing_session = 1;
- int need_domain;
+ bool need_tracing_session = true;
+ bool need_domain;
+ bool need_consumerd;
- DBG("Processing client command %d", cmd_ctx->lsm.cmd_type);
+ DBG("Processing client command '%s\' (%d)",
+ lttcomm_sessiond_command_str(cmd_ctx->lsm.cmd_type),
+ cmd_ctx->lsm.cmd_type);
assert(!rcu_read_ongoing());
case LTTNG_SET_SESSION_SHM_PATH:
case LTTNG_REGENERATE_METADATA:
case LTTNG_REGENERATE_STATEDUMP:
- case LTTNG_REGISTER_TRIGGER:
- case LTTNG_UNREGISTER_TRIGGER:
case LTTNG_ROTATE_SESSION:
case LTTNG_ROTATION_GET_INFO:
case LTTNG_ROTATION_SET_SCHEDULE:
case LTTNG_SESSION_LIST_ROTATION_SCHEDULES:
case LTTNG_CLEAR_SESSION:
- need_domain = 0;
+ case LTTNG_LIST_TRIGGERS:
+ need_domain = false;
+ break;
+ default:
+ need_domain = true;
+ }
+
+ /* Needs a functioning consumerd? */
+ switch (cmd_ctx->lsm.cmd_type) {
+ case LTTNG_REGISTER_TRIGGER:
+ case LTTNG_UNREGISTER_TRIGGER:
+ need_consumerd = false;
break;
default:
- need_domain = 1;
+ need_consumerd = true;
+ break;
}
if (config.no_kernel && need_domain
case LTTNG_DATA_PENDING:
case LTTNG_ROTATE_SESSION:
case LTTNG_ROTATION_GET_INFO:
+ case LTTNG_REGISTER_TRIGGER:
+ case LTTNG_LIST_TRIGGERS:
break;
default:
/* Setup lttng message with no payload */
case LTTNG_SAVE_SESSION:
case LTTNG_REGISTER_TRIGGER:
case LTTNG_UNREGISTER_TRIGGER:
- need_tracing_session = 0;
+ case LTTNG_LIST_TRIGGERS:
+ need_tracing_session = false;
break;
default:
DBG("Getting session %s by name", cmd_ctx->lsm.session.name);
}
/* Consumer is in an ERROR state. Report back to client */
- if (uatomic_read(&kernel_consumerd_state) == CONSUMER_ERROR) {
+ if (need_consumerd && uatomic_read(&kernel_consumerd_state) ==
+ CONSUMER_ERROR) {
ret = LTTNG_ERR_NO_KERNCONSUMERD;
goto error;
}
ret = LTTNG_ERR_NO_UST;
goto error;
}
+
/* Consumer is in an ERROR state. Report back to client */
- if (uatomic_read(&ust_consumerd_state) == CONSUMER_ERROR) {
+ if (need_consumerd && uatomic_read(&ust_consumerd_state) ==
+ CONSUMER_ERROR) {
ret = LTTNG_ERR_NO_USTCONSUMERD;
goto error;
}
}
/*
- * Check that the UID or GID match that of the tracing session.
+ * Check that the UID matches that of the tracing session.
* The root user can interact with all sessions.
*/
if (need_tracing_session) {
if (!session_access_ok(cmd_ctx->session,
- LTTNG_SOCK_GET_UID_CRED(&cmd_ctx->creds),
- LTTNG_SOCK_GET_GID_CRED(&cmd_ctx->creds)) ||
+ LTTNG_SOCK_GET_UID_CRED(&cmd_ctx->creds)) ||
cmd_ctx->session->destroyed) {
ret = LTTNG_ERR_EPERM;
goto error;
.value_type;
struct process_attr_value *value;
enum lttng_error_code ret_code;
+ long login_name_max;
+
+ login_name_max = sysconf(_SC_LOGIN_NAME_MAX);
+ if (login_name_max < 0) {
+ PERROR("Failed to get _SC_LOGIN_NAME_MAX system configuration");
+ ret = LTTNG_ERR_INVALID;
+ goto error;
+ }
/* Receive remaining variable length payload if applicable. */
- if (name_len > LOGIN_NAME_MAX) {
+ if (name_len > login_name_max) {
/*
* POSIX mandates user and group names that are at least
* 8 characters long. Note that although shadow-utils
* limit (from bits/utmp.h, UT_NAMESIZE),
* LOGIN_NAME_MAX is defined to 256.
*/
- ERR("Rejecting process attribute tracker value %s as the provided exceeds the maximal allowed length: argument length = %zu, maximal length = %d",
+ ERR("Rejecting process attribute tracker value %s as the provided exceeds the maximal allowed length: argument length = %zu, maximal length = %ld",
add_value ? "addition" : "removal",
- name_len, LOGIN_NAME_MAX);
+ name_len, login_name_max);
ret = LTTNG_ERR_INVALID;
goto error;
}
payload_view = lttng_buffer_view_from_dynamic_buffer(
&payload, 0, name_len);
+ if (name_len > 0 && !lttng_buffer_view_is_valid(&payload_view)) {
+ ret = LTTNG_ERR_INVALID_PROTOCOL;
+ goto error_add_remove_tracker_value;
+ }
+
/*
* Validate the value type and domains are legal for the process
* attribute tracker that is specified and convert the value to
}
case LTTNG_LIST_EVENTS:
{
- ssize_t nb_event;
- struct lttng_event *events = NULL;
- struct lttcomm_event_command_header cmd_header;
- size_t total_size;
-
- memset(&cmd_header, 0, sizeof(cmd_header));
- /* Extended infos are included at the end of events */
- nb_event = cmd_list_events(cmd_ctx->lsm.domain.type,
- cmd_ctx->session, cmd_ctx->lsm.u.list.channel_name,
- &events, &total_size);
-
- if (nb_event < 0) {
- /* Return value is a negative lttng_error_code. */
- ret = -nb_event;
- goto error;
+ ssize_t list_ret;
+ struct lttcomm_event_command_header cmd_header = {};
+ size_t original_payload_size;
+ size_t payload_size;
+
+ ret = setup_empty_lttng_msg(cmd_ctx);
+ if (ret) {
+ ret = LTTNG_ERR_NOMEM;
+ goto setup_error;
}
- cmd_header.nb_events = nb_event;
- ret = setup_lttng_msg(cmd_ctx, events, total_size,
- &cmd_header, sizeof(cmd_header));
- free(events);
+ original_payload_size = cmd_ctx->reply_payload.buffer.size;
- if (ret < 0) {
- goto setup_error;
+ /* Extended infos are included at the end of the payload. */
+ list_ret = cmd_list_events(cmd_ctx->lsm.domain.type,
+ cmd_ctx->session,
+ cmd_ctx->lsm.u.list.channel_name,
+ &cmd_ctx->reply_payload);
+ if (list_ret < 0) {
+ /* Return value is a negative lttng_error_code. */
+ ret = -list_ret;
+ goto error;
}
+ payload_size = cmd_ctx->reply_payload.buffer.size -
+ sizeof(cmd_header) - original_payload_size;
+ update_lttng_msg(cmd_ctx, sizeof(cmd_header), payload_size);
+
ret = LTTNG_OK;
break;
}
}
case LTTNG_REGISTER_TRIGGER:
{
- ret = cmd_register_trigger(cmd_ctx, *sock,
- notification_thread_handle);
+ struct lttng_trigger *payload_trigger;
+ struct lttng_trigger *return_trigger;
+ size_t original_reply_payload_size;
+ size_t reply_payload_size;
+ const struct lttng_credentials cmd_creds = {
+ .uid = LTTNG_OPTIONAL_INIT_VALUE(cmd_ctx->creds.uid),
+ .gid = LTTNG_OPTIONAL_INIT_VALUE(cmd_ctx->creds.gid),
+ };
+
+ ret = setup_empty_lttng_msg(cmd_ctx);
+ if (ret) {
+ ret = LTTNG_ERR_NOMEM;
+ goto setup_error;
+ }
+
+ ret = receive_lttng_trigger(
+ cmd_ctx, *sock, sock_error, &payload_trigger);
+ if (ret != LTTNG_OK) {
+ goto error;
+ }
+
+ original_reply_payload_size = cmd_ctx->reply_payload.buffer.size;
+
+ ret = cmd_register_trigger(&cmd_creds, payload_trigger,
+ notification_thread_handle, &return_trigger);
+ if (ret != LTTNG_OK) {
+ lttng_trigger_put(payload_trigger);
+ goto error;
+ }
+
+ ret = lttng_trigger_serialize(return_trigger, &cmd_ctx->reply_payload);
+ lttng_trigger_put(payload_trigger);
+ lttng_trigger_put(return_trigger);
+ if (ret) {
+ ERR("Failed to serialize trigger in reply to \"register trigger\" command");
+ ret = LTTNG_ERR_NOMEM;
+ goto error;
+ }
+
+ reply_payload_size = cmd_ctx->reply_payload.buffer.size -
+ original_reply_payload_size;
+
+ update_lttng_msg(cmd_ctx, 0, reply_payload_size);
+
+ ret = LTTNG_OK;
break;
}
case LTTNG_UNREGISTER_TRIGGER:
{
- ret = cmd_unregister_trigger(cmd_ctx, *sock,
+ struct lttng_trigger *payload_trigger;
+ const struct lttng_credentials cmd_creds = {
+ .uid = LTTNG_OPTIONAL_INIT_VALUE(cmd_ctx->creds.uid),
+ .gid = LTTNG_OPTIONAL_INIT_VALUE(cmd_ctx->creds.gid),
+ };
+
+ ret = receive_lttng_trigger(
+ cmd_ctx, *sock, sock_error, &payload_trigger);
+ if (ret != LTTNG_OK) {
+ goto error;
+ }
+
+ ret = cmd_unregister_trigger(&cmd_creds, payload_trigger,
notification_thread_handle);
+ lttng_trigger_put(payload_trigger);
break;
}
case LTTNG_ROTATE_SESSION:
ret = cmd_clear_session(cmd_ctx->session, sock);
break;
}
+ case LTTNG_LIST_TRIGGERS:
+ {
+ struct lttng_triggers *return_triggers = NULL;
+ size_t original_payload_size;
+ size_t payload_size;
+
+ ret = setup_empty_lttng_msg(cmd_ctx);
+ if (ret) {
+ ret = LTTNG_ERR_NOMEM;
+ goto setup_error;
+ }
+
+ original_payload_size = cmd_ctx->reply_payload.buffer.size;
+
+ ret = cmd_list_triggers(cmd_ctx,
+ notification_thread_handle, &return_triggers);
+ if (ret != LTTNG_OK) {
+ goto error;
+ }
+
+ assert(return_triggers);
+ ret = lttng_triggers_serialize(
+ return_triggers, &cmd_ctx->reply_payload);
+ lttng_triggers_destroy(return_triggers);
+ if (ret) {
+ ERR("Failed to serialize triggers in reply to `list triggers` command");
+ ret = LTTNG_ERR_NOMEM;
+ goto error;
+ }
+
+ payload_size = cmd_ctx->reply_payload.buffer.size -
+ original_payload_size;
+
+ update_lttng_msg(cmd_ctx, 0, payload_size);
+
+ ret = LTTNG_OK;
+ break;
+ }
default:
ret = LTTNG_ERR_UND;
break;
.gid = UINT32_MAX,
};
cmd_ctx.session = NULL;
- lttng_dynamic_buffer_set_size(&cmd_ctx.reply_payload.buffer, 0);
- lttng_dynamic_array_clear(&cmd_ctx.reply_payload._fds);
+ lttng_payload_clear(&cmd_ctx.reply_payload);
+ cmd_ctx.lttng_msg_size = 0;
DBG("Accepting client command ...");
lttng_payload_view_from_payload(
&cmd_ctx.reply_payload,
0, -1);
- const struct lttcomm_lttng_msg *llm = (typeof(
+ struct lttcomm_lttng_msg *llm = (typeof(
llm)) cmd_ctx.reply_payload.buffer.data;
- assert(cmd_ctx.reply_payload.buffer.size >=
- sizeof(llm));
+ assert(cmd_ctx.reply_payload.buffer.size >= sizeof(*llm));
assert(cmd_ctx.lttng_msg_size == cmd_ctx.reply_payload.buffer.size);
+ llm->fd_count = lttng_payload_view_get_fd_handle_count(&view);
+
DBG("Sending response (size: %d, retcode: %s (%d))",
cmd_ctx.lttng_msg_size,
lttng_strerror(-llm->ret_code),