summaryrefslogtreecommitdiff
path: root/bus/connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'bus/connection.c')
-rw-r--r--bus/connection.c155
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)
{