diff options
Diffstat (limited to 'bus/connection.c')
-rw-r--r-- | bus/connection.c | 155 |
1 files changed, 125 insertions, 30 deletions
diff --git a/bus/connection.c b/bus/connection.c index fddbc78a..519122c5 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -33,6 +33,7 @@ #include <dbus/dbus-list.h> #include <dbus/dbus-hash.h> #include <dbus/dbus-timeout.h> +#include <dbus/dbus-connection-internal.h> /* Trim executed commands to this length; we want to keep logs readable */ #define MAX_LOG_COMMAND_LEN 50 @@ -102,6 +103,8 @@ typedef struct int peak_match_rules; int peak_bus_names; #endif + int n_pending_unix_fds; + DBusTimeout *pending_unix_fds_timeout; } BusConnectionData; static dbus_bool_t bus_pending_reply_expired (BusExpireList *list, @@ -268,6 +271,15 @@ bus_connection_disconnected (DBusConnection *connection) dbus_connection_set_dispatch_status_function (connection, NULL, NULL, NULL); + + if (d->pending_unix_fds_timeout) + { + _dbus_loop_remove_timeout (bus_context_get_loop (d->connections->context), + d->pending_unix_fds_timeout); + _dbus_timeout_unref (d->pending_unix_fds_timeout); + } + d->pending_unix_fds_timeout = NULL; + _dbus_connection_set_pending_fds_function (connection, NULL, NULL); bus_connection_remove_transactions (connection); @@ -293,6 +305,10 @@ bus_connection_disconnected (DBusConnection *connection) _dbus_list_remove_link (&d->connections->incomplete, d->link_in_connection_list); d->link_in_connection_list = NULL; d->connections->n_incomplete -= 1; + + /* If we have dropped below the max. number of incomplete + * connections, start accept()ing again */ + bus_context_check_all_watches (d->connections->context); } _dbus_assert (d->connections->n_incomplete >= 0); @@ -588,6 +604,42 @@ oom: return FALSE; } +static void +check_pending_fds_cb (DBusConnection *connection) +{ + BusConnectionData *d = BUS_CONNECTION_DATA (connection); + int n_pending_unix_fds_old = d->n_pending_unix_fds; + int n_pending_unix_fds_new; + + n_pending_unix_fds_new = _dbus_connection_get_pending_fds_count (connection); + + _dbus_verbose ("Pending fds count changed on connection %p: %d -> %d\n", + connection, n_pending_unix_fds_old, n_pending_unix_fds_new); + + if (n_pending_unix_fds_old == 0 && n_pending_unix_fds_new > 0) + { + _dbus_timeout_set_interval (d->pending_unix_fds_timeout, + bus_context_get_pending_fd_timeout (d->connections->context)); + _dbus_timeout_set_enabled (d->pending_unix_fds_timeout, TRUE); + } + + if (n_pending_unix_fds_old > 0 && n_pending_unix_fds_new == 0) + { + _dbus_timeout_set_enabled (d->pending_unix_fds_timeout, FALSE); + } + + + d->n_pending_unix_fds = n_pending_unix_fds_new; +} + +static dbus_bool_t +pending_unix_fds_timeout_cb (void *data) +{ + DBusConnection *connection = data; + dbus_connection_close (connection); + return TRUE; +} + dbus_bool_t bus_connections_setup_connection (BusConnections *connections, DBusConnection *connection) @@ -683,36 +735,38 @@ bus_connections_setup_connection (BusConnections *connections, } } + /* Setup pending fds timeout (see #80559) */ + d->pending_unix_fds_timeout = _dbus_timeout_new (100, /* irrelevant */ + pending_unix_fds_timeout_cb, + connection, NULL); + if (d->pending_unix_fds_timeout == NULL) + goto out; + + _dbus_timeout_set_enabled (d->pending_unix_fds_timeout, FALSE); + if (!_dbus_loop_add_timeout (bus_context_get_loop (connections->context), + d->pending_unix_fds_timeout)) + goto out; + + _dbus_connection_set_pending_fds_function (connection, + (DBusPendingFdsChangeFunction) check_pending_fds_cb, + connection); + _dbus_list_append_link (&connections->incomplete, d->link_in_connection_list); connections->n_incomplete += 1; dbus_connection_ref (connection); - /* Note that we might disconnect ourselves here, but it only takes - * effect on return to the main loop. We call this to free up - * expired connections if possible, and to queue the timeout for our - * own expiration. - */ bus_connections_expire_incomplete (connections); - /* And we might also disconnect ourselves here, but again it - * only takes effect on return to main loop. - */ - if (connections->n_incomplete > - bus_context_get_max_incomplete_connections (connections->context)) - { - _dbus_verbose ("Number of incomplete connections exceeds max, dropping oldest one\n"); - - _dbus_assert (connections->incomplete != NULL); - /* Disconnect the oldest unauthenticated connection. FIXME - * would it be more secure to drop a *random* connection? This - * algorithm seems to mean that if someone can create new - * connections quickly enough, they can keep anyone else from - * completing authentication. But random may or may not really - * help with that, a more elaborate solution might be required. - */ - dbus_connection_close (connections->incomplete->data); - } + /* The listening socket is removed from the main loop, + * i.e. does not accept(), while n_incomplete is at its + * maximum value; so we shouldn't get here in that case */ + _dbus_assert (connections->n_incomplete <= + bus_context_get_max_incomplete_connections (connections->context)); + + /* If we have the maximum number of incomplete connections, + * stop accept()ing any more, to avert a DoS. See fd.o #80919 */ + bus_context_check_all_watches (d->connections->context); retval = TRUE; @@ -744,6 +798,13 @@ bus_connections_setup_connection (BusConnections *connections, dbus_connection_set_dispatch_status_function (connection, NULL, NULL, NULL); + if (d->pending_unix_fds_timeout) + _dbus_timeout_unref (d->pending_unix_fds_timeout); + + d->pending_unix_fds_timeout = NULL; + + _dbus_connection_set_pending_fds_function (connection, NULL, NULL); + if (d->link_in_connection_list != NULL) { _dbus_assert (d->link_in_connection_list->next == NULL); @@ -1419,6 +1480,10 @@ bus_connection_complete (DBusConnection *connection, _dbus_assert (d->connections->n_incomplete >= 0); _dbus_assert (d->connections->n_completed > 0); + /* If we have dropped below the max. number of incomplete + * connections, start accept()ing again */ + bus_context_check_all_watches (d->connections->context); + /* See if we can remove the timeout */ bus_connections_expire_incomplete (d->connections); @@ -1435,6 +1500,42 @@ fail: return FALSE; } +dbus_bool_t +bus_connections_reload_policy (BusConnections *connections, + DBusError *error) +{ + BusConnectionData *d; + DBusConnection *connection; + DBusList *link; + + _dbus_assert (connections != NULL); + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + for (link = _dbus_list_get_first_link (&(connections->completed)); + link; + link = _dbus_list_get_next_link (&(connections->completed), link)) + { + connection = link->data; + d = BUS_CONNECTION_DATA (connection); + _dbus_assert (d != NULL); + _dbus_assert (d->policy != NULL); + + bus_client_policy_unref (d->policy); + d->policy = bus_context_create_client_policy (connections->context, + connection, + error); + if (d->policy == NULL) + { + _dbus_verbose ("Failed to create security policy for connection %p\n", + connection); + _DBUS_ASSERT_ERROR_IS_SET (error); + return FALSE; + } + } + + return TRUE; +} + const char * bus_connection_get_name (DBusConnection *connection) { @@ -1990,12 +2091,6 @@ bus_transaction_get_context (BusTransaction *transaction) return transaction->context; } -BusConnections* -bus_transaction_get_connections (BusTransaction *transaction) -{ - return bus_context_get_connections (transaction->context); -} - dbus_bool_t bus_transaction_send_from_driver (BusTransaction *transaction, DBusConnection *connection, @@ -2318,7 +2413,6 @@ bus_transaction_add_cancel_hook (BusTransaction *transaction, return TRUE; } -#ifdef DBUS_ENABLE_STATS int bus_connections_get_n_active (BusConnections *connections) { @@ -2331,6 +2425,7 @@ bus_connections_get_n_incomplete (BusConnections *connections) return connections->n_incomplete; } +#ifdef DBUS_ENABLE_STATS int bus_connections_get_total_match_rules (BusConnections *connections) { |