X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fmain.c;h=6310db7e601654f5d5f3bc0c1bae41cf866c532a;hp=e084aba61437961fe0f2d505bef57ed0f991c283;hb=772b8f4db503f0dc5ba184b2f71509eb4c718b24;hpb=7fa2082ed250230b7823e01b144aa6b580d4b2f5 diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index e084aba61..6310db7e6 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -42,6 +42,7 @@ #include #include +#include #include #include #include @@ -72,6 +73,7 @@ #include "save.h" #include "load-session-thread.h" #include "syscall.h" +#include "agent.h" #define CONSUMERD_FILE "lttng-consumerd" @@ -132,34 +134,34 @@ static struct consumer_data ustconsumer32_data = { /* Command line options */ static const struct option long_options[] = { - { "client-sock", 1, 0, 'c' }, - { "apps-sock", 1, 0, 'a' }, - { "kconsumerd-cmd-sock", 1, 0, 'C' }, - { "kconsumerd-err-sock", 1, 0, 'E' }, - { "ustconsumerd32-cmd-sock", 1, 0, 'G' }, - { "ustconsumerd32-err-sock", 1, 0, 'H' }, - { "ustconsumerd64-cmd-sock", 1, 0, 'D' }, - { "ustconsumerd64-err-sock", 1, 0, 'F' }, - { "consumerd32-path", 1, 0, 'u' }, - { "consumerd32-libdir", 1, 0, 'U' }, - { "consumerd64-path", 1, 0, 't' }, - { "consumerd64-libdir", 1, 0, 'T' }, - { "daemonize", 0, 0, 'd' }, - { "background", 0, 0, 'b' }, - { "sig-parent", 0, 0, 'S' }, - { "help", 0, 0, 'h' }, - { "group", 1, 0, 'g' }, - { "version", 0, 0, 'V' }, - { "quiet", 0, 0, 'q' }, - { "verbose", 0, 0, 'v' }, - { "verbose-consumer", 0, 0, 'Z' }, - { "no-kernel", 0, 0, 'N' }, - { "pidfile", 1, 0, 'p' }, - { "agent-tcp-port", 1, 0, 'J' }, - { "config", 1, 0, 'f' }, - { "load", 1, 0, 'l' }, - { "kmod-probes", 1, 0, 'P' }, - { "extra-kmod-probes", 1, 0, 'e' }, + { "client-sock", required_argument, 0, 'c' }, + { "apps-sock", required_argument, 0, 'a' }, + { "kconsumerd-cmd-sock", required_argument, 0, '\0' }, + { "kconsumerd-err-sock", required_argument, 0, '\0' }, + { "ustconsumerd32-cmd-sock", required_argument, 0, '\0' }, + { "ustconsumerd32-err-sock", required_argument, 0, '\0' }, + { "ustconsumerd64-cmd-sock", required_argument, 0, '\0' }, + { "ustconsumerd64-err-sock", required_argument, 0, '\0' }, + { "consumerd32-path", required_argument, 0, '\0' }, + { "consumerd32-libdir", required_argument, 0, '\0' }, + { "consumerd64-path", required_argument, 0, '\0' }, + { "consumerd64-libdir", required_argument, 0, '\0' }, + { "daemonize", no_argument, 0, 'd' }, + { "background", no_argument, 0, 'b' }, + { "sig-parent", no_argument, 0, 'S' }, + { "help", no_argument, 0, 'h' }, + { "group", required_argument, 0, 'g' }, + { "version", no_argument, 0, 'V' }, + { "quiet", no_argument, 0, 'q' }, + { "verbose", no_argument, 0, 'v' }, + { "verbose-consumer", no_argument, 0, '\0' }, + { "no-kernel", no_argument, 0, '\0' }, + { "pidfile", required_argument, 0, 'p' }, + { "agent-tcp-port", required_argument, 0, '\0' }, + { "config", required_argument, 0, 'f' }, + { "load", required_argument, 0, 'l' }, + { "kmod-probes", required_argument, 0, '\0' }, + { "extra-kmod-probes", required_argument, 0, '\0' }, { NULL, 0, 0, 0 } }; @@ -304,6 +306,9 @@ const char * const config_section_name = "sessiond"; /* Load session thread information to operate. */ struct load_session_thread_data *load_info; +/* Global hash tables */ +struct lttng_ht *agent_apps_ht_by_sock = NULL; + /* * Whether sessiond is ready for commands/health check requests. * NR_LTTNG_SESSIOND_READY must match the number of calls to @@ -367,19 +372,19 @@ void setup_consumerd_path(void) /* * runtime env. var. overrides the build default. */ - bin = getenv("LTTNG_CONSUMERD32_BIN"); + bin = lttng_secure_getenv("LTTNG_CONSUMERD32_BIN"); if (bin) { consumerd32_bin = bin; } - bin = getenv("LTTNG_CONSUMERD64_BIN"); + bin = lttng_secure_getenv("LTTNG_CONSUMERD64_BIN"); if (bin) { consumerd64_bin = bin; } - libdir = getenv("LTTNG_CONSUMERD32_LIBDIR"); + libdir = lttng_secure_getenv("LTTNG_CONSUMERD32_LIBDIR"); if (libdir) { consumerd32_libdir = libdir; } - libdir = getenv("LTTNG_CONSUMERD64_LIBDIR"); + libdir = lttng_secure_getenv("LTTNG_CONSUMERD64_LIBDIR"); if (libdir) { consumerd64_libdir = libdir; } @@ -675,6 +680,9 @@ static void sessiond_cleanup(void) } } + DBG("Cleaning up all agent apps"); + agent_app_ht_clean(); + DBG("Closing all UST sockets"); ust_app_clean_list(); buffer_reg_destroy_registries(); @@ -993,10 +1001,30 @@ static void update_ust_app(int app_sock) /* For all tracing session(s) */ cds_list_for_each_entry_safe(sess, stmp, &session_list_ptr->head, list) { + struct ust_app *app; + session_lock(sess); - if (sess->ust_session) { - ust_app_global_update(sess->ust_session, app_sock); + if (!sess->ust_session) { + goto unlock_session; } + + rcu_read_lock(); + assert(app_sock >= 0); + app = ust_app_find_by_sock(app_sock); + if (app == NULL) { + /* + * Application can be unregistered before so + * this is possible hence simply stopping the + * update. + */ + DBG3("UST app update failed to find app sock %d", + app_sock); + goto unlock_rcu; + } + ust_app_global_update(sess->ust_session, app); + unlock_rcu: + rcu_read_unlock(); + unlock_session: session_unlock(sess); } } @@ -1188,6 +1216,9 @@ static void *thread_manage_consumer(void *data) DBG("[thread] Manage consumer started"); + rcu_register_thread(); + rcu_thread_online(); + health_register(health_sessiond, HEALTH_SESSIOND_TYPE_CONSUMER); health_code_update(); @@ -1486,6 +1517,9 @@ error_poll: health_unregister(health_sessiond); DBG("consumer thread cleanup completed"); + rcu_thread_offline(); + rcu_unregister_thread(); + return NULL; } @@ -1997,6 +2031,22 @@ error: free(wait_node); } + /* Empty command queue. */ + for (;;) { + /* Dequeue command for registration */ + node = cds_wfcq_dequeue_blocking(&ust_cmd_queue.head, &ust_cmd_queue.tail); + if (node == NULL) { + break; + } + ust_cmd = caa_container_of(node, struct ust_command, node); + ret = close(ust_cmd->sock); + if (ret < 0) { + PERROR("close ust sock exit dispatch %d", ust_cmd->sock); + } + lttng_fd_put(LTTNG_FD_APPS, 1); + free(ust_cmd); + } + error_testpoint: DBG("Dispatch thread dying"); if (err) { @@ -2129,6 +2179,10 @@ static void *thread_registration_apps(void *data) ust_cmd = zmalloc(sizeof(struct ust_command)); if (ust_cmd == NULL) { PERROR("ust command zmalloc"); + ret = close(sock); + if (ret) { + PERROR("close"); + } goto error; } @@ -2440,7 +2494,7 @@ static pid_t spawn_consumerd(struct consumer_data *consumer_data) char *tmp; size_t tmplen; - tmp = getenv("LD_LIBRARY_PATH"); + tmp = lttng_secure_getenv("LD_LIBRARY_PATH"); if (!tmp) { tmp = ""; } @@ -2483,7 +2537,7 @@ static pid_t spawn_consumerd(struct consumer_data *consumer_data) char *tmp; size_t tmplen; - tmp = getenv("LD_LIBRARY_PATH"); + tmp = lttng_secure_getenv("LD_LIBRARY_PATH"); if (!tmp) { tmp = ""; } @@ -2685,7 +2739,7 @@ static int copy_session_consumer(int domain, struct ltt_session *session) * domain. */ if (session->kernel_session->consumer) { - consumer_destroy_output(session->kernel_session->consumer); + consumer_output_put(session->kernel_session->consumer); } session->kernel_session->consumer = consumer_copy_output(session->consumer); @@ -2699,7 +2753,7 @@ static int copy_session_consumer(int domain, struct ltt_session *session) case LTTNG_DOMAIN_UST: DBG3("Copying tracing session consumer output in UST session"); if (session->ust_session->consumer) { - consumer_destroy_output(session->ust_session->consumer); + consumer_output_put(session->ust_session->consumer); } session->ust_session->consumer = consumer_copy_output(session->consumer); @@ -2764,7 +2818,16 @@ static int create_ust_session(struct ltt_session *session, lus->snapshot_mode = session->snapshot_mode; lus->live_timer_interval = session->live_timer; session->ust_session = lus; - + if (session->shm_path[0]) { + strncpy(lus->root_shm_path, session->shm_path, + sizeof(lus->root_shm_path)); + lus->root_shm_path[sizeof(lus->root_shm_path) - 1] = '\0'; + strncpy(lus->shm_path, session->shm_path, + sizeof(lus->shm_path)); + lus->shm_path[sizeof(lus->shm_path) - 1] = '\0'; + strncat(lus->shm_path, "/ust", + sizeof(lus->shm_path) - strlen(lus->shm_path) - 1); + } /* Copy session output to the newly created UST session */ ret = copy_session_consumer(domain->type, session); if (ret != LTTNG_OK) { @@ -2810,7 +2873,7 @@ static int create_kernel_session(struct ltt_session *session) session->kernel_session->consumer->dst.trace_path, S_IRWXU | S_IRWXG, session->uid, session->gid); if (ret < 0) { - if (ret != -EEXIST) { + if (errno != EEXIST) { ERR("Trace directory creation error"); goto error; } @@ -2889,6 +2952,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, case LTTNG_SNAPSHOT_LIST_OUTPUT: case LTTNG_SNAPSHOT_RECORD: case LTTNG_SAVE_SESSION: + case LTTNG_SET_SESSION_SHM_PATH: need_domain = 0; break; default: @@ -2929,6 +2993,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, case LTTNG_LIST_CHANNELS: case LTTNG_LIST_EVENTS: case LTTNG_LIST_SYSCALLS: + case LTTNG_LIST_TRACKER_PIDS: break; default: /* Setup lttng message with no payload */ @@ -3228,8 +3293,34 @@ skip_domain: } case LTTNG_DISABLE_EVENT: { + + /* + * FIXME: handle filter; for now we just receive the filter's + * bytecode along with the filter expression which are sent by + * liblttng-ctl and discard them. + * + * This fixes an issue where the client may block while sending + * the filter payload and encounter an error because the session + * daemon closes the socket without ever handling this data. + */ + size_t count = cmd_ctx->lsm->u.disable.expression_len + + cmd_ctx->lsm->u.disable.bytecode_len; + + if (count) { + char data[LTTNG_FILTER_MAX_LEN]; + + DBG("Discarding disable event command payload of size %zu", count); + while (count) { + ret = lttcomm_recv_unix_sock(sock, data, + count > sizeof(data) ? sizeof(data) : count); + if (ret < 0) { + goto error; + } + + count -= (size_t) ret; + } + } /* FIXME: passing packed structure to non-packed pointer */ - /* TODO: handle filter */ ret = cmd_disable_event(cmd_ctx->session, cmd_ctx->lsm->domain.type, cmd_ctx->lsm->u.disable.channel_name, &cmd_ctx->lsm->u.disable.event); @@ -3241,6 +3332,20 @@ skip_domain: &cmd_ctx->lsm->u.channel.chan, kernel_poll_pipe[1]); break; } + case LTTNG_TRACK_PID: + { + ret = cmd_track_pid(cmd_ctx->session, + cmd_ctx->lsm->domain.type, + cmd_ctx->lsm->u.pid_tracker.pid); + break; + } + case LTTNG_UNTRACK_PID: + { + ret = cmd_untrack_pid(cmd_ctx->session, + cmd_ctx->lsm->domain.type, + cmd_ctx->lsm->u.pid_tracker.pid); + break; + } case LTTNG_ENABLE_EVENT: { struct lttng_event_exclusion *exclusion = NULL; @@ -3450,6 +3555,38 @@ skip_domain: ret = LTTNG_OK; break; } + case LTTNG_LIST_TRACKER_PIDS: + { + int32_t *pids = NULL; + ssize_t nr_pids; + + nr_pids = cmd_list_tracker_pids(cmd_ctx->session, + cmd_ctx->lsm->domain.type, &pids); + if (nr_pids < 0) { + /* Return value is a negative lttng_error_code. */ + ret = -nr_pids; + goto error; + } + + /* + * Setup lttng message with payload size set to the event list size in + * bytes and then copy list into the llm payload. + */ + ret = setup_lttng_msg(cmd_ctx, sizeof(int32_t) * nr_pids); + if (ret < 0) { + free(pids); + goto setup_error; + } + + /* Copy event list into message payload */ + memcpy(cmd_ctx->llm->payload, pids, + sizeof(int) * nr_pids); + + free(pids); + + ret = LTTNG_OK; + break; + } case LTTNG_SET_CONSUMER_URI: { size_t nb_uri, len; @@ -3681,7 +3818,35 @@ skip_domain: } case LTTNG_DATA_PENDING: { - ret = cmd_data_pending(cmd_ctx->session); + int pending_ret; + + /* 1 byte to return whether or not data is pending */ + ret = setup_lttng_msg(cmd_ctx, 1); + if (ret < 0) { + goto setup_error; + } + + pending_ret = cmd_data_pending(cmd_ctx->session); + /* + * FIXME + * + * This function may returns 0 or 1 to indicate whether or not + * there is data pending. In case of error, it should return an + * LTTNG_ERR code. However, some code paths may still return + * a nondescript error code, which we handle by returning an + * "unknown" error. + */ + if (pending_ret == 0 || pending_ret == 1) { + ret = LTTNG_OK; + } else if (pending_ret < 0) { + ret = LTTNG_ERR_UNK; + goto setup_error; + } else { + ret = pending_ret; + goto setup_error; + } + + *cmd_ctx->llm->payload = (uint8_t) pending_ret; break; } case LTTNG_SNAPSHOT_ADD_OUTPUT: @@ -3829,6 +3994,12 @@ skip_domain: &cmd_ctx->creds); break; } + case LTTNG_SET_SESSION_SHM_PATH: + { + ret = cmd_set_session_shm_path(cmd_ctx->session, + cmd_ctx->lsm->u.set_shm_path.shm_path); + break; + } default: ret = LTTNG_ERR_UND; break; @@ -4242,9 +4413,10 @@ static void *thread_manage_clients(void *data) health_code_update(); - DBG("Sending response (size: %d, retcode: %s)", + DBG("Sending response (size: %d, retcode: %s (%d))", cmd_ctx->lttng_msg_size, - lttng_strerror(-cmd_ctx->llm->ret_code)); + lttng_strerror(-cmd_ctx->llm->ret_code), + cmd_ctx->llm->ret_code); ret = send_unix_sock(sock, cmd_ctx->llm, cmd_ctx->lttng_msg_size); if (ret < 0) { ERR("Failed to send data back to client"); @@ -4356,6 +4528,11 @@ static void usage(void) fprintf(stderr, " --extra-kmod-probes Specify extra kernel module probes to load\n"); } +static int string_match(const char *str1, const char *str2) +{ + return (str1 && str2) && !strcmp(str1, str2); +} + /* * Take an option from the getopt output and set it in the right variable to be * used later. @@ -4377,75 +4554,99 @@ static int set_option(int opt, const char *arg, const char *optname) goto end; } - switch (opt) { - case 0: - fprintf(stderr, "option %s", optname); - if (arg) { - fprintf(stderr, " with arg %s\n", arg); + if (string_match(optname, "client-sock") || opt == 'c') { + if (lttng_is_setuid_setgid()) { + WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", + "-c, --client-sock"); + } else { + snprintf(client_unix_sock_path, PATH_MAX, "%s", arg); } - break; - case 'c': - snprintf(client_unix_sock_path, PATH_MAX, "%s", arg); - break; - case 'a': - snprintf(apps_unix_sock_path, PATH_MAX, "%s", arg); - break; - case 'd': + } else if (string_match(optname, "apps-sock") || opt == 'a') { + if (lttng_is_setuid_setgid()) { + WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", + "-a, --apps-sock"); + } else { + snprintf(apps_unix_sock_path, PATH_MAX, "%s", arg); + } + } else if (string_match(optname, "daemonize") || opt == 'd') { opt_daemon = 1; - break; - case 'b': + } else if (string_match(optname, "background") || opt == 'b') { opt_background = 1; - break; - case 'g': - /* - * If the override option is set, the pointer points to a - * *non* const thus freeing it even though the variable type is - * set to const. - */ - if (tracing_group_name_override) { - free((void *) tracing_group_name); - } - tracing_group_name = strdup(arg); - if (!tracing_group_name) { - PERROR("strdup"); - ret = -ENOMEM; + } else if (string_match(optname, "group") || opt == 'g') { + if (lttng_is_setuid_setgid()) { + WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", + "-g, --group"); + } else { + /* + * If the override option is set, the pointer points to a + * *non* const thus freeing it even though the variable type is + * set to const. + */ + if (tracing_group_name_override) { + free((void *) tracing_group_name); + } + tracing_group_name = strdup(arg); + if (!tracing_group_name) { + PERROR("strdup"); + ret = -ENOMEM; + } + tracing_group_name_override = 1; } - tracing_group_name_override = 1; - break; - case 'h': + } else if (string_match(optname, "help") || opt == 'h') { usage(); exit(EXIT_SUCCESS); - case 'V': + } else if (string_match(optname, "version") || opt == 'V') { fprintf(stdout, "%s\n", VERSION); exit(EXIT_SUCCESS); - case 'S': + } else if (string_match(optname, "sig-parent") || opt == 'S') { opt_sig_parent = 1; - break; - case 'E': - snprintf(kconsumer_data.err_unix_sock_path, PATH_MAX, "%s", arg); - break; - case 'C': - snprintf(kconsumer_data.cmd_unix_sock_path, PATH_MAX, "%s", arg); - break; - case 'F': - snprintf(ustconsumer64_data.err_unix_sock_path, PATH_MAX, "%s", arg); - break; - case 'D': - snprintf(ustconsumer64_data.cmd_unix_sock_path, PATH_MAX, "%s", arg); - break; - case 'H': - snprintf(ustconsumer32_data.err_unix_sock_path, PATH_MAX, "%s", arg); - break; - case 'G': - snprintf(ustconsumer32_data.cmd_unix_sock_path, PATH_MAX, "%s", arg); - break; - case 'N': + } else if (string_match(optname, "kconsumerd-err-sock")) { + if (lttng_is_setuid_setgid()) { + WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", + "--kconsumerd-err-sock"); + } else { + snprintf(kconsumer_data.err_unix_sock_path, PATH_MAX, "%s", arg); + } + } else if (string_match(optname, "kconsumerd-cmd-sock")) { + if (lttng_is_setuid_setgid()) { + WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", + "--kconsumerd-cmd-sock"); + } else { + snprintf(kconsumer_data.cmd_unix_sock_path, PATH_MAX, "%s", arg); + } + } else if (string_match(optname, "ustconsumerd64-err-sock")) { + if (lttng_is_setuid_setgid()) { + WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", + "--ustconsumerd64-err-sock"); + } else { + snprintf(ustconsumer64_data.err_unix_sock_path, PATH_MAX, "%s", arg); + } + } else if (string_match(optname, "ustconsumerd64-cmd-sock")) { + if (lttng_is_setuid_setgid()) { + WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", + "--ustconsumerd64-cmd-sock"); + } else { + snprintf(ustconsumer64_data.cmd_unix_sock_path, PATH_MAX, "%s", arg); + } + } else if (string_match(optname, "ustconsumerd32-err-sock")) { + if (lttng_is_setuid_setgid()) { + WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", + "--ustconsumerd32-err-sock"); + } else { + snprintf(ustconsumer32_data.err_unix_sock_path, PATH_MAX, "%s", arg); + } + } else if (string_match(optname, "ustconsumerd32-cmd-sock")) { + if (lttng_is_setuid_setgid()) { + WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", + "--ustconsumerd32-cmd-sock"); + } else { + snprintf(ustconsumer32_data.cmd_unix_sock_path, PATH_MAX, "%s", arg); + } + } else if (string_match(optname, "no-kernel")) { opt_no_kernel = 1; - break; - case 'q': + } else if (string_match(optname, "quiet") || opt == 'q') { lttng_opt_quiet = 1; - break; - case 'v': + } else if (string_match(optname, "verbose") || opt == 'v') { /* Verbose level can increase using multiple -v */ if (arg) { /* Value obtained from config file */ @@ -4457,112 +4658,148 @@ static int set_option(int opt, const char *arg, const char *optname) /* Clamp value to [0, 3] */ lttng_opt_verbose = lttng_opt_verbose < 0 ? 0 : (lttng_opt_verbose <= 3 ? lttng_opt_verbose : 3); - break; - case 'Z': + } else if (string_match(optname, "verbose-consumer")) { if (arg) { opt_verbose_consumer = config_parse_value(arg); } else { opt_verbose_consumer += 1; } - break; - case 'u': - if (consumerd32_bin_override) { - free((void *) consumerd32_bin); - } - consumerd32_bin = strdup(arg); - if (!consumerd32_bin) { - PERROR("strdup"); - ret = -ENOMEM; - } - consumerd32_bin_override = 1; - break; - case 'U': - if (consumerd32_libdir_override) { - free((void *) consumerd32_libdir); - } - consumerd32_libdir = strdup(arg); - if (!consumerd32_libdir) { - PERROR("strdup"); - ret = -ENOMEM; - } - consumerd32_libdir_override = 1; - break; - case 't': - if (consumerd64_bin_override) { - free((void *) consumerd64_bin); + } else if (string_match(optname, "consumerd32-path")) { + if (lttng_is_setuid_setgid()) { + WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", + "--consumerd32-path"); + } else { + if (consumerd32_bin_override) { + free((void *) consumerd32_bin); + } + consumerd32_bin = strdup(arg); + if (!consumerd32_bin) { + PERROR("strdup"); + ret = -ENOMEM; + } + consumerd32_bin_override = 1; } - consumerd64_bin = strdup(arg); - if (!consumerd64_bin) { - PERROR("strdup"); - ret = -ENOMEM; + } else if (string_match(optname, "consumerd32-libdir")) { + if (lttng_is_setuid_setgid()) { + WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", + "--consumerd32-libdir"); + } else { + if (consumerd32_libdir_override) { + free((void *) consumerd32_libdir); + } + consumerd32_libdir = strdup(arg); + if (!consumerd32_libdir) { + PERROR("strdup"); + ret = -ENOMEM; + } + consumerd32_libdir_override = 1; } - consumerd64_bin_override = 1; - break; - case 'T': - if (consumerd64_libdir_override) { - free((void *) consumerd64_libdir); + } else if (string_match(optname, "consumerd64-path")) { + if (lttng_is_setuid_setgid()) { + WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", + "--consumerd64-path"); + } else { + if (consumerd64_bin_override) { + free((void *) consumerd64_bin); + } + consumerd64_bin = strdup(arg); + if (!consumerd64_bin) { + PERROR("strdup"); + ret = -ENOMEM; + } + consumerd64_bin_override = 1; } - consumerd64_libdir = strdup(arg); - if (!consumerd64_libdir) { - PERROR("strdup"); - ret = -ENOMEM; + } else if (string_match(optname, "consumerd64-libdir")) { + if (lttng_is_setuid_setgid()) { + WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", + "--consumerd64-libdir"); + } else { + if (consumerd64_libdir_override) { + free((void *) consumerd64_libdir); + } + consumerd64_libdir = strdup(arg); + if (!consumerd64_libdir) { + PERROR("strdup"); + ret = -ENOMEM; + } + consumerd64_libdir_override = 1; } - consumerd64_libdir_override = 1; - break; - case 'p': - free(opt_pidfile); - opt_pidfile = strdup(arg); - if (!opt_pidfile) { - PERROR("strdup"); - ret = -ENOMEM; + } else if (string_match(optname, "pidfile") || opt == 'p') { + if (lttng_is_setuid_setgid()) { + WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", + "-p, --pidfile"); + } else { + free(opt_pidfile); + opt_pidfile = strdup(arg); + if (!opt_pidfile) { + PERROR("strdup"); + ret = -ENOMEM; + } } - break; - case 'J': /* Agent TCP port. */ - { - unsigned long v; + } else if (string_match(optname, "agent-tcp-port")) { + if (lttng_is_setuid_setgid()) { + WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", + "--agent-tcp-port"); + } else { + unsigned long v; - errno = 0; - v = strtoul(arg, NULL, 0); - if (errno != 0 || !isdigit(arg[0])) { - ERR("Wrong value in --agent-tcp-port parameter: %s", arg); - return -1; - } - if (v == 0 || v >= 65535) { - ERR("Port overflow in --agent-tcp-port parameter: %s", arg); - return -1; + if (!arg) { + ret = -EINVAL; + goto end; + } + errno = 0; + v = strtoul(arg, NULL, 0); + if (errno != 0 || !isdigit(arg[0])) { + ERR("Wrong value in --agent-tcp-port parameter: %s", arg); + return -1; + } + if (v == 0 || v >= 65535) { + ERR("Port overflow in --agent-tcp-port parameter: %s", arg); + return -1; + } + agent_tcp_port = (uint32_t) v; + DBG3("Agent TCP port set to non default: %u", agent_tcp_port); } - agent_tcp_port = (uint32_t) v; - DBG3("Agent TCP port set to non default: %u", agent_tcp_port); - break; - } - case 'l': - free(opt_load_session_path); - opt_load_session_path = strdup(arg); - if (!opt_load_session_path) { - PERROR("strdup"); - ret = -ENOMEM; + } else if (string_match(optname, "load") || opt == 'l') { + if (lttng_is_setuid_setgid()) { + WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", + "-l, --load"); + } else { + free(opt_load_session_path); + opt_load_session_path = strdup(arg); + if (!opt_load_session_path) { + PERROR("strdup"); + ret = -ENOMEM; + } } - break; - case 'P': /* probe modules list */ - free(kmod_probes_list); - kmod_probes_list = strdup(arg); - if (!kmod_probes_list) { - PERROR("strdup"); - ret = -ENOMEM; + } else if (string_match(optname, "kmod-probes")) { + if (lttng_is_setuid_setgid()) { + WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", + "--kmod-probes"); + } else { + free(kmod_probes_list); + kmod_probes_list = strdup(arg); + if (!kmod_probes_list) { + PERROR("strdup"); + ret = -ENOMEM; + } } - break; - case 'e': - free(kmod_extra_probes_list); - kmod_extra_probes_list = strdup(arg); - if (!kmod_extra_probes_list) { - PERROR("strdup"); - ret = -ENOMEM; + } else if (string_match(optname, "extra-kmod-probes")) { + if (lttng_is_setuid_setgid()) { + WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", + "--extra-kmod-probes"); + } else { + free(kmod_extra_probes_list); + kmod_extra_probes_list = strdup(arg); + if (!kmod_extra_probes_list) { + PERROR("strdup"); + ret = -ENOMEM; + } } - break; - case 'f': - /* This is handled in set_options() thus silent break. */ - break; - default: + } else if (string_match(optname, "config") || opt == 'f') { + /* This is handled in set_options() thus silent skip. */ + goto end; + } else { /* Unknown option or other error. * Error is printed by getopt, just return */ ret = -1; @@ -4672,9 +4909,14 @@ static int set_options(int argc, char **argv) continue; } - config_path = utils_expand_path(optarg); - if (!config_path) { - ERR("Failed to resolve path: %s", optarg); + if (lttng_is_setuid_setgid()) { + WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", + "-f, --config"); + } else { + config_path = utils_expand_path(optarg); + if (!config_path) { + ERR("Failed to resolve path: %s", optarg); + } } } @@ -4692,12 +4934,24 @@ static int set_options(int argc, char **argv) optopt = orig_optopt; optind = orig_optind; while (1) { - c = getopt_long(argc, argv, optstring, long_options, &option_index); + option_index = -1; + /* + * getopt_long() will not set option_index if it encounters a + * short option. + */ + c = getopt_long(argc, argv, optstring, long_options, + &option_index); if (c == -1) { break; } - ret = set_option(c, optarg, long_options[option_index].name); + /* + * Pass NULL as the long option name if popt left the index + * unset. + */ + ret = set_option(c, optarg, + option_index < 0 ? NULL : + long_options[option_index].name); if (ret < 0) { break; } @@ -5447,13 +5701,17 @@ int main(int argc, char **argv) * cleanup() can get called after that point. */ if (ust_app_ht_alloc()) { + ERR("Failed to allocate UST app hash table"); retval = -1; goto exit_init_data; } - /* Initialize agent domain subsystem. */ - if (agent_setup()) { - /* ENOMEM at this point. */ + /* + * Initialize agent app hash table. We allocate the hash table here + * since cleanup() can get called after this point. + */ + if (agent_app_ht_alloc()) { + ERR("Failed to allocate Agent app hash table"); retval = -1; goto exit_init_data; } @@ -5731,6 +5989,10 @@ exit_apps: } exit_reg_apps: + /* + * Join dispatch thread after joining reg_apps_thread to ensure + * we don't leak applications in the queue. + */ ret = pthread_join(dispatch_thread, &status); if (ret) { errno = ret;