From: Jonathan Rajotte Date: Wed, 20 Apr 2022 21:03:52 +0000 (-0400) Subject: Basic serialization/deserialization for lttng_session X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=commitdiff_plain;h=2d321d3ee31f191312a524f7120191005004d23f Basic serialization/deserialization for lttng_session Signed-off-by: Jonathan Rajotte Change-Id: I38ec05059ade8ad2400c9e5a871928a4da96c52f --- diff --git a/include/lttng/session-internal.hpp b/include/lttng/session-internal.hpp index 7f73b9610..b56ab214c 100644 --- a/include/lttng/session-internal.hpp +++ b/include/lttng/session-internal.hpp @@ -8,14 +8,43 @@ #ifndef LTTNG_SESSION_INTERNAL_H #define LTTNG_SESSION_INTERNAL_H -#include +#include #include +#include +#include +#include + +struct lttng_session; +struct lttng_payload_view; struct lttng_session_extended { - struct { - uint64_t value; - uint8_t is_set; - } LTTNG_PACKED creation_time; + LTTNG_OPTIONAL(uint64_t) creation_time; +}; + +struct lttng_session_comm { + uint32_t name_len; + uint32_t path_len; + uint8_t enabled; + uint32_t snapshot_mode; + uint32_t live_timer_interval; + /* lttng_session_extended data */ + LTTNG_OPTIONAL(uint64_t) LTTNG_PACKED creation_time; + /* + * Dynamic payload: + * - name[name_len] + * - path[path_len] + */ + char payload[]; } LTTNG_PACKED; +int lttng_session_serialize(const struct lttng_session *session, struct lttng_payload *payload); + +ssize_t lttng_session_create_from_payload( + struct lttng_payload_view *view, struct lttng_session **out_session); + +enum lttng_error_code lttng_sessions_create_and_flatten_from_payload( + struct lttng_payload_view *view, + unsigned int count, + struct lttng_session **sessions); + #endif /* LTTNG_SESSION_INTERNAL_H */ diff --git a/src/bin/lttng-sessiond/client.cpp b/src/bin/lttng-sessiond/client.cpp index 1f94bdad8..aafbd919c 100644 --- a/src/bin/lttng-sessiond/client.cpp +++ b/src/bin/lttng-sessiond/client.cpp @@ -582,33 +582,6 @@ error_create: return ret; } -/* - * Count number of session permitted by uid/gid. - */ -static unsigned int lttng_sessions_count(uid_t uid, - gid_t gid __attribute__((unused))) -{ - unsigned int i = 0; - struct ltt_session *session; - const struct ltt_session_list *session_list = session_get_list(); - - 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) && - !session->destroyed) { - i++; - } - session_unlock(session); - session_put(session); - } - return i; -} - static enum lttng_error_code receive_lttng_trigger(struct command_ctx *cmd_ctx, int sock, int *sock_error, @@ -1893,42 +1866,33 @@ skip_domain: } case LTTNG_LIST_SESSIONS: { - unsigned int nr_sessions; - lttng_session *sessions_payload = nullptr; - size_t payload_len = 0; + enum lttng_error_code ret_code; + size_t original_payload_size; + size_t payload_size; + const size_t command_header_size = sizeof(struct lttcomm_list_command_header); + + 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; session_lock_list(); - nr_sessions = lttng_sessions_count( + ret_code = cmd_list_lttng_sessions(&cmd_ctx->reply_payload, LTTNG_SOCK_GET_UID_CRED(&cmd_ctx->creds), LTTNG_SOCK_GET_GID_CRED(&cmd_ctx->creds)); - - if (nr_sessions > 0) { - payload_len = (sizeof(struct lttng_session) * - nr_sessions) + - (sizeof(struct lttng_session_extended) * - nr_sessions); - sessions_payload = zmalloc(payload_len); - if (!sessions_payload) { - session_unlock_list(); - ret = -ENOMEM; - goto setup_error; - } - - cmd_list_lttng_sessions(sessions_payload, nr_sessions, - LTTNG_SOCK_GET_UID_CRED(&cmd_ctx->creds), - LTTNG_SOCK_GET_GID_CRED(&cmd_ctx->creds)); - } - session_unlock_list(); - - ret = setup_lttng_msg_no_cmd_header( - cmd_ctx, sessions_payload, payload_len); - free(sessions_payload); - - if (ret < 0) { - goto setup_error; + if (ret_code != LTTNG_OK) { + ret = (int) ret_code; + goto error; } + payload_size = cmd_ctx->reply_payload.buffer.size - command_header_size - + original_payload_size; + update_lttng_msg(cmd_ctx, command_header_size, payload_size); + ret = LTTNG_OK; break; } diff --git a/src/bin/lttng-sessiond/cmd.cpp b/src/bin/lttng-sessiond/cmd.cpp index 0b7492055..0db41e127 100644 --- a/src/bin/lttng-sessiond/cmd.cpp +++ b/src/bin/lttng-sessiond/cmd.cpp @@ -3946,23 +3946,38 @@ end: * The session list lock MUST be acquired before calling this function. Use * session_lock_list() and session_unlock_list(). */ -void cmd_list_lttng_sessions(struct lttng_session *sessions, - size_t session_count, uid_t uid, gid_t gid) +enum lttng_error_code cmd_list_lttng_sessions( + struct lttng_payload *reply_payload, uid_t uid, gid_t gid) { - int ret; - unsigned int i = 0; + int buffer_resize_ret; + enum lttng_error_code ret_code = LTTNG_OK; + struct lttcomm_list_command_header reply_command_header = {}; + size_t reply_command_header_offset; struct ltt_session *session; struct ltt_session_list *list = session_get_list(); - struct lttng_session_extended *extended = - (typeof(extended)) (&sessions[session_count]); + int ret; + unsigned int i = 0; + + assert(reply_payload); + + /* Reserve space for command reply header. */ + reply_command_header_offset = reply_payload->buffer.size; + buffer_resize_ret = lttng_dynamic_buffer_set_size(&reply_payload->buffer, + reply_command_header_offset + sizeof(struct lttcomm_list_command_header)); + if (buffer_resize_ret) { + ret_code = LTTNG_ERR_NOMEM; + goto error; + } DBG("Getting all available session for UID %d GID %d", uid, gid); - /* - * Iterate over session list and append data after the control struct in - * the buffer. - */ + cds_list_for_each_entry(session, &list->head, list) { + struct lttng_session tmp_session = {}; + struct lttng_session_extended tmp_extended = {}; + + tmp_session.extended.ptr = &tmp_extended; + if (!session_get(session)) { continue; } @@ -3981,10 +3996,10 @@ void cmd_list_lttng_sessions(struct lttng_session *sessions, if (session->consumer->type == CONSUMER_DST_NET || (ksess && ksess->consumer->type == CONSUMER_DST_NET) || (usess && usess->consumer->type == CONSUMER_DST_NET)) { - ret = build_network_session_path(sessions[i].path, - sizeof(sessions[i].path), session); + ret = build_network_session_path( + tmp_session.path, sizeof(tmp_session.path), session); } else { - ret = snprintf(sessions[i].path, sizeof(sessions[i].path), "%s", + ret = snprintf(tmp_session.path, sizeof(tmp_session.path), "%s", session->consumer->dst.session_root_path); } if (ret < 0) { @@ -3993,16 +4008,33 @@ void cmd_list_lttng_sessions(struct lttng_session *sessions, continue; } - strncpy(sessions[i].name, session->name, NAME_MAX); - sessions[i].name[NAME_MAX - 1] = '\0'; - sessions[i].enabled = session->active; - sessions[i].snapshot_mode = session->snapshot_mode; - sessions[i].live_timer_interval = session->live_timer; - extended[i].creation_time.value = (uint64_t) session->creation_time; - extended[i].creation_time.is_set = 1; + strncpy(tmp_session.name, session->name, NAME_MAX); + tmp_session.name[NAME_MAX - 1] = '\0'; + tmp_session.enabled = session->active; + tmp_session.snapshot_mode = session->snapshot_mode; + tmp_session.live_timer_interval = session->live_timer; + LTTNG_OPTIONAL_SET(&tmp_extended.creation_time, (uint64_t) session->creation_time); + ret = lttng_session_serialize(&tmp_session, reply_payload); + if (ret) { + ret_code = LTTNG_ERR_FATAL; + goto error; + } i++; session_put(session); } + + if (i > UINT32_MAX) { + ret_code = LTTNG_ERR_OVERFLOW; + goto error; + } + + /* Update command reply header. */ + reply_command_header.count = (uint32_t) i; + memcpy(reply_payload->buffer.data + reply_command_header_offset, &reply_command_header, + sizeof(reply_command_header)); + ret_code = LTTNG_OK; +error: + return ret_code; } /* diff --git a/src/bin/lttng-sessiond/cmd.hpp b/src/bin/lttng-sessiond/cmd.hpp index 8727e741b..4dd877be7 100644 --- a/src/bin/lttng-sessiond/cmd.hpp +++ b/src/bin/lttng-sessiond/cmd.hpp @@ -117,8 +117,7 @@ enum lttng_error_code cmd_list_events(enum lttng_domain_type domain, enum lttng_error_code cmd_list_channels(enum lttng_domain_type domain, struct ltt_session *session, struct lttng_payload *payload); -void cmd_list_lttng_sessions(struct lttng_session *sessions, - size_t session_count, uid_t uid, gid_t gid); +enum lttng_error_code cmd_list_lttng_sessions(struct lttng_payload *payload, uid_t uid, gid_t gid); enum lttng_error_code cmd_list_tracepoint_fields(enum lttng_domain_type domain, struct lttng_payload *reply); enum lttng_error_code cmd_list_tracepoints(enum lttng_domain_type domain, diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 66ab77d05..a7d43b39c 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -99,6 +99,7 @@ libcommon_lgpl_la_SOURCES = \ pthread-lock.hpp \ readwrite.cpp readwrite.hpp \ runas.cpp runas.hpp \ + session.cpp \ session-descriptor.cpp \ snapshot.cpp snapshot.hpp \ spawn-viewer.cpp spawn-viewer.hpp \ diff --git a/src/common/session.cpp b/src/common/session.cpp new file mode 100644 index 000000000..0af62f7a7 --- /dev/null +++ b/src/common/session.cpp @@ -0,0 +1,392 @@ +/* + * Copyright (C) 2022 Jonathan Rajotte + * + * SPDX-License-Identifier: LGPL-2.1-only + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct session_list_element { + struct lttng_session *session; +}; + +static void session_list_destructor(void *ptr) +{ + struct session_list_element *element = (struct session_list_element *) ptr; + + free(element->session); + free(element); +} + +int lttng_session_serialize(const struct lttng_session *session, lttng_payload *payload) +{ + int ret; + size_t name_len, path_len; + struct lttng_session_comm session_comm = {}; + struct lttng_session_extended *extended = (typeof(extended)) session->extended.ptr; + + LTTNG_ASSERT(extended != nullptr); + + name_len = lttng_strnlen(session->name, sizeof(session->name)); + if (name_len == sizeof(session->name)) { + /* Session name is not NULL-terminated. */ + ret = -1; + goto end; + } + + /* Add null termination. */ + name_len += 1; + + path_len = lttng_strnlen(session->path, sizeof(session->path)); + if (path_len == sizeof(session->path)) { + /* Session path is not NULL-terminated. */ + ret = -1; + goto end; + } + + /* Add null termination. */ + path_len += 1; + + session_comm.name_len = (uint32_t) name_len; + session_comm.path_len = (uint32_t) path_len; + session_comm.enabled = (uint8_t) session->enabled; + session_comm.snapshot_mode = session->snapshot_mode; + session_comm.live_timer_interval = session->live_timer_interval; + if (extended->creation_time.is_set) { + LTTNG_OPTIONAL_SET(&session_comm.creation_time, + LTTNG_OPTIONAL_GET(extended->creation_time)); + } else { + LTTNG_OPTIONAL_UNSET(&session_comm.creation_time); + } + + /* Header */ + ret = lttng_dynamic_buffer_append(&payload->buffer, &session_comm, sizeof(session_comm)); + if (ret) { + goto end; + } + + /* Session name */ + ret = lttng_dynamic_buffer_append(&payload->buffer, session->name, name_len); + if (ret) { + goto end; + } + + /* Session path */ + ret = lttng_dynamic_buffer_append(&payload->buffer, session->path, path_len); + if (ret) { + goto end; + } + +end: + return ret; +} + +ssize_t lttng_session_create_from_payload( + struct lttng_payload_view *view, struct lttng_session **out_session) +{ + ssize_t ret, offset = 0; + struct lttng_session *local_session = nullptr; + struct lttng_session_extended *local_extended = nullptr; + const struct lttng_session_comm *session_comm; + + LTTNG_ASSERT(out_session); + LTTNG_ASSERT(view); + + { + struct lttng_payload_view comm_view = + lttng_payload_view_from_view(view, offset, sizeof(*session_comm)); + + if (!lttng_payload_view_is_valid(&comm_view)) { + ret = -1; + goto end; + } + + /* lttng_session_comm header */ + session_comm = (typeof(session_comm)) comm_view.buffer.data; + offset += sizeof(*session_comm); + } + + local_session = zmalloc( + sizeof(struct lttng_session) + sizeof(struct lttng_session_extended)); + if (local_session == nullptr) { + ret = -1; + goto end; + } + + local_extended = (struct lttng_session_extended *) ((char *) local_session + + sizeof(lttng_session)); + if (local_extended == nullptr) { + ret = -1; + goto end; + } + + local_session->extended.ptr = local_extended; + + local_session->enabled = session_comm->enabled; + local_session->live_timer_interval = session_comm->live_timer_interval; + local_session->snapshot_mode = session_comm->snapshot_mode; + if (session_comm->creation_time.is_set) { + LTTNG_OPTIONAL_SET(&local_extended->creation_time, + LTTNG_OPTIONAL_GET(session_comm->creation_time)); + } + + { + const char *name; + const struct lttng_buffer_view name_view = lttng_buffer_view_from_view( + &view->buffer, offset, session_comm->name_len); + + if (!lttng_buffer_view_is_valid(&name_view)) { + ret = -1; + goto end; + } + + name = (const char *) name_view.data; + + if (!lttng_buffer_view_contains_string(&name_view, name, session_comm->name_len)) { + ret = -1; + goto end; + } + + ret = lttng_strncpy(local_session->name, name, sizeof(local_session->name)); + if (ret) { + ret = -1; + goto end; + } + + offset += session_comm->name_len; + } + + { + const char *path; + const struct lttng_buffer_view path_view = lttng_buffer_view_from_view( + &view->buffer, offset, session_comm->path_len); + + if (!lttng_buffer_view_is_valid(&path_view)) { + ret = -1; + goto end; + } + + path = (const char *) path_view.data; + + if (!lttng_buffer_view_contains_string(&path_view, path, session_comm->path_len)) { + ret = -1; + goto end; + } + + ret = lttng_strncpy(local_session->path, path, sizeof(local_session->path)); + if (ret) { + ret = -1; + goto end; + } + + offset += session_comm->path_len; + } + /* Transfer ownership to the caller. */ + *out_session = local_session; + local_session = nullptr; + + ret = offset; +end: + free(local_session); + return ret; +} + +static enum lttng_error_code compute_flattened_size( + struct lttng_dynamic_pointer_array *sessions, size_t *size) +{ + enum lttng_error_code ret_code; + size_t storage_req, session_count; + + assert(size); + assert(sessions); + + session_count = lttng_dynamic_pointer_array_get_count(sessions); + + /* The basic struct lttng_session */ + storage_req = session_count * sizeof(struct lttng_session); + + /* The struct lttng_session_extended */ + storage_req += session_count * sizeof(struct lttng_session_extended); + + *size = storage_req; + ret_code = LTTNG_OK; + + return ret_code; +} + +static enum lttng_error_code flatten_lttng_sessions(struct lttng_dynamic_pointer_array *sessions, + struct lttng_session **flattened_sessions) +{ + enum lttng_error_code ret_code; + int ret, i; + size_t storage_req; + struct lttng_dynamic_buffer local_flattened_sessions; + int nb_sessions; + + assert(sessions); + assert(flattened_sessions); + + lttng_dynamic_buffer_init(&local_flattened_sessions); + nb_sessions = lttng_dynamic_pointer_array_get_count(sessions); + + ret_code = compute_flattened_size(sessions, &storage_req); + if (ret_code != LTTNG_OK) { + goto end; + } + + /* + * We must ensure that "local_flattened_sessions" is never resized so as + * to preserve the validity of the flattened objects. + */ + ret = lttng_dynamic_buffer_set_capacity(&local_flattened_sessions, storage_req); + if (ret) { + ret_code = LTTNG_ERR_NOMEM; + goto end; + } + + /* Start by laying the struct lttng_session */ + for (i = 0; i < nb_sessions; i++) { + const struct session_list_element *element = (const struct session_list_element *) + lttng_dynamic_pointer_array_get_pointer(sessions, i); + + if (!element) { + ret_code = LTTNG_ERR_FATAL; + goto end; + } + + ret = lttng_dynamic_buffer_append(&local_flattened_sessions, element->session, + sizeof(struct lttng_session)); + if (ret) { + ret_code = LTTNG_ERR_NOMEM; + goto end; + } + } + + for (i = 0; i < nb_sessions; i++) { + const struct session_list_element *element = (const struct session_list_element *) + lttng_dynamic_pointer_array_get_pointer(sessions, i); + struct lttng_session *session = + (struct lttng_session *) (local_flattened_sessions.data + + (sizeof(struct lttng_session) * i)); + struct lttng_session_extended *session_extended = + (struct lttng_session_extended *) (local_flattened_sessions.data + + local_flattened_sessions.size); + + assert(element); + + /* Insert struct lttng_session_extended. */ + ret = lttng_dynamic_buffer_set_size(&local_flattened_sessions, + local_flattened_sessions.size + sizeof(*session_extended)); + if (ret) { + ret_code = LTTNG_ERR_NOMEM; + goto end; + } + session->extended.ptr = session_extended; + + memcpy(session_extended, element->session->extended.ptr, + sizeof(struct lttng_session_extended)); + } + + /* Don't reset local_flattened_sessions buffer as we return its content. */ + *flattened_sessions = (struct lttng_session *) local_flattened_sessions.data; + lttng_dynamic_buffer_init(&local_flattened_sessions); + ret_code = LTTNG_OK; +end: + lttng_dynamic_buffer_reset(&local_flattened_sessions); + return ret_code; +} + +static enum lttng_error_code session_list_create_from_payload(struct lttng_payload_view *view, + unsigned int count, + struct lttng_dynamic_pointer_array *session_list) +{ + enum lttng_error_code ret_code; + int ret; + unsigned int i; + int offset = 0; + + assert(view); + assert(session_list); + + for (i = 0; i < count; i++) { + ssize_t session_size; + struct lttng_payload_view session_view = + lttng_payload_view_from_view(view, offset, -1); + struct session_list_element *element = zmalloc(); + + if (!element) { + ret_code = LTTNG_ERR_NOMEM; + goto end; + } + + /* + * Lifetime and management of the object is now bound to the + * array. + */ + ret = lttng_dynamic_pointer_array_add_pointer(session_list, element); + if (ret) { + session_list_destructor(element); + ret_code = LTTNG_ERR_NOMEM; + goto end; + } + + session_size = lttng_session_create_from_payload(&session_view, &element->session); + if (session_size < 0) { + ret_code = LTTNG_ERR_INVALID; + goto end; + } + + offset += session_size; + } + + if (view->buffer.size != offset) { + ret_code = LTTNG_ERR_INVALID_PROTOCOL; + goto end; + } + + ret_code = LTTNG_OK; + +end: + return ret_code; +} +enum lttng_error_code lttng_sessions_create_and_flatten_from_payload( + struct lttng_payload_view *payload, + unsigned int count, + struct lttng_session **sessions) +{ + enum lttng_error_code ret = LTTNG_OK; + struct lttng_dynamic_pointer_array local_sessions; + + lttng_dynamic_pointer_array_init(&local_sessions, session_list_destructor); + + /* Deserialize the sessions. */ + { + struct lttng_payload_view sessions_view = + lttng_payload_view_from_view(payload, 0, -1); + + ret = session_list_create_from_payload(&sessions_view, count, &local_sessions); + if (ret != LTTNG_OK) { + goto end; + } + } + + ret = flatten_lttng_sessions(&local_sessions, sessions); + if (ret != LTTNG_OK) { + goto end; + } + +end: + lttng_dynamic_pointer_array_reset(&local_sessions); + return ret; +} diff --git a/src/lib/lttng-ctl/lttng-ctl.cpp b/src/lib/lttng-ctl/lttng-ctl.cpp index 3d0c8b412..9dff22a2b 100644 --- a/src/lib/lttng-ctl/lttng-ctl.cpp +++ b/src/lib/lttng-ctl/lttng-ctl.cpp @@ -2211,51 +2211,59 @@ int lttng_destroy_session_no_wait(const char *session_name) int lttng_list_sessions(struct lttng_session **out_sessions) { int ret; - struct lttcomm_session_msg lsm; - const size_t session_size = sizeof(struct lttng_session) + - sizeof(struct lttng_session_extended); - size_t session_count, i; - struct lttng_session_extended *sessions_extended_begin; - struct lttng_session *sessions = NULL; + struct lttcomm_session_msg lsm = {}; + struct lttng_payload reply; + struct lttng_payload_view lsm_view = + lttng_payload_view_init_from_buffer((const char *) &lsm, 0, sizeof(lsm)); + unsigned int nb_sessions = 0; - memset(&lsm, 0, sizeof(lsm)); + lttng_payload_init(&reply); + + /* Initialize command parameters. */ lsm.cmd_type = LTTNG_LIST_SESSIONS; - /* - * Initialize out_sessions to NULL so it is initialized when - * lttng_list_sessions returns 0, thus allowing *out_sessions to - * be subsequently freed. - */ - *out_sessions = NULL; - ret = lttng_ctl_ask_sessiond(&lsm, (void**) &sessions); - if (ret <= 0) { - goto end; - } - if (!sessions) { - ret = -LTTNG_ERR_FATAL; + + /* Execute command against the session daemon. */ + ret = lttng_ctl_ask_sessiond_payload(&lsm_view, &reply); + if (ret < 0) { goto end; } - if (ret % session_size) { - ret = -LTTNG_ERR_UNK; - free(sessions); - goto end; + { + const struct lttcomm_list_command_header *cmd_reply_header = NULL; + const lttng_payload_view cmd_reply_header_view = lttng_payload_view_from_payload( + &reply, 0, sizeof(*cmd_reply_header)); + + if (!lttng_payload_view_is_valid(&cmd_reply_header_view)) { + ret = -LTTNG_ERR_INVALID_PROTOCOL; + goto end; + } + + cmd_reply_header = (const struct lttcomm_list_command_header *) + cmd_reply_header_view.buffer.data; + if (cmd_reply_header->count > INT_MAX) { + ret = -LTTNG_ERR_OVERFLOW; + goto end; + } + + nb_sessions = (unsigned int) cmd_reply_header->count; } - session_count = (size_t) ret / session_size; - sessions_extended_begin = (struct lttng_session_extended *) - (&sessions[session_count]); - /* Set extended session info pointers. */ - for (i = 0; i < session_count; i++) { - struct lttng_session *session = &sessions[i]; - struct lttng_session_extended *extended = - &(sessions_extended_begin[i]); + { + enum lttng_error_code ret_code; + lttng_payload_view cmd_reply_payload = lttng_payload_view_from_payload( + &reply, sizeof(struct lttcomm_list_command_header), -1); - session->extended.ptr = extended; + ret_code = lttng_sessions_create_and_flatten_from_payload( + &cmd_reply_payload, nb_sessions, out_sessions); + if (ret_code != LTTNG_OK) { + ret = -((int) ret_code); + goto end; + } } - ret = (int) session_count; - *out_sessions = sessions; + ret = (int) nb_sessions; end: + lttng_payload_reset(&reply); return ret; }