X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fcommon%2Fconfig%2Fconfig.c;h=03601be486deacc189f260251108534156aa0c1c;hp=cdc044d6dc72fda892f9f2d3239140714ad61eb0;hb=847a5916c26ab9cc0dfc9322cccd2c748c54747e;hpb=7ab02a271869642f4b34d4bd4dd9a68b3207271d diff --git a/src/common/config/config.c b/src/common/config/config.c index cdc044d6d..03601be48 100644 --- a/src/common/config/config.c +++ b/src/common/config/config.c @@ -16,6 +16,7 @@ */ #define _GNU_SOURCE +#define _LGPL_SOURCE #include #include #include @@ -31,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -113,10 +115,19 @@ const char * const config_element_net_output = "net_output"; const char * const config_element_control_uri = "control_uri"; const char * const config_element_data_uri = "data_uri"; const char * const config_element_max_size = "max_size"; +const char * const config_element_pid = "pid"; +const char * const config_element_pids = "pids"; +const char * const config_element_shared_memory_path = "shared_memory_path"; +const char * const config_element_pid_tracker = "pid_tracker"; +const char * const config_element_trackers = "trackers"; +const char * const config_element_targets = "targets"; +const char * const config_element_target_pid = "pid_target"; const char * const config_domain_type_kernel = "KERNEL"; const char * const config_domain_type_ust = "UST"; const char * const config_domain_type_jul = "JUL"; +const char * const config_domain_type_log4j = "LOG4J"; +const char * const config_domain_type_python = "PYTHON"; const char * const config_buffer_type_per_pid = "PER_PID"; const char * const config_buffer_type_per_uid = "PER_UID"; @@ -154,6 +165,7 @@ const char * const config_event_context_vppid = "VPPID"; const char * const config_event_context_pthread_id = "PTHREAD_ID"; const char * const config_event_context_hostname = "HOSTNAME"; const char * const config_event_context_ip = "IP"; +const char * const config_event_context_perf_thread_counter = "PERF_THREAD_COUNTER"; struct consumer_output { int enabled; @@ -352,7 +364,7 @@ end: } LTTNG_HIDDEN -struct config_writer *config_writer_create(int fd_output) +struct config_writer *config_writer_create(int fd_output, int indent) { int ret; struct config_writer *writer; @@ -378,12 +390,12 @@ struct config_writer *config_writer_create(int fd_output) ret = xmlTextWriterSetIndentString(writer->writer, BAD_CAST config_xml_indent_string); - if (ret) { + if (ret) { goto error_destroy; } - ret = xmlTextWriterSetIndent(writer->writer, 1); - if (ret) { + ret = xmlTextWriterSetIndent(writer->writer, indent); + if (ret) { goto error_destroy; } @@ -591,7 +603,7 @@ static char *get_session_config_xsd_path() { char *xsd_path; - const char *base_path = getenv(DEFAULT_SESSION_CONFIG_XSD_PATH_ENV); + const char *base_path = lttng_secure_getenv(DEFAULT_SESSION_CONFIG_XSD_PATH_ENV); size_t base_path_len; size_t max_path_len; @@ -748,6 +760,10 @@ int get_domain_type(xmlChar *domain) ret = LTTNG_DOMAIN_UST; } else if (!strcmp((char *) domain, config_domain_type_jul)) { ret = LTTNG_DOMAIN_JUL; + } else if (!strcmp((char *) domain, config_domain_type_log4j)) { + ret = LTTNG_DOMAIN_LOG4J; + } else if (!strcmp((char *) domain, config_domain_type_python)) { + ret = LTTNG_DOMAIN_PYTHON; } else { goto error; } @@ -1235,6 +1251,7 @@ int create_session(const char *name, struct lttng_domain *kernel_domain, struct lttng_domain *ust_domain, struct lttng_domain *jul_domain, + struct lttng_domain *log4j_domain, xmlNodePtr output_node, uint64_t live_timer_interval) { @@ -1275,7 +1292,7 @@ int create_session(const char *name, int i; struct lttng_domain *domain; struct lttng_domain *domains[] = - { kernel_domain, ust_domain, jul_domain }; + { kernel_domain, ust_domain, jul_domain, log4j_domain }; /* network destination */ if (live_timer_interval && live_timer_interval != UINT64_MAX) { @@ -1631,6 +1648,24 @@ int process_event_node(xmlNodePtr event_node, struct lttng_handle *handle, ret = lttng_enable_event_with_exclusions(handle, &event, channel_name, filter_expression, exclusion_count, exclusions); + if (ret) { + goto end; + } + + if (!event.enabled) { + /* + * Note that we should use lttng_disable_event_ext() (2.6+) to + * eliminate the risk of clashing on events of the same + * name (with different event types and loglevels). + * + * Unfortunately, lttng_disable_event_ext() only performs a + * match on the name and event type and errors out if any other + * event attribute is not set to its default value. + * + * This will disable all events that match this name. + */ + ret = lttng_disable_event(handle, event.name, channel_name); + } end: for (i = 0; i < exclusion_count; i++) { free(exclusions[i]); @@ -1955,7 +1990,9 @@ int process_context_node(xmlNodePtr context_node, xmlNodePtr perf_attr_node; /* perf */ - context.ctx = LTTNG_EVENT_CONTEXT_PERF_COUNTER; + context.ctx = handle->domain.type == LTTNG_DOMAIN_KERNEL ? + LTTNG_EVENT_CONTEXT_PERF_CPU_COUNTER : + LTTNG_EVENT_CONTEXT_PERF_THREAD_COUNTER; for (perf_attr_node = xmlFirstElementChild(context_child_node); perf_attr_node; perf_attr_node = xmlNextElementSibling(perf_attr_node)) { @@ -2055,6 +2092,79 @@ end: return ret; } +static +int process_pid_tracker_node(xmlNodePtr pid_tracker_node, + struct lttng_handle *handle) +{ + int ret, child; + xmlNodePtr targets_node = NULL; + xmlNodePtr node; + + assert(handle); + assert(pid_tracker_node); + /* get the targets node */ + for (node = xmlFirstElementChild(pid_tracker_node); node; + node = xmlNextElementSibling(node)) { + if (!strcmp((const char *) node->name, + config_element_targets)) { + targets_node = node; + break; + } + } + + if (!targets_node) { + ret = LTTNG_ERR_INVALID; + goto end; + } + + /* Go through all pid_target node */ + child = xmlChildElementCount(targets_node); + if (child == 0) { + /* The session is explicitly set to target nothing. */ + ret = lttng_untrack_pid(handle, -1); + if (ret) { + goto end; + } + } + for (node = xmlFirstElementChild(targets_node); node; + node = xmlNextElementSibling(node)) { + xmlNodePtr pid_target_node = node; + + /* get pid node and track it */ + for (node = xmlFirstElementChild(pid_target_node); node; + node = xmlNextElementSibling(node)) { + if (!strcmp((const char *) node->name, + config_element_pid)) { + int64_t pid; + xmlChar *content = NULL; + + content = xmlNodeGetContent(node); + if (!content) { + ret = LTTNG_ERR_LOAD_INVALID_CONFIG; + goto end; + } + + ret = parse_int(content, &pid); + free(content); + if (ret) { + ret = LTTNG_ERR_LOAD_INVALID_CONFIG; + goto end; + } + + ret = lttng_track_pid(handle, (int) pid); + if (ret) { + goto end; + } + } + } + node = pid_target_node; + } + +end: + return ret; +} + + static int process_domain_node(xmlNodePtr domain_node, const char *session_name) { @@ -2062,6 +2172,8 @@ int process_domain_node(xmlNodePtr domain_node, const char *session_name) struct lttng_domain domain = { 0 }; struct lttng_handle *handle = NULL; xmlNodePtr channels_node = NULL; + xmlNodePtr trackers_node = NULL; + xmlNodePtr pid_tracker_node = NULL; xmlNodePtr node; assert(session_name); @@ -2128,6 +2240,36 @@ int process_domain_node(xmlNodePtr domain_node, const char *session_name) goto end; } } + + /* get the trackers node */ + for (node = xmlFirstElementChild(domain_node); node; + node = xmlNextElementSibling(node)) { + if (!strcmp((const char *) node->name, + config_element_trackers)) { + trackers_node = node; + break; + } + } + + if (!trackers_node) { + goto end; + } + + for (node = xmlFirstElementChild(trackers_node); node; + node = xmlNextElementSibling(node)) { + if (!strcmp((const char *)node->name,config_element_pid_tracker)) { + pid_tracker_node = node; + ret = process_pid_tracker_node(pid_tracker_node, handle); + if (ret) { + goto end; + } + } + } + + if (!pid_tracker_node) { + lttng_track_pid(handle, -1); + } + end: lttng_destroy_handle(handle); return ret; @@ -2139,13 +2281,16 @@ int process_session_node(xmlNodePtr session_node, const char *session_name, { int ret, started = -1, snapshot_mode = -1; uint64_t live_timer_interval = UINT64_MAX; - char *name = NULL; + xmlChar *name = NULL; + xmlChar *shm_path = NULL; xmlNodePtr domains_node = NULL; xmlNodePtr output_node = NULL; xmlNodePtr node; struct lttng_domain *kernel_domain = NULL; struct lttng_domain *ust_domain = NULL; struct lttng_domain *jul_domain = NULL; + struct lttng_domain *log4j_domain = NULL; + struct lttng_domain *python_domain = NULL; for (node = xmlFirstElementChild(session_node); node; node = xmlNextElementSibling(node)) { @@ -2155,10 +2300,10 @@ int process_session_node(xmlNodePtr session_node, const char *session_name, xmlChar *node_content = xmlNodeGetContent(node); if (!node_content) { ret = -LTTNG_ERR_NOMEM; - goto end; + goto error; } - name = (char *) node_content; + name = node_content; } else if (!domains_node && !strcmp((const char *) node->name, config_element_domains)) { /* domains */ @@ -2169,19 +2314,29 @@ int process_session_node(xmlNodePtr session_node, const char *session_name, xmlChar *node_content = xmlNodeGetContent(node); if (!node_content) { ret = -LTTNG_ERR_NOMEM; - goto end; + goto error; } ret = parse_bool(node_content, &started); free(node_content); if (ret) { ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; - goto end; + goto error; } } else if (!output_node && !strcmp((const char *) node->name, config_element_output)) { /* output */ output_node = node; + } else if (!shm_path && !strcmp((const char *) node->name, + config_element_shared_memory_path)) { + /* shared memory path */ + xmlChar *node_content = xmlNodeGetContent(node); + if (!node_content) { + ret = -LTTNG_ERR_NOMEM; + goto error; + } + + shm_path = node_content; } else { /* attributes, snapshot_mode or live_timer_interval */ xmlNodePtr attributes_child = @@ -2194,14 +2349,14 @@ int process_session_node(xmlNodePtr session_node, const char *session_name, xmlNodeGetContent(attributes_child); if (!snapshot_mode_content) { ret = -LTTNG_ERR_NOMEM; - goto end; + goto error; } ret = parse_bool(snapshot_mode_content, &snapshot_mode); free(snapshot_mode_content); if (ret) { ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; - goto end; + goto error; } } else { /* live_timer_interval */ @@ -2209,14 +2364,14 @@ int process_session_node(xmlNodePtr session_node, const char *session_name, xmlNodeGetContent(attributes_child); if (!timer_interval_content) { ret = -LTTNG_ERR_NOMEM; - goto end; + goto error; } ret = parse_uint(timer_interval_content, &live_timer_interval); free(timer_interval_content); if (ret) { ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; - goto end; + goto error; } } } @@ -2225,13 +2380,13 @@ int process_session_node(xmlNodePtr session_node, const char *session_name, if (!name) { /* Mandatory attribute, as defined in the session XSD */ ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; - goto end; + goto error; } - if (session_name && strcmp(name, session_name)) { + if (session_name && strcmp((char *) name, session_name)) { /* This is not the session we are looking for */ - ret = -LTTNG_ERR_LOAD_SESSION_NOENT; - goto end; + ret = -LTTNG_ERR_NO_SESSION; + goto error; } /* Init domains to create the session handles */ @@ -2242,7 +2397,7 @@ int process_session_node(xmlNodePtr session_node, const char *session_name, domain = zmalloc(sizeof(*domain)); if (!domain) { ret = -LTTNG_ERR_NOMEM; - goto end; + goto error; } ret = init_domain(node, domain); @@ -2272,6 +2427,20 @@ int process_session_node(xmlNodePtr session_node, const char *session_name, } jul_domain = domain; break; + case LTTNG_DOMAIN_LOG4J: + if (log4j_domain) { + /* Same domain seen twice, invalid! */ + goto domain_init_error; + } + log4j_domain = domain; + break; + case LTTNG_DOMAIN_PYTHON: + if (python_domain) { + /* Same domain seen twice, invalid! */ + goto domain_init_error; + } + python_domain = domain; + break; default: WARN("Invalid domain type"); goto domain_init_error; @@ -2280,62 +2449,102 @@ int process_session_node(xmlNodePtr session_node, const char *session_name, domain_init_error: free(domain); ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; - goto end; + goto error; } if (override) { /* Destroy session if it exists */ - ret = lttng_destroy_session(name); + ret = lttng_destroy_session((const char *) name); if (ret && ret != -LTTNG_ERR_SESS_NOT_FOUND) { ERR("Failed to destroy existing session."); - goto end; + goto error; } } /* Create session type depending on output type */ if (snapshot_mode && snapshot_mode != -1) { - ret = create_snapshot_session(name, output_node); + ret = create_snapshot_session((const char *) name, output_node); } else if (live_timer_interval && live_timer_interval != UINT64_MAX) { - ret = create_session(name, kernel_domain, ust_domain, jul_domain, + ret = create_session((const char *) name, kernel_domain, + ust_domain, jul_domain, log4j_domain, output_node, live_timer_interval); } else { /* regular session */ - ret = create_session(name, kernel_domain, ust_domain, jul_domain, + ret = create_session((const char *) name, kernel_domain, + ust_domain, jul_domain, log4j_domain, output_node, UINT64_MAX); } - if (ret) { - goto end; + goto error; + } + + if (shm_path) { + ret = lttng_set_session_shm_path((const char *) name, + (const char *) shm_path); + if (ret) { + goto error; + } } for (node = xmlFirstElementChild(domains_node); node; node = xmlNextElementSibling(node)) { - ret = process_domain_node(node, name); + ret = process_domain_node(node, (const char *) name); if (ret) { goto end; } } if (started) { - ret = lttng_start_tracing(name); + ret = lttng_start_tracing((const char *) name); if (ret) { goto end; } } + end: if (ret < 0) { - ERR("Failed to load session %s: %s", name, lttng_strerror(ret)); - lttng_destroy_session(name); + ERR("Failed to load session %s: %s", (const char *) name, + lttng_strerror(ret)); + lttng_destroy_session((const char *) name); } +error: free(kernel_domain); free(ust_domain); free(jul_domain); - free(name); + free(log4j_domain); + free(python_domain); + xmlFree(name); + xmlFree(shm_path); return ret; } +/* + * Return 1 if the given path is readable by the current UID or 0 if not. + * Return -1 if the path is EPERM. + */ +static int validate_file_read_creds(const char *path) +{ + int ret; + + assert(path); + + /* Can we read the file. */ + ret = access(path, R_OK); + if (!ret) { + goto valid; + } + if (errno == EACCES) { + return -1; + } else { + /* Invalid. */ + return 0; + } +valid: + return 1; +} + static int load_session_from_file(const char *path, const char *session_name, struct session_config_validation_ctx *validation_ctx, int override) @@ -2344,14 +2553,17 @@ int load_session_from_file(const char *path, const char *session_name, xmlDocPtr doc = NULL; xmlNodePtr sessions_node; xmlNodePtr session_node; - struct stat sb; assert(path); assert(validation_ctx); - ret = stat(path, &sb); - if (ret) { - ret = -LTTNG_ERR_LOAD_SESSION_NOENT; + ret = validate_file_read_creds(path); + if (ret != 1) { + if (ret == -1) { + ret = -LTTNG_ERR_EPERM; + } else { + ret = -LTTNG_ERR_LOAD_SESSION_NOENT; + } goto end; } @@ -2392,6 +2604,23 @@ end: return ret; } +/* Allocate dirent as recommended by READDIR(3), NOTES on readdir_r */ +static +struct dirent *alloc_dirent(const char *path) +{ + size_t len; + long name_max; + struct dirent *entry; + + name_max = pathconf(path, _PC_NAME_MAX); + if (name_max == -1) { + name_max = PATH_MAX; + } + len = offsetof(struct dirent, d_name) + name_max + 1; + entry = zmalloc(len); + return entry; +} + static int load_session_from_path(const char *path, const char *session_name, struct session_config_validation_ctx *validation_ctx, int override) @@ -2427,7 +2656,7 @@ int load_session_from_path(const char *path, const char *session_name, goto end; } - entry = zmalloc(sizeof(*entry)); + entry = alloc_dirent(path); if (!entry) { ret = -LTTNG_ERR_NOMEM; goto end; @@ -2502,11 +2731,46 @@ end: return ret; } +/* + * Validate that the given path's credentials and the current process have the + * same UID. If so, return 1 else return 0 if it does NOT match. + */ +static int validate_path_creds(const char *path) +{ + int ret, uid = getuid(); + struct stat buf; + + assert(path); + + if (uid == 0) { + goto valid; + } + + ret = stat(path, &buf); + if (ret < 0) { + if (errno != ENOENT) { + PERROR("stat"); + } + ret = -LTTNG_ERR_INVALID; + goto valid; + } + + if (buf.st_uid != uid) { + goto invalid; + } + +valid: + return 1; +invalid: + return 0; +} + LTTNG_HIDDEN int config_load_session(const char *path, const char *session_name, - int override) + int override, unsigned int autoload) { int ret; + const char *path_ptr = NULL; struct session_config_validation_ctx validation_ctx = { 0 }; ret = init_session_config_validation_ctx(&validation_ctx); @@ -2515,34 +2779,77 @@ int config_load_session(const char *path, const char *session_name, } if (!path) { + char *home_path; + const char *sys_path; + /* Try home path */ - char *home_path = utils_get_home_dir(); + home_path = utils_get_home_dir(); if (home_path) { - char *path; + char path[PATH_MAX]; - ret = asprintf(&path, DEFAULT_SESSION_HOME_CONFIGPATH, - home_path); - if (ret < 0) { - goto end; - } + /* + * Try user session configuration path. Ignore error here so we can + * continue loading the system wide sessions. + */ + if (autoload) { + ret = snprintf(path, sizeof(path), + DEFAULT_SESSION_HOME_CONFIGPATH "/" + DEFAULT_SESSION_CONFIG_AUTOLOAD, home_path); + if (ret < 0) { + PERROR("snprintf session autoload home config path"); + goto end; + } - ret = load_session_from_path(path, session_name, - &validation_ctx, 0); - if (!ret || (ret && ret != -LTTNG_ERR_LOAD_SESSION_NOENT)) { - /* Session found or an error occured */ - free(path); - goto end; + /* + * Credentials are only validated for the autoload in order to + * avoid any user session daemon to try to load kernel sessions + * automatically and failing all the times. + */ + ret = validate_path_creds(path); + if (ret) { + path_ptr = path; + } + } else { + ret = snprintf(path, sizeof(path), + DEFAULT_SESSION_HOME_CONFIGPATH, home_path); + if (ret < 0) { + PERROR("snprintf session home config path"); + goto end; + } + path_ptr = path; } + if (path_ptr) { + ret = load_session_from_path(path_ptr, session_name, + &validation_ctx, override); + if (ret && ret != -LTTNG_ERR_LOAD_SESSION_NOENT) { + goto end; + } + /* + * Continue even if the session was found since we have to try + * the system wide sessions. + */ + } + } - free(path); + /* Reset path pointer for the system wide dir. */ + path_ptr = NULL; + + /* Try system wide configuration directory. */ + if (autoload) { + sys_path = DEFAULT_SESSION_SYSTEM_CONFIGPATH "/" + DEFAULT_SESSION_CONFIG_AUTOLOAD; + ret = validate_path_creds(sys_path); + if (ret) { + path_ptr = sys_path; + } + } else { + sys_path = DEFAULT_SESSION_SYSTEM_CONFIGPATH; + path_ptr = sys_path; } - /* Try system session configuration path */ - ret = load_session_from_path(DEFAULT_SESSION_SYSTEM_CONFIGPATH, - session_name, &validation_ctx, 0); - if (!ret || (ret && ret != -LTTNG_ERR_LOAD_SESSION_NOENT)) { - /* Session found or an error occured */ - goto end; + if (path_ptr) { + ret = load_session_from_path(path_ptr, session_name, + &validation_ctx, override); } } else { ret = access(path, F_OK);