X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Flib%2Flttng-ctl%2Flttng-ctl.c;h=a295667fea7855e594645e99b5c24520ea5976ec;hp=b2f25ecd06ac58c471f94c4ea34daa2d30383cbb;hb=9124c6304bba12b0d4424b4071a25a34445ff4da;hpb=e368fb4396b9bdb22de16f0c93512c9f6d7ab0b4 diff --git a/src/lib/lttng-ctl/lttng-ctl.c b/src/lib/lttng-ctl/lttng-ctl.c index b2f25ecd0..a295667fe 100644 --- a/src/lib/lttng-ctl/lttng-ctl.c +++ b/src/lib/lttng-ctl/lttng-ctl.c @@ -13,20 +13,22 @@ #define _LGPL_SOURCE #include #include -#include #include #include #include #include #include +#include #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -39,27 +41,14 @@ #include #include #include +#include -#include "filter/filter-ast.h" -#include "filter/filter-parser.h" -#include "filter/filter-bytecode.h" -#include "filter/memstream.h" +#include +#include +#include +#include #include "lttng-ctl-helper.h" -#ifdef DEBUG -static const int print_xml = 1; -#define dbg_printf(fmt, args...) \ - printf("[debug liblttng-ctl] " fmt, ## args) -#else -static const int print_xml = 0; -#define dbg_printf(fmt, args...) \ -do { \ - /* do nothing but check printf format */ \ - if (0) \ - printf("[debug liblttnctl] " fmt, ## args); \ -} while (0) -#endif - #define COPY_DOMAIN_PACKED(dst, src) \ do { \ struct lttng_domain _tmp_domain; \ @@ -222,6 +211,8 @@ static int recv_data_sessiond(void *buf, size_t len) { int ret; + assert(len > 0); + if (!connected) { ret = -LTTNG_ERR_NO_SESSIOND; goto end; @@ -230,6 +221,8 @@ static int recv_data_sessiond(void *buf, size_t len) ret = lttcomm_recv_unix_sock(sessiond_socket, buf, len); if (ret < 0) { ret = -LTTNG_ERR_FATAL; + } else if (ret == 0) { + ret = -LTTNG_ERR_NO_SESSIOND; } end: @@ -627,9 +620,10 @@ int lttng_ctl_ask_sessiond_payload(struct lttng_payload_view *message, { int ret; struct lttcomm_lttng_msg llm; + const int fd_count = lttng_payload_view_get_fd_handle_count(message); assert(reply->buffer.size == 0); - assert(reply->_fds.size == 0); + assert(lttng_dynamic_pointer_array_get_count(&reply->_fd_handles) == 0); ret = connect_sessiond(); if (ret < 0) { @@ -648,10 +642,13 @@ int lttng_ctl_ask_sessiond_payload(struct lttng_payload_view *message, goto end; } - if (lttng_payload_view_get_fd_count(message) > 0) { - ret = lttcomm_send_fds_unix_sock(sessiond_socket, - (const int *) message->_fds.buffer.data, - lttng_dynamic_array_get_count(&message->_fds)); + if (fd_count > 0) { + ret = lttcomm_send_payload_view_fds_unix_sock(sessiond_socket, + message); + if (ret < 0) { + ret = -LTTNG_ERR_FATAL; + goto end; + } } /* Get header from data transmission */ @@ -685,19 +682,9 @@ int lttng_ctl_ask_sessiond_payload(struct lttng_payload_view *message, } if (llm.fd_count > 0) { - ret = lttng_dynamic_array_set_count(&reply->_fds, llm.fd_count); - if (ret) { - ret = -LTTNG_ERR_NOMEM; - goto end; - } - - ret = lttcomm_recv_fds_unix_sock(sessiond_socket, - (int *) reply->_fds.buffer.data, llm.fd_count); - if (ret > 0 && ret != llm.fd_count * sizeof(int)) { - ret = -LTTNG_ERR_INVALID_PROTOCOL; - goto end; - } else if (ret <= 0) { - ret = -LTTNG_ERR_FATAL; + ret = lttcomm_recv_payload_fds_unix_sock( + sessiond_socket, llm.fd_count, reply); + if (ret < 0) { goto end; } } @@ -1053,133 +1040,6 @@ error: return NULL; } -/* - * Generate the filter bytecode from a given filter expression string. Put the - * newly allocated parser context in ctxp and populate the lsm object with the - * expression len. - * - * Return 0 on success else a LTTNG_ERR_* code and ctxp is untouched. - */ -static int generate_filter(char *filter_expression, - struct lttcomm_session_msg *lsm, struct filter_parser_ctx **ctxp) -{ - int ret; - struct filter_parser_ctx *ctx = NULL; - FILE *fmem = NULL; - - assert(filter_expression); - assert(lsm); - assert(ctxp); - - /* - * Casting const to non-const, as the underlying function will use it in - * read-only mode. - */ - fmem = lttng_fmemopen((void *) filter_expression, - strlen(filter_expression), "r"); - if (!fmem) { - fprintf(stderr, "Error opening memory as stream\n"); - ret = -LTTNG_ERR_FILTER_NOMEM; - goto error; - } - ctx = filter_parser_ctx_alloc(fmem); - if (!ctx) { - fprintf(stderr, "Error allocating parser\n"); - ret = -LTTNG_ERR_FILTER_NOMEM; - goto filter_alloc_error; - } - ret = filter_parser_ctx_append_ast(ctx); - if (ret) { - fprintf(stderr, "Parse error\n"); - ret = -LTTNG_ERR_FILTER_INVAL; - goto parse_error; - } - if (print_xml) { - ret = filter_visitor_print_xml(ctx, stdout, 0); - if (ret) { - fflush(stdout); - fprintf(stderr, "XML print error\n"); - ret = -LTTNG_ERR_FILTER_INVAL; - goto parse_error; - } - } - - dbg_printf("Generating IR... "); - fflush(stdout); - ret = filter_visitor_ir_generate(ctx); - if (ret) { - fprintf(stderr, "Generate IR error\n"); - ret = -LTTNG_ERR_FILTER_INVAL; - goto parse_error; - } - dbg_printf("done\n"); - - dbg_printf("Validating IR... "); - fflush(stdout); - ret = filter_visitor_ir_check_binary_op_nesting(ctx); - if (ret) { - ret = -LTTNG_ERR_FILTER_INVAL; - goto parse_error; - } - - /* Normalize globbing patterns in the expression. */ - ret = filter_visitor_ir_normalize_glob_patterns(ctx); - if (ret) { - ret = -LTTNG_ERR_FILTER_INVAL; - goto parse_error; - } - - /* Validate strings used as literals in the expression. */ - ret = filter_visitor_ir_validate_string(ctx); - if (ret) { - ret = -LTTNG_ERR_FILTER_INVAL; - goto parse_error; - } - - /* Validate globbing patterns in the expression. */ - ret = filter_visitor_ir_validate_globbing(ctx); - if (ret) { - ret = -LTTNG_ERR_FILTER_INVAL; - goto parse_error; - } - - dbg_printf("done\n"); - - dbg_printf("Generating bytecode... "); - fflush(stdout); - ret = filter_visitor_bytecode_generate(ctx); - if (ret) { - fprintf(stderr, "Generate bytecode error\n"); - ret = -LTTNG_ERR_FILTER_INVAL; - goto parse_error; - } - dbg_printf("done\n"); - dbg_printf("Size of bytecode generated: %u bytes.\n", - bytecode_get_len(&ctx->bytecode->b)); - - lsm->u.enable.bytecode_len = sizeof(ctx->bytecode->b) - + bytecode_get_len(&ctx->bytecode->b); - lsm->u.enable.expression_len = strlen(filter_expression) + 1; - - /* No need to keep the memory stream. */ - if (fclose(fmem) != 0) { - PERROR("fclose"); - } - - *ctxp = ctx; - return 0; - -parse_error: - filter_ir_free(ctx); - filter_parser_ctx_free(ctx); -filter_alloc_error: - if (fclose(fmem) != 0) { - PERROR("fclose"); - } -error: - return ret; -} - /* * Enable event(s) for a channel, possibly with exclusions and a filter. * If no event name is specified, all events are enabled. @@ -1282,10 +1142,14 @@ int lttng_enable_event_with_exclusions(struct lttng_handle *handle, } } - ret = generate_filter(filter_expression, &lsm, &ctx); + ret = filter_parser_ctx_create_from_filter_expression(filter_expression, &ctx); if (ret) { goto filter_error; } + + lsm.u.enable.bytecode_len = sizeof(ctx->bytecode->b) + + bytecode_get_len(&ctx->bytecode->b); + lsm.u.enable.expression_len = strlen(filter_expression) + 1; } ret = lttng_dynamic_buffer_set_capacity(&payload.buffer, @@ -1360,7 +1224,7 @@ int lttng_enable_event_with_exclusions(struct lttng_handle *handle, { struct lttng_payload_view view = lttng_payload_view_from_payload( &payload, 0, -1); - int fd_count = lttng_payload_view_get_fd_count(&view); + int fd_count = lttng_payload_view_get_fd_handle_count(&view); int fd_to_send; if (fd_count < 0) { @@ -1369,12 +1233,15 @@ int lttng_enable_event_with_exclusions(struct lttng_handle *handle, assert(fd_count == 0 || fd_count == 1); if (fd_count == 1) { - ret = lttng_payload_view_pop_fd(&view); - if (ret < 0) { + struct fd_handle *handle = + lttng_payload_view_pop_fd_handle(&view); + + if (!handle) { goto mem_error; } - fd_to_send = ret; + fd_to_send = fd_handle_get_fd(handle); + fd_handle_put(handle); } ret = lttng_ctl_ask_sessiond_fds_varlen(&lsm, @@ -1509,10 +1376,14 @@ int lttng_disable_event_ext(struct lttng_handle *handle, } } - ret = generate_filter(filter_expression, &lsm, &ctx); + ret = filter_parser_ctx_create_from_filter_expression(filter_expression, &ctx); if (ret) { goto filter_error; } + + lsm.u.enable.bytecode_len = sizeof(ctx->bytecode->b) + + bytecode_get_len(&ctx->bytecode->b); + lsm.u.enable.expression_len = strlen(filter_expression) + 1; } varlen_data = zmalloc(lsm.u.disable.bytecode_len @@ -2376,7 +2247,7 @@ int lttng_list_events(struct lttng_handle *handle, cmd_header_view = lttng_buffer_view_from_dynamic_buffer( &payload.buffer, 0, sizeof(*cmd_header)); - if (!cmd_header_view.data) { + if (!lttng_buffer_view_is_valid(&cmd_header_view)) { ret = -LTTNG_ERR_INVALID_PROTOCOL; goto end; } @@ -2443,6 +2314,11 @@ int lttng_list_events(struct lttng_handle *handle, payload_view.buffer.data, ext_comm->userspace_probe_location_len); + if (!lttng_payload_view_is_valid(&probe_location_view)) { + ret = -LTTNG_ERR_PROBE_LOCATION_INVAL; + goto end; + } + /* * Create a temporary userspace probe location * to determine the size needed by a "flattened" @@ -2582,6 +2458,11 @@ int lttng_list_events(struct lttng_handle *handle, payload_copy_view.buffer.data, ext_comm->userspace_probe_location_len); + if (!lttng_payload_view_is_valid(&probe_location_view)) { + ret = -LTTNG_ERR_PROBE_LOCATION_INVAL; + goto free_dynamic_buffer; + } + ret = lttng_userspace_probe_location_create_from_payload( &probe_location_view, &probe_location); @@ -3083,33 +2964,120 @@ end: int lttng_register_trigger(struct lttng_trigger *trigger) { int ret; - struct lttcomm_session_msg lsm; - struct lttng_payload payload; + struct lttcomm_session_msg lsm = { + .cmd_type = LTTNG_REGISTER_TRIGGER, + }; + struct lttcomm_session_msg *message_lsm; + struct lttng_payload message; + struct lttng_payload reply; + struct lttng_trigger *reply_trigger = NULL; + enum lttng_domain_type domain_type; + const struct lttng_credentials user_creds = { + .uid = LTTNG_OPTIONAL_INIT_VALUE(geteuid()), + .gid = LTTNG_OPTIONAL_INIT_UNSET, + }; + + + lttng_payload_init(&message); + lttng_payload_init(&reply); - lttng_payload_init(&payload); if (!trigger) { ret = -LTTNG_ERR_INVALID; goto end; } + if (!trigger->creds.uid.is_set) { + /* Use the client's credentials as the trigger credentials. */ + lttng_trigger_set_credentials(trigger, &user_creds); + } else { + /* + * Validate that either the current trigger credentials and the + * client credentials are identical or that the current user is + * root. The root user can register, unregister triggers for + * himself and other users. + * + * This check is also present on the sessiond side, using the + * credentials passed on the socket. These check are all + * "safety" checks. + */ + const struct lttng_credentials *trigger_creds = + lttng_trigger_get_credentials(trigger); + + if (!lttng_credentials_is_equal_uid(trigger_creds, &user_creds)) { + if (lttng_credentials_get_uid(&user_creds) != 0) { + ret = -LTTNG_ERR_EPERM; + goto end; + } + } + } + if (!lttng_trigger_validate(trigger)) { ret = -LTTNG_ERR_INVALID_TRIGGER; goto end; } - ret = lttng_trigger_serialize(trigger, &payload); + domain_type = lttng_trigger_get_underlying_domain_type_restriction( + trigger); + + lsm.domain.type = domain_type; + + ret = lttng_dynamic_buffer_append(&message.buffer, &lsm, sizeof(lsm)); + if (ret) { + ret = -LTTNG_ERR_NOMEM; + goto end; + } + + /* + * This is needed to populate the trigger object size for the command + * header. + */ + message_lsm = (struct lttcomm_session_msg *) message.buffer.data; + + ret = lttng_trigger_serialize(trigger, &message); if (ret < 0) { ret = -LTTNG_ERR_UNK; goto end; } - memset(&lsm, 0, sizeof(lsm)); - lsm.cmd_type = LTTNG_REGISTER_TRIGGER; - lsm.u.trigger.length = (uint32_t) payload.buffer.size; - ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header( - &lsm, payload.buffer.data, payload.buffer.size, NULL); + message_lsm->u.trigger.length = (uint32_t) message.buffer.size - sizeof(lsm); + + { + struct lttng_payload_view message_view = + lttng_payload_view_from_payload( + &message, 0, -1); + + message_lsm->fd_count = lttng_payload_view_get_fd_handle_count( + &message_view); + ret = lttng_ctl_ask_sessiond_payload(&message_view, &reply); + if (ret < 0) { + goto end; + } + } + + { + struct lttng_payload_view reply_view = + lttng_payload_view_from_payload( + &reply, 0, reply.buffer.size); + + ret = lttng_trigger_create_from_payload( + &reply_view, &reply_trigger); + if (ret < 0) { + ret = -LTTNG_ERR_FATAL; + goto end; + } + } + + ret = lttng_trigger_assign_name(trigger, reply_trigger); + if (ret < 0) { + ret = -LTTNG_ERR_FATAL; + goto end; + } + + ret = 0; end: - lttng_payload_reset(&payload); + lttng_payload_reset(&message); + lttng_payload_reset(&reply); + lttng_trigger_destroy(reply_trigger); return ret; } @@ -3117,35 +3085,146 @@ int lttng_unregister_trigger(struct lttng_trigger *trigger) { int ret; struct lttcomm_session_msg lsm; - struct lttng_payload payload; + struct lttcomm_session_msg *message_lsm; + struct lttng_payload message; + struct lttng_payload reply; + const struct lttng_credentials user_creds = { + .uid = LTTNG_OPTIONAL_INIT_VALUE(geteuid()), + .gid = LTTNG_OPTIONAL_INIT_UNSET, + }; + + lttng_payload_init(&message); + lttng_payload_init(&reply); - lttng_payload_init(&payload); if (!trigger) { ret = -LTTNG_ERR_INVALID; goto end; } + if (!trigger->creds.uid.is_set) { + /* Use the client's credentials as the trigger credentials. */ + lttng_trigger_set_credentials(trigger, &user_creds); + } else { + /* + * Validate that either the current trigger credentials and the + * client credentials are identical or that the current user is + * root. The root user can register, unregister triggers for + * himself and other users. + * + * This check is also present on the sessiond side, using the + * credentials passed on the socket. These check are all + * "safety" checks. + */ + const struct lttng_credentials *trigger_creds = + lttng_trigger_get_credentials(trigger); + + if (!lttng_credentials_is_equal_uid(trigger_creds, &user_creds)) { + if (lttng_credentials_get_uid(&user_creds) != 0) { + ret = -LTTNG_ERR_EPERM; + goto end; + } + } + } + if (!lttng_trigger_validate(trigger)) { ret = -LTTNG_ERR_INVALID_TRIGGER; goto end; } - ret = lttng_trigger_serialize(trigger, &payload); + memset(&lsm, 0, sizeof(lsm)); + lsm.cmd_type = LTTNG_UNREGISTER_TRIGGER; + + ret = lttng_dynamic_buffer_append(&message.buffer, &lsm, sizeof(lsm)); + if (ret) { + ret = -LTTNG_ERR_NOMEM; + goto end; + } + + /* + * This is needed to populate the trigger object size for the command + * header and number of fds sent. + */ + message_lsm = (struct lttcomm_session_msg *) message.buffer.data; + + ret = lttng_trigger_serialize(trigger, &message); if (ret < 0) { ret = -LTTNG_ERR_UNK; goto end; } - memset(&lsm, 0, sizeof(lsm)); - lsm.cmd_type = LTTNG_UNREGISTER_TRIGGER; - lsm.u.trigger.length = (uint32_t) payload.buffer.size; - ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header( - &lsm, payload.buffer.data, payload.buffer.size, NULL); + message_lsm->u.trigger.length = (uint32_t) message.buffer.size - sizeof(lsm); + + { + struct lttng_payload_view message_view = + lttng_payload_view_from_payload( + &message, 0, -1); + + /* + * Update the message header with the number of fd that will be + * sent. + */ + message_lsm->fd_count = lttng_payload_view_get_fd_handle_count( + &message_view); + + ret = lttng_ctl_ask_sessiond_payload(&message_view, &reply); + if (ret < 0) { + goto end; + } + } + + ret = 0; end: - lttng_payload_reset(&payload); + lttng_payload_reset(&message); + lttng_payload_reset(&reply); return ret; } +/* + * Ask the session daemon for all registered triggers for the current user. + * + * Allocates and return an lttng_triggers set. + * On error, returns a suitable lttng_error_code. + */ +enum lttng_error_code lttng_list_triggers(struct lttng_triggers **triggers) +{ + int ret; + enum lttng_error_code ret_code = LTTNG_OK; + struct lttcomm_session_msg lsm = { .cmd_type = LTTNG_LIST_TRIGGERS }; + struct lttng_triggers *local_triggers = NULL; + struct lttng_payload reply; + struct lttng_payload_view lsm_view = + lttng_payload_view_init_from_buffer( + (const char *) &lsm, 0, sizeof(lsm)); + + lttng_payload_init(&reply); + + ret = lttng_ctl_ask_sessiond_payload(&lsm_view, &reply); + if (ret < 0) { + ret_code = (enum lttng_error_code) -ret; + goto end; + } + + { + struct lttng_payload_view reply_view = + lttng_payload_view_from_payload( + &reply, 0, reply.buffer.size); + + ret = lttng_triggers_create_from_payload( + &reply_view, &local_triggers); + if (ret < 0) { + ret_code = LTTNG_ERR_FATAL; + goto end; + } + } + + *triggers = local_triggers; + local_triggers = NULL; +end: + lttng_payload_reset(&reply); + lttng_triggers_destroy(local_triggers); + return ret_code; +} + /* * lib constructor. */