X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fnotification-thread-events.c;h=6f0ee7d7942cf762b38c6c7edc37ab97caa8972b;hp=038716cf567c03e7b03cd8f9ae0d292f7696a7c4;hb=f37d0f861f20a72a0b77fb43fa27744521dd7995;hpb=af0c318df128a05e708f704ec21c5d3cf8e314fa diff --git a/src/bin/lttng-sessiond/notification-thread-events.c b/src/bin/lttng-sessiond/notification-thread-events.c index 038716cf5..6f0ee7d79 100644 --- a/src/bin/lttng-sessiond/notification-thread-events.c +++ b/src/bin/lttng-sessiond/notification-thread-events.c @@ -1,18 +1,8 @@ /* - * Copyright (C) 2017 - Jérémie Galarneau + * Copyright (C) 2017 Jérémie Galarneau * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License, version 2 only, as - * published by the Free Software Foundation. + * SPDX-License-Identifier: GPL-2.0-only * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 51 - * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define _LGPL_SOURCE @@ -501,7 +491,7 @@ enum lttng_object_type get_condition_binding_object( case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW: case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH: case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE: - return LTTNG_OBJECT_TYPE_CHANNEL; + return LTTNG_OBJECT_TYPE_CHANNEL; case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING: case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED: return LTTNG_OBJECT_TYPE_SESSION; @@ -692,7 +682,7 @@ struct notification_client_list *get_client_list_from_condition( &iter); node = cds_lfht_iter_get_node(&iter); - return node ? caa_container_of(node, + return node ? caa_container_of(node, struct notification_client_list, notification_trigger_ht_node) : NULL; } @@ -1316,7 +1306,7 @@ struct lttng_session_trigger_list *get_session_trigger_list( goto end; } - list = caa_container_of(node, + list = caa_container_of(node, struct lttng_session_trigger_list, session_triggers_ht_node); end: @@ -2156,10 +2146,6 @@ error_free_ht_element: free(trigger_ht_element); error: if (free_trigger) { - struct lttng_action *action = lttng_trigger_get_action(trigger); - - lttng_condition_destroy(condition); - lttng_action_destroy(action); lttng_trigger_destroy(trigger); } rcu_read_unlock(); @@ -2194,7 +2180,6 @@ int handle_notification_thread_command_unregister_trigger( struct lttng_trigger_ht_element *trigger_ht_element = NULL; struct lttng_condition *condition = lttng_trigger_get_condition( trigger); - struct lttng_action *action; enum lttng_error_code cmd_reply; rcu_read_lock(); @@ -2256,10 +2241,7 @@ int handle_notification_thread_command_unregister_trigger( struct lttng_trigger_ht_element, node); cds_lfht_del(state->triggers_ht, triggers_ht_node); - condition = lttng_trigger_get_condition(trigger_ht_element->trigger); - lttng_condition_destroy(condition); - action = lttng_trigger_get_action(trigger_ht_element->trigger); - lttng_action_destroy(action); + /* Release the ownership of the trigger. */ lttng_trigger_destroy(trigger_ht_element->trigger); call_rcu(&trigger_ht_element->rcu_node, free_lttng_trigger_ht_element_rcu); end: @@ -2436,7 +2418,7 @@ int handle_notification_thread_client_connect( ret = client_reset_inbound_state(client); if (ret) { ERR("[notification-thread] Failed to reset client communication's inbound state"); - ret = 0; + ret = 0; goto error; } @@ -2508,7 +2490,7 @@ int handle_notification_thread_client_disconnect( if (ret) { ERR("[notification-thread] Failed to remove client socket from poll set"); } - cds_lfht_del(state->client_socket_ht, + cds_lfht_del(state->client_socket_ht, &client->client_socket_ht_node); notification_client_destroy(client, state); end: @@ -2574,8 +2556,7 @@ int client_flush_outgoing_queue(struct notification_client *client, ret = lttcomm_send_unix_sock_non_block(client->socket, client->communication.outbound.buffer.data, to_send_count); - if ((ret < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) || - (ret > 0 && ret < to_send_count)) { + if ((ret >= 0 && ret < to_send_count)) { DBG("[notification-thread] Client (socket fd = %i) outgoing queue could not be completely flushed", client->socket); to_send_count -= max(ret, 0); @@ -2811,14 +2792,14 @@ int client_dispatch_message(struct notification_client *client, struct lttng_condition *condition; enum lttng_notification_channel_status status = LTTNG_NOTIFICATION_CHANNEL_STATUS_OK; - const struct lttng_buffer_view condition_view = - lttng_buffer_view_from_dynamic_buffer( + struct lttng_payload_view condition_view = + lttng_payload_view_from_dynamic_buffer( &client->communication.inbound.buffer, 0, -1); size_t expected_condition_size = client->communication.inbound.buffer.size; - ret = lttng_condition_create_from_buffer(&condition_view, + ret = lttng_condition_create_from_payload(&condition_view, &condition); if (ret != expected_condition_size) { ERR("[notification-thread] Malformed condition received from client"); @@ -2959,7 +2940,7 @@ bool evaluate_buffer_usage_condition(const struct lttng_condition *condition, * forego this double-multiplication or it could be performed * as fixed-point math. * - * Note that caching should accomodate the case where the + * Note that caching should accommodates the case where the * condition applies to multiple channels (i.e. don't assume * that all channels matching my_chann* have the same size...) */ @@ -3099,8 +3080,7 @@ end: } static -int client_enqueue_dropped_notification(struct notification_client *client, - struct notification_thread_state *state) +int client_enqueue_dropped_notification(struct notification_client *client) { int ret; struct lttng_notification_channel_message msg = { @@ -3114,15 +3094,48 @@ int client_enqueue_dropped_notification(struct notification_client *client, return ret; } +/* + * Permission checks relative to notification channel clients are performed + * here. Notice how object, client, and trigger credentials are involved in + * this check. + * + * The `object` credentials are the credentials associated with the "subject" + * of a condition. For instance, a `rotation completed` condition applies + * to a session. When that condition is met, it will produce an evaluation + * against a session. Hence, in this case, the `object` credentials are the + * credentials of the "subject" session. + * + * The `trigger` credentials are the credentials of the user that registered the + * trigger. + * + * The `client` credentials are the credentials of the user that created a given + * notification channel. + * + * In terms of visibility, it is expected that non-privilieged users can only + * register triggers against "their" objects (their own sessions and + * applications they are allowed to interact with). They can then open a + * notification channel and subscribe to notifications associated with those + * triggers. + * + * As for privilieged users, they can register triggers against the objects of + * other users. They can then subscribe to the notifications associated to their + * triggers. Privilieged users _can't_ subscribe to the notifications of + * triggers owned by other users; they must create their own triggers. + * + * This is more a concern of usability than security. It would be difficult for + * a root user reliably subscribe to a specific set of conditions without + * interference from external users (those could, for instance, unregister + * their triggers). + */ static int send_evaluation_to_clients(const struct lttng_trigger *trigger, const struct lttng_evaluation *evaluation, struct notification_client_list* client_list, struct notification_thread_state *state, - uid_t channel_uid, gid_t channel_gid) + uid_t object_uid, gid_t object_gid) { int ret = 0; - struct lttng_dynamic_buffer msg_buffer; + struct lttng_payload msg_payload; struct notification_client_list_element *client_list_element, *tmp; const struct lttng_notification notification = { .condition = (struct lttng_condition *) lttng_trigger_get_const_condition(trigger), @@ -3131,16 +3144,17 @@ int send_evaluation_to_clients(const struct lttng_trigger *trigger, struct lttng_notification_channel_message msg_header = { .type = (int8_t) LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_NOTIFICATION, }; + const struct lttng_credentials *trigger_creds = lttng_trigger_get_credentials(trigger); - lttng_dynamic_buffer_init(&msg_buffer); + lttng_payload_init(&msg_payload); - ret = lttng_dynamic_buffer_append(&msg_buffer, &msg_header, + ret = lttng_dynamic_buffer_append(&msg_payload.buffer, &msg_header, sizeof(msg_header)); if (ret) { goto end; } - ret = lttng_notification_serialize(¬ification, &msg_buffer); + ret = lttng_notification_serialize(¬ification, &msg_payload); if (ret) { ERR("[notification-thread] Failed to serialize notification"); ret = -1; @@ -3148,23 +3162,28 @@ int send_evaluation_to_clients(const struct lttng_trigger *trigger, } /* Update payload size. */ - ((struct lttng_notification_channel_message * ) msg_buffer.data)->size = - (uint32_t) (msg_buffer.size - sizeof(msg_header)); + ((struct lttng_notification_channel_message * ) msg_payload.buffer.data)->size = + (uint32_t) (msg_payload.buffer.size - sizeof(msg_header)); cds_list_for_each_entry_safe(client_list_element, tmp, &client_list->list, node) { struct notification_client *client = client_list_element->client; - if (client->uid != channel_uid && client->gid != channel_gid && + if (client->uid != object_uid && client->gid != object_gid && client->uid != 0) { /* Client is not allowed to monitor this channel. */ - DBG("[notification-thread] Skipping client at it does not have the permission to receive notification for this channel"); + DBG("[notification-thread] Skipping client at it does not have the object permission to receive notification for this trigger"); + continue; + } + + if (client->uid != trigger_creds->uid && client->gid != trigger_creds->gid) { + DBG("[notification-thread] Skipping client at it does not have the permission to receive notification for this trigger"); continue; } DBG("[notification-thread] Sending notification to client (fd = %i, %zu bytes)", - client->socket, msg_buffer.size); + client->socket, msg_payload.buffer.size); if (client->communication.outbound.buffer.size) { /* * Outgoing data is already buffered for this client; @@ -3178,7 +3197,7 @@ int send_evaluation_to_clients(const struct lttng_trigger *trigger, if (!client->communication.outbound.dropped_notification) { client->communication.outbound.dropped_notification = true; ret = client_enqueue_dropped_notification( - client, state); + client); if (ret) { goto end; } @@ -3188,7 +3207,7 @@ int send_evaluation_to_clients(const struct lttng_trigger *trigger, ret = lttng_dynamic_buffer_append_buffer( &client->communication.outbound.buffer, - &msg_buffer); + &msg_payload.buffer); if (ret) { goto end; } @@ -3200,7 +3219,7 @@ int send_evaluation_to_clients(const struct lttng_trigger *trigger, } ret = 0; end: - lttng_dynamic_buffer_reset(&msg_buffer); + lttng_payload_reset(&msg_payload); return ret; } @@ -3339,7 +3358,7 @@ int handle_notification_thread_channel_sample( trigger_list = caa_container_of(node, struct lttng_channel_trigger_list, channel_triggers_ht_node); cds_list_for_each_entry(trigger_list_element, &trigger_list->list, - node) { + node) { const struct lttng_condition *condition; const struct lttng_action *action; const struct lttng_trigger *trigger;