Fix: sessiond: double free on duplicate removal of tracer source
[lttng-tools.git] / src / bin / lttng-sessiond / notification-thread-events.c
index d5a3f95026f0d3b4af2ed83c74751e9b41a645e3..212746faa1c7a50d67e3006f868908222a00d22c 100644 (file)
@@ -27,6 +27,7 @@
 #include <lttng/condition/session-consumed-size-internal.h>
 #include <lttng/condition/session-rotation-internal.h>
 #include <lttng/condition/event-rule-internal.h>
+#include <lttng/domain-internal.h>
 #include <lttng/notification/channel-internal.h>
 #include <lttng/trigger/trigger-internal.h>
 #include <lttng/event-rule/event-rule-internal.h>
@@ -280,6 +281,17 @@ int match_trigger(struct cds_lfht_node *node, const void *key)
        return !!lttng_trigger_is_equal(trigger_key, trigger_ht_element->trigger);
 }
 
+static
+int match_trigger_token(struct cds_lfht_node *node, const void *key)
+{
+       const uint64_t *_key = key;
+       struct notification_trigger_tokens_ht_element *element;
+
+       element = caa_container_of(node,
+                       struct notification_trigger_tokens_ht_element, node);
+       return *_key == element->token;
+}
+
 static
 int match_client_list_condition(struct cds_lfht_node *node, const void *key)
 {
@@ -925,6 +937,7 @@ int evaluate_condition_for_client(const struct lttng_trigger *trigger,
                                &evaluation, &object_uid, &object_gid);
                break;
        case LTTNG_OBJECT_TYPE_NONE:
+               DBG("[notification-thread] Newly subscribed-to condition not bound to object, nothing to evaluate");
                ret = 0;
                goto end;
        case LTTNG_OBJECT_TYPE_UNKNOWN:
@@ -1890,6 +1903,126 @@ end:
        return ret;
 }
 
+static
+int handle_notification_thread_command_add_tracer_event_source(
+               struct notification_thread_state *state,
+               int tracer_event_source_fd,
+               enum lttng_domain_type domain_type,
+               enum lttng_error_code *_cmd_result)
+{
+       int ret = 0;
+       enum lttng_error_code cmd_result = LTTNG_OK;
+       struct notification_event_tracer_event_source_element *element = NULL;
+
+       element = zmalloc(sizeof(*element));
+       if (!element) {
+               cmd_result = LTTNG_ERR_NOMEM;
+               ret = -1;
+               goto end;
+       }
+
+       element->fd = tracer_event_source_fd;
+       element->domain = domain_type;
+
+       cds_list_add(&element->node, &state->tracer_event_sources_list);
+
+       DBG3("[notification-thread] Adding tracer event source fd to poll set: tracer_event_source_fd = %d, domain = '%s'",
+                       tracer_event_source_fd,
+                       lttng_domain_type_str(domain_type));
+
+       /* Adding the read side pipe to the event poll. */
+       ret = lttng_poll_add(&state->events, tracer_event_source_fd, LPOLLIN | LPOLLERR);
+       if (ret < 0) {
+               ERR("[notification-thread] Failed to add tracer event source to poll set: tracer_event_source_fd = %d, domain = '%s'",
+                               tracer_event_source_fd,
+                               lttng_domain_type_str(element->domain));
+               cds_list_del(&element->node);
+               free(element);
+               goto end;
+       }
+
+       element->is_fd_in_poll_set = true;
+
+end:
+       *_cmd_result = cmd_result;
+       return ret;
+}
+
+static
+int handle_notification_thread_command_remove_tracer_event_source(
+               struct notification_thread_state *state,
+               int tracer_event_source_fd,
+               enum lttng_error_code *_cmd_result)
+{
+       int ret = 0;
+       bool found = false;
+       enum lttng_error_code cmd_result = LTTNG_OK;
+       struct notification_event_tracer_event_source_element *source_element = NULL, *tmp;
+
+       cds_list_for_each_entry_safe(source_element, tmp,
+                       &state->tracer_event_sources_list, node) {
+               if (source_element->fd != tracer_event_source_fd) {
+                       continue;
+               }
+
+               DBG("[notification-thread] Removed tracer event source from poll set: tracer_event_source_fd = %d, domain = '%s'",
+                               tracer_event_source_fd,
+                               lttng_domain_type_str(source_element->domain));
+               cds_list_del(&source_element->node);
+               found = true;
+               break;
+       }
+
+       if (!found) {
+               /*
+                * This is temporarily allowed since the poll activity set is
+                * not properly cleaned-up for the moment. This is adressed in
+                * an upcoming fix.
+                */
+               source_element = NULL;
+               goto end;
+       }
+
+       if (!source_element->is_fd_in_poll_set) {
+               /* Skip the poll set removal. */
+               goto end;
+       }
+
+       DBG3("[notification-thread] Removing tracer event source from poll set: tracer_event_source_fd = %d, domain = '%s'",
+                       tracer_event_source_fd,
+                       lttng_domain_type_str(source_element->domain));
+
+       /* Removing the fd from the event poll set. */
+       ret = lttng_poll_del(&state->events, tracer_event_source_fd);
+       if (ret < 0) {
+               ERR("[notification-thread] Failed to remove tracer event source from poll set: tracer_event_source_fd = %d, domain = '%s'",
+                               tracer_event_source_fd,
+                               lttng_domain_type_str(source_element->domain));
+               cmd_result = LTTNG_ERR_FATAL;
+               goto end;
+       }
+
+       source_element->is_fd_in_poll_set = false;
+
+end:
+       free(source_element);
+       *_cmd_result = cmd_result;
+       return ret;
+}
+
+int handle_notification_thread_remove_tracer_event_source_no_result(
+               struct notification_thread_state *state,
+               int tracer_event_source_fd)
+{
+       int ret;
+       enum lttng_error_code cmd_result;
+
+       ret = handle_notification_thread_command_remove_tracer_event_source(
+                       state, tracer_event_source_fd, &cmd_result);
+       (void) cmd_result;
+       return ret;
+}
+
 static int handle_notification_thread_command_list_triggers(
                struct notification_thread_handle *handle,
                struct notification_thread_state *state,
@@ -2210,6 +2343,7 @@ int handle_notification_thread_command_register_trigger(
        struct notification_client_list *client_list = NULL;
        struct lttng_trigger_ht_element *trigger_ht_element = NULL;
        struct notification_client_list_element *client_list_element;
+       struct notification_trigger_tokens_ht_element *trigger_tokens_ht_element = NULL;
        struct cds_lfht_node *node;
        struct cds_lfht_iter iter;
        const char* trigger_name;
@@ -2288,10 +2422,47 @@ int handle_notification_thread_command_register_trigger(
                goto error_free_ht_element;
        }
 
+       if (lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_EVENT_RULE_HIT) {
+               trigger_tokens_ht_element = zmalloc(sizeof(*trigger_tokens_ht_element));
+               if (!trigger_tokens_ht_element) {
+                       /* Fatal error. */
+                       ret = -1;
+                       cds_lfht_del(state->triggers_ht,
+                                       &trigger_ht_element->node);
+                       cds_lfht_del(state->triggers_by_name_uid_ht,
+                                       &trigger_ht_element->node_by_name_uid);
+                       goto error_free_ht_element;
+               }
+
+               /* Add trigger token to the trigger_tokens_ht. */
+               cds_lfht_node_init(&trigger_tokens_ht_element->node);
+               trigger_tokens_ht_element->token =
+                               LTTNG_OPTIONAL_GET(trigger->tracer_token);
+               trigger_tokens_ht_element->trigger = trigger;
+
+               node = cds_lfht_add_unique(state->trigger_tokens_ht,
+                               hash_key_u64(&trigger_tokens_ht_element->token,
+                                               lttng_ht_seed),
+                               match_trigger_token,
+                               &trigger_tokens_ht_element->token,
+                               &trigger_tokens_ht_element->node);
+               if (node != &trigger_tokens_ht_element->node) {
+                       /* Internal corruption, fatal error. */
+                       ret = -1;
+                       *cmd_result = LTTNG_ERR_TRIGGER_EXISTS;
+                       cds_lfht_del(state->triggers_ht,
+                                       &trigger_ht_element->node);
+                       cds_lfht_del(state->triggers_by_name_uid_ht,
+                                       &trigger_ht_element->node_by_name_uid);
+                       goto error_free_ht_element;
+               }
+       }
+
        /*
         * Ownership of the trigger and of its wrapper was transfered to
-        * the triggers_ht.
+        * the triggers_ht. Same for token ht element if necessary.
         */
+       trigger_tokens_ht_element = NULL;
        trigger_ht_element = NULL;
        free_trigger = false;
 
@@ -2473,6 +2644,7 @@ error_free_ht_element:
                                free_lttng_trigger_ht_element_rcu);
        }
 
+       free(trigger_tokens_ht_element);
 error:
        if (free_trigger) {
                lttng_trigger_destroy(trigger);
@@ -2488,6 +2660,13 @@ void free_lttng_trigger_ht_element_rcu(struct rcu_head *node)
                        rcu_node));
 }
 
+static
+void free_notification_trigger_tokens_ht_element_rcu(struct rcu_head *node)
+{
+       free(caa_container_of(node, struct notification_trigger_tokens_ht_element,
+                       rcu_node));
+}
+
 static
 int handle_notification_thread_command_unregister_trigger(
                struct notification_thread_state *state,
@@ -2536,6 +2715,28 @@ int handle_notification_thread_command_unregister_trigger(
                }
        }
 
+       if (lttng_condition_get_type(condition) ==
+                       LTTNG_CONDITION_TYPE_EVENT_RULE_HIT) {
+               struct notification_trigger_tokens_ht_element
+                               *trigger_tokens_ht_element;
+
+               cds_lfht_for_each_entry (state->trigger_tokens_ht, &iter,
+                               trigger_tokens_ht_element, node) {
+                       if (!lttng_trigger_is_equal(trigger,
+                                           trigger_tokens_ht_element->trigger)) {
+                               continue;
+                       }
+
+                       DBG("[notification-thread] Removed trigger from tokens_ht");
+                       cds_lfht_del(state->trigger_tokens_ht,
+                                       &trigger_tokens_ht_element->node);
+                       call_rcu(&trigger_tokens_ht_element->rcu_node,
+                                       free_notification_trigger_tokens_ht_element_rcu);
+
+                       break;
+               }
+       }
+
        if (is_trigger_action_notify(trigger)) {
                /*
                 * Remove and release the client list from
@@ -2636,6 +2837,19 @@ int handle_notification_thread_command(
                                cmd->parameters.session_rotation.location,
                                &cmd->reply_code);
                break;
+       case NOTIFICATION_COMMAND_TYPE_ADD_TRACER_EVENT_SOURCE:
+               ret = handle_notification_thread_command_add_tracer_event_source(
+                               state,
+                               cmd->parameters.tracer_event_source.tracer_event_source_fd,
+                               cmd->parameters.tracer_event_source.domain,
+                               &cmd->reply_code);
+               break;
+       case NOTIFICATION_COMMAND_TYPE_REMOVE_TRACER_EVENT_SOURCE:
+               ret = handle_notification_thread_command_remove_tracer_event_source(
+                               state,
+                               cmd->parameters.tracer_event_source.tracer_event_source_fd,
+                               &cmd->reply_code);
+               break;
        case NOTIFICATION_COMMAND_TYPE_LIST_TRIGGERS:
        {
                struct lttng_triggers *triggers = NULL;
This page took 0.047962 seconds and 4 git commands to generate.