Commit 1909a82a authored by Simon McVittie's avatar Simon McVittie

Merge branch 'dbus-1.8'

Conflicts:
	NEWS
	configure.ac
parents eca7a1c5 8874d3a0
......@@ -51,6 +51,57 @@ Fixes:
(like Mac OS X 10.6), or available in libc but unsupported by the kernel
(fd.o #77032; rmvsxop, OBATA Akio, Patrick Welche)
• Fix include path for test/internal/*.c with cmake (Ralf Habacker)
• Change DBUS_TYPE_G_BYTE_ARRAY reference in dbus-tutorial.xml
to the correct DBUS_TYPE_G_UCHAR_ARRAY (fd.o #80795, Thomas Haller)
• in dbus-monitor, do not leak file descriptors that we have monitored
(fd.o #80603, Alban Crequy)
D-Bus 1.8.8 (2014-09-16)
==
The "smashy smashy egg man" release.
Security fixes:
• Do not accept an extra fd in the padding of a cmsg message, which
could lead to a 4-byte heap buffer overrun.
(CVE-2014-3635, fd.o #83622; Simon McVittie)
• Reduce default for maximum Unix file descriptors passed per message
from 1024 to 16, preventing a uid with the default maximum number of
connections from exhausting the system bus' file descriptors under
Linux's default rlimit. Distributors or system administrators with a
more restrictive fd limit may wish to reduce these limits further.
Additionally, on Linux this prevents a second denial of service
in which the dbus-daemon can be made to exceed the maximum number
of fds per sendmsg() and disconnect the process that would have
received them.
(CVE-2014-3636, fd.o #82820; Alban Crequy)
• Disconnect connections that still have a fd pending unmarshalling after
a new configurable limit, pending_fd_timeout (defaulting to 150 seconds),
removing the possibility of creating an abusive connection that cannot be
disconnected by setting up a circular reference to a connection's
file descriptor.
(CVE-2014-3637, fd.o #80559; Alban Crequy)
• Reduce default for maximum pending replies per connection from 8192 to 128,
mitigating an algorithmic complexity denial-of-service attack
(CVE-2014-3638, fd.o #81053; Alban Crequy)
• Reduce default for authentication timeout on the system bus from
30 seconds to 5 seconds, avoiding denial of service by using up
all unauthenticated connection slots; and when all unauthenticated
connection slots are used up, make new connection attempts block
instead of disconnecting them.
(CVE-2014-3639, fd.o #80919; Alban Crequy)
Other fixes:
• Check for libsystemd from systemd >= 209, falling back to
the older separate libraries if not found (Umut Tezduyar Lindskog,
Simon McVittie)
......@@ -62,17 +113,9 @@ Fixes:
• Fix compilation with --enable-stats (fd.o #81043, Gentoo #507232;
Alban Crequy)
• Fix include path for test/internal/*.c with cmake (Ralf Habacker)
• Change DBUS_TYPE_G_BYTE_ARRAY reference in dbus-tutorial.xml
to the correct DBUS_TYPE_G_UCHAR_ARRAY (fd.o #80795, Thomas Haller)
• Improve documentation for running tests on Windows (fd.o #41252,
Ralf Habacker)
• in dbus-monitor, do not leak file descriptors that we have monitored
(fd.o #80603, Alban Crequy)
D-Bus 1.8.6 (2014-06-02)
==
......
......@@ -39,6 +39,7 @@
#include <dbus/dbus-hash.h>
#include <dbus/dbus-credentials.h>
#include <dbus/dbus-internals.h>
#include <dbus/dbus-server-protected.h>
#ifdef DBUS_CYGWIN
#include <signal.h>
......@@ -68,6 +69,7 @@ struct BusContext
unsigned int keep_umask : 1;
unsigned int allow_anonymous : 1;
unsigned int systemd_activation : 1;
dbus_bool_t watches_enabled;
};
static dbus_int32_t server_data_slot = -1;
......@@ -758,6 +760,8 @@ bus_context_new (const DBusString *config_file,
goto failed;
}
context->watches_enabled = TRUE;
context->registry = bus_registry_new (context);
if (context->registry == NULL)
{
......@@ -1236,6 +1240,12 @@ bus_context_get_auth_timeout (BusContext *context)
return context->limits.auth_timeout;
}
int
bus_context_get_pending_fd_timeout (BusContext *context)
{
return context->limits.pending_fd_timeout;
}
int
bus_context_get_max_completed_connections (BusContext *context)
{
......@@ -1658,3 +1668,36 @@ bus_context_check_security_policy (BusContext *context,
_dbus_verbose ("security policy allowing message\n");
return TRUE;
}
void
bus_context_check_all_watches (BusContext *context)
{
DBusList *link;
dbus_bool_t enabled = TRUE;
if (bus_connections_get_n_incomplete (context->connections) >=
bus_context_get_max_incomplete_connections (context))
{
enabled = FALSE;
}
if (context->watches_enabled == enabled)
return;
context->watches_enabled = enabled;
for (link = _dbus_list_get_first_link (&context->servers);
link != NULL;
link = _dbus_list_get_next_link (&context->servers, link))
{
/* A BusContext might contains several DBusServer (if there are
* several <listen> configuration items) and a DBusServer might
* contain several DBusWatch in its DBusWatchList (if getaddrinfo
* returns several addresses on a dual IPv4-IPv6 stack or if
* systemd passes several fds).
* We want to enable/disable them all.
*/
DBusServer *server = link->data;
_dbus_server_toggle_all_watches (server, enabled);
}
}
......@@ -54,6 +54,7 @@ typedef struct
long max_message_unix_fds; /**< Max number of unix fds of a single message*/
int activation_timeout; /**< How long to wait for an activation to time out */
int auth_timeout; /**< How long to wait for an authentication to time out */
int pending_fd_timeout; /**< How long to wait for a D-Bus message with a fd to time out */
int max_completed_connections; /**< Max number of authorized connections */
int max_incomplete_connections; /**< Max number of incomplete connections */
int max_connections_per_user; /**< Max number of connections auth'd as same user */
......@@ -106,6 +107,7 @@ BusClientPolicy* bus_context_create_client_policy (BusContext
DBusError *error);
int bus_context_get_activation_timeout (BusContext *context);
int bus_context_get_auth_timeout (BusContext *context);
int bus_context_get_pending_fd_timeout (BusContext *context);
int bus_context_get_max_completed_connections (BusContext *context);
int bus_context_get_max_incomplete_connections (BusContext *context);
int bus_context_get_max_connections_per_user (BusContext *context);
......@@ -125,5 +127,6 @@ dbus_bool_t bus_context_check_security_policy (BusContext
DBusConnection *proposed_recipient,
DBusMessage *message,
DBusError *error);
void bus_context_check_all_watches (BusContext *context);
#endif /* BUS_BUS_H */
......@@ -438,7 +438,12 @@ bus_config_parser_new (const DBusString *basedir,
* and legitimate auth will fail. If interactive auth (ask user for
* password) is allowed, then potentially it has to be quite long.
*/
parser->limits.auth_timeout = 30000; /* 30 seconds */
parser->limits.auth_timeout = 5000; /* 5 seconds */
/* Do not allow a fd to stay forever in dbus-daemon
* https://bugs.freedesktop.org/show_bug.cgi?id=80559
*/
parser->limits.pending_fd_timeout = 150000; /* 2.5 minutes */
parser->limits.max_incomplete_connections = 64;
parser->limits.max_connections_per_user = 256;
......@@ -467,7 +472,7 @@ bus_config_parser_new (const DBusString *basedir,
/* this is effectively a limit on message queue size for messages
* that require a reply
*/
parser->limits.max_replies_per_connection = 1024*8;
parser->limits.max_replies_per_connection = 128;
}
parser->refcount = 1;
......@@ -1902,6 +1907,12 @@ set_limit (BusConfigParser *parser,
must_be_int = TRUE;
parser->limits.auth_timeout = value;
}
else if (strcmp (name, "pending_fd_timeout") == 0)
{
must_be_positive = TRUE;
must_be_int = TRUE;
parser->limits.pending_fd_timeout = value;
}
else if (strcmp (name, "reply_timeout") == 0)
{
must_be_positive = TRUE;
......@@ -3108,6 +3119,7 @@ limits_equal (const BusLimits *a,
|| a->max_message_unix_fds == b->max_message_unix_fds
|| a->activation_timeout == b->activation_timeout
|| a->auth_timeout == b->auth_timeout
|| a->pending_fd_timeout == b->pending_fd_timeout
|| a->max_completed_connections == b->max_completed_connections
|| a->max_incomplete_connections == b->max_incomplete_connections
|| a->max_connections_per_user == b->max_connections_per_user
......
......@@ -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);
......@@ -2348,7 +2413,6 @@ bus_transaction_add_cancel_hook (BusTransaction *transaction,
return TRUE;
}
#ifdef DBUS_ENABLE_STATS
int
bus_connections_get_n_active (BusConnections *connections)
{
......@@ -2361,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)
{
......
......@@ -139,9 +139,10 @@ dbus_bool_t bus_transaction_add_cancel_hook (BusTransaction *
void *data,
DBusFreeFunction free_data_function);
/* called by stats.c, only present if DBUS_ENABLE_STATS */
int bus_connections_get_n_active (BusConnections *connections);
int bus_connections_get_n_incomplete (BusConnections *connections);
/* called by stats.c, only present if DBUS_ENABLE_STATS */
int bus_connections_get_total_match_rules (BusConnections *connections);
int bus_connections_get_peak_match_rules (BusConnections *connections);
int bus_connections_get_peak_match_rules_per_conn (BusConnections *connections);
......
......@@ -49,9 +49,11 @@
<limit name="max_outgoing_bytes">1000000000</limit>
<limit name="max_outgoing_unix_fds">250000000</limit>
<limit name="max_message_size">1000000000</limit>
<limit name="max_message_unix_fds">@DEFAULT_MESSAGE_UNIX_FDS@</limit>
<!-- We do not override max_message_unix_fds here since the in-kernel
limit is also relatively low -->
<limit name="service_start_timeout">120000</limit>
<limit name="auth_timeout">240000</limit>
<limit name="pending_fd_timeout">150000</limit>
<limit name="max_completed_connections">100000</limit>
<limit name="max_incomplete_connections">10000</limit>
<limit name="max_connections_per_user">100000</limit>
......
......@@ -411,10 +411,6 @@ endif (WIN32)
set (DBUS_USER )
# In Autotools this has a different default on QNX, but there seems little
# point in replicating that here; if you're on an unusual Unix, use Autotools.
set (DEFAULT_MESSAGE_UNIX_FDS 1024)
# This won't work on Windows. It's not meant to - the system bus is
# meaningless on Windows anyway.
#
......
......@@ -82,8 +82,6 @@
# define DBUS_ENABLE_X11_AUTOLAUNCH 1
#endif
#define DBUS_DEFAULT_MESSAGE_UNIX_FDS @DEFAULT_MESSAGE_UNIX_FDS@
#define _DBUS_VA_COPY_ASSIGN(a1,a2) { a1 = a2; }
#cmakedefine DBUS_VA_COPY_FUNC
......
......@@ -37,7 +37,7 @@ LT_CURRENT=11
## increment any time the source changes; set to
## 0 if you increment CURRENT
LT_REVISION=6
LT_REVISION=7
## increment if any interfaces have been added; set to 0
## if any interfaces have been changed or removed. removal has
......@@ -1245,17 +1245,6 @@ if test x$with_valgrind != xno; then
AC_DEFINE([WITH_VALGRIND], [1], [Define to add Valgrind instrumentation])
fi
# Determine maximum number of Unix fds which may be passed
AS_CASE([$host_os],
[*qnx*],
[DEFAULT_MESSAGE_UNIX_FDS=256],
[*],
[DEFAULT_MESSAGE_UNIX_FDS=1024])
AC_DEFINE_UNQUOTED([DBUS_DEFAULT_MESSAGE_UNIX_FDS],
[$DEFAULT_MESSAGE_UNIX_FDS],
[Default for dbus_connection_get_max_message_unix_fds()])
AC_SUBST([DEFAULT_MESSAGE_UNIX_FDS])
#### Set up final flags
LIBDBUS_LIBS="$THREAD_LIBS $NETWORK_libs $SYSTEMD_LIBS"
AC_SUBST([LIBDBUS_LIBS])
......
......@@ -44,6 +44,8 @@ typedef enum
/** default timeout value when waiting for a message reply, 25 seconds */
#define _DBUS_DEFAULT_TIMEOUT_VALUE (25 * 1000)
typedef void (* DBusPendingFdsChangeFunction) (void *data);
void _dbus_connection_lock (DBusConnection *connection);
void _dbus_connection_unlock (DBusConnection *connection);
DBusConnection * _dbus_connection_ref_unlocked (DBusConnection *connection);
......@@ -100,6 +102,10 @@ void _dbus_connection_test_get_locks (DBusConnectio
DBusMutex **io_path_mutex_loc,
DBusCondVar **dispatch_cond_loc,
DBusCondVar **io_path_cond_loc);
int _dbus_connection_get_pending_fds_count (DBusConnection *connection);
void _dbus_connection_set_pending_fds_function (DBusConnection *connection,
DBusPendingFdsChangeFunction callback,
void *data);
/* if DBUS_ENABLE_STATS */
void _dbus_connection_get_stats (DBusConnection *connection,
......
......@@ -2549,6 +2549,33 @@ _dbus_connection_block_pending_call (DBusPendingCall *pending)
dbus_pending_call_unref (pending);
}
/**
* Return how many file descriptors are pending in the loader
*
* @param connection the connection
*/
int
_dbus_connection_get_pending_fds_count (DBusConnection *connection)
{
return _dbus_transport_get_pending_fds_count (connection->transport);
}
/**
* Register a function to be called whenever the number of pending file
* descriptors in the loader change.
*
* @param connection the connection
* @param callback the callback
*/
void
_dbus_connection_set_pending_fds_function (DBusConnection *connection,
DBusPendingFdsChangeFunction callback,
void *data)
{
_dbus_transport_set_pending_fds_function (connection->transport,
callback, data);
}
/** @} */
/**
......
......@@ -96,6 +96,10 @@ long _dbus_message_loader_get_max_message_size (DBusMessageLoader
void _dbus_message_loader_set_max_message_unix_fds(DBusMessageLoader *loader,
long n);
long _dbus_message_loader_get_max_message_unix_fds(DBusMessageLoader *loader);
int _dbus_message_loader_get_pending_fds_count (DBusMessageLoader *loader);
void _dbus_message_loader_set_pending_fds_function (DBusMessageLoader *loader,
void (* callback) (void *),
void *data);
typedef struct DBusInitialFDs DBusInitialFDs;
DBusInitialFDs *_dbus_check_fdleaks_enter (void);
......
......@@ -80,6 +80,8 @@ struct DBusMessageLoader
int *unix_fds; /**< File descriptors that have been read from the transport but not yet been handed to any message. Array will be allocated at first use. */
unsigned n_unix_fds_allocated; /**< Number of file descriptors this array has space for */
unsigned n_unix_fds; /**< Number of valid file descriptors in array */
void (* unix_fds_change) (void *); /**< Notify when the pending fds change */
void *unix_fds_change_data;
#endif
};
......
......@@ -35,6 +35,7 @@
#include "dbus-list.h"
#include "dbus-threads-internal.h"
#ifdef HAVE_UNIX_FD_PASSING
#include "dbus-sysdeps.h"
#include "dbus-sysdeps-unix.h"
#endif
......@@ -4058,6 +4059,9 @@ _dbus_message_loader_return_unix_fds(DBusMessageLoader *loader,
loader->n_unix_fds += n_fds;
loader->unix_fds_outstanding = FALSE;
if (n_fds && loader->unix_fds_change)
loader->unix_fds_change (loader->unix_fds_change_data);
#else
_dbus_assert_not_reached("Platform doesn't support unix fd passing");
#endif
......@@ -4205,6 +4209,9 @@ load_message (DBusMessageLoader *loader,
message->n_unix_fds_allocated = message->n_unix_fds = n_unix_fds;
loader->n_unix_fds -= n_unix_fds;
memmove (loader->unix_fds, loader->unix_fds + n_unix_fds, loader->n_unix_fds * sizeof (loader->unix_fds[0]));
if (loader->unix_fds_change)
loader->unix_fds_change (loader->unix_fds_change_data);
}
else
message->unix_fds = NULL;
......@@ -4498,6 +4505,40 @@ _dbus_message_loader_get_max_message_unix_fds (DBusMessageLoader *loader)
return loader->max_message_unix_fds;
}
/**
* Return how many file descriptors are pending in the loader
*
* @param loader the loader
*/
int
_dbus_message_loader_get_pending_fds_count (DBusMessageLoader *loader)
{
#ifdef HAVE_UNIX_FD_PASSING
return loader->n_unix_fds;
#else
return 0;
#endif
}
/**
* Register a function to be called whenever the number of pending file
* descriptors in the loader change.
*
* @param loader the loader
* @param callback the callback
* @param data the data for the callback
*/
void
_dbus_message_loader_set_pending_fds_function (DBusMessageLoader *loader,
void (* callback) (void *),
void *data)
{
#ifdef HAVE_UNIX_FD_PASSING
loader->unix_fds_change = callback;
loader->unix_fds_change_data = data;
#endif
}
static DBusDataSlotAllocator slot_allocator =
_DBUS_DATA_SLOT_ALLOCATOR_INIT (_DBUS_LOCK_NAME (message_slots));
......
......@@ -99,9 +99,8 @@ dbus_bool_t _dbus_server_add_watch (DBusServer *server,
DBusWatch *watch);
void _dbus_server_remove_watch (DBusServer *server,
DBusWatch *watch);
void _dbus_server_toggle_watch (DBusServer *server,
DBusWatch *watch,
dbus_bool_t enabled);
void _dbus_server_toggle_all_watches (DBusServer *server,
dbus_bool_t enabled);
dbus_bool_t _dbus_server_add_timeout (DBusServer *server,
DBusTimeout *timeout);
void _dbus_server_remove_timeout (DBusServer *server,
......
......@@ -312,26 +312,17 @@ _dbus_server_remove_watch (DBusServer *server,
}
/**
* Toggles a watch and notifies app via server's
* DBusWatchToggledFunction if available. It's an error to call this
* function on a watch that was not previously added.
* Toggles all watch and notifies app via server's
* DBusWatchToggledFunction if available.
*
* @param server the server.
* @param watch the watch to toggle.
* @param enabled whether to enable or disable
*/
void
_dbus_server_toggle_watch (DBusServer *server,
DBusWatch *watch,
dbus_bool_t enabled)
_dbus_server_toggle_all_watches (DBusServer *server,
dbus_bool_t enabled)
{
_dbus_assert (watch != NULL);
HAVE_LOCK_CHECK (server);
protected_change_watch (server, watch,
NULL, NULL,
_dbus_watch_list_toggle_watch,
enabled);
_dbus_watch_list_toggle_all_watches (server->watches, enabled);
}
/** Function to be called in protected_change_timeout() with refcount held */
......
......@@ -323,6 +323,12 @@ _dbus_read_socket_with_unix_fds (int fd,
m.msg_control = alloca(m.msg_controllen);
memset(m.msg_control, 0, m.msg_controllen);
/* Do not include the padding at the end when we tell the kernel
* how much we're willing to receive. This avoids getting
* the padding filled with additional fds that we weren't expecting,
* if a (potentially malicious) sender included them. (fd.o #83622) */
m.msg_controllen = CMSG_LEN (*n_fds * sizeof(int));
again:
bytes_read = recvmsg(fd, &m, 0
......@@ -362,18 +368,49 @@ _dbus_read_socket_with_unix_fds (int fd,
for (cm = CMSG_FIRSTHDR(&m); cm; cm = CMSG_NXTHDR(&m, cm))
if (cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SCM_RIGHTS)
{
unsigned i;
_dbus_assert(cm->cmsg_len <= CMSG_LEN(*n_fds * sizeof(int)));
*n_fds = (cm->cmsg_len - CMSG_LEN(0)) / sizeof(int);
size_t i;
int *payload = (int *) CMSG_DATA (cm);
size_t payload_len_bytes = (cm->cmsg_len - CMSG_LEN (0));
size_t payload_len_fds = payload_len_bytes / sizeof (int);
size_t fds_to_use;
/* Every non-negative int fits in a size_t without truncation,
* and we already know that *n_fds is non-negative, so
* casting (size_t) *n_fds is OK */
_DBUS_STATIC_ASSERT (sizeof (size_t) >= sizeof (int));
if (_DBUS_LIKELY (payload_len_fds <= (size_t) *n_fds))
{
/* The fds in the payload will fit in our buffer */
fds_to_use = payload_len_fds;
}
else
{
/* Too many fds in the payload. This shouldn't happen
* any more because we're setting m.msg_controllen to
* the exact number we can accept, but be safe and
* truncate. */
fds_to_use = (size_t) *n_fds;
/* Close the excess fds to avoid DoS: if they stayed open,
* someone could send us an extra fd per message
* and we'd eventually run out. */
for (i = fds_to_use; i < payload_len_fds; i++)
{
close (payload[i]);
}
}
memcpy(fds, CMSG_DATA(cm), *n_fds * sizeof(int));
memcpy (fds, payload, fds_to_use * sizeof (int));
found = TRUE;
/* This cannot overflow because we have chosen fds_to_use
* to be <= *n_fds */
*n_fds = (int) fds_to_use;
/* Linux doesn't tell us whether MSG_CMSG_CLOEXEC actually
worked, hence we need to go through this list and set
CLOEXEC everywhere in any case */
for (i = 0; i < *n_fds; i++)
for (i = 0; i < fds_to_use; i++)
_dbus_fd_set_close_on_exec(fds[i]);
break;
......
......@@ -556,6 +556,14 @@ void _dbus_request_file_descriptor_limit (unsigned int limit);
const char *
_dbus_replace_install_prefix (const char *configure_time_path);
/* Do not set this too high: it is a denial-of-service risk.
* See <https://bugs.freedesktop.org/show_bug.cgi?id=82820>
*
* (This needs to be in the non-Unix-specific header so that
* the config-parser can use it.)
*/
#define DBUS_DEFAULT_MESSAGE_UNIX_FDS 16
/** @} */
DBUS_END_DECLS
......
......@@ -1512,6 +1512,33 @@ _dbus_transport_set_allow_anonymous (DBusTransport *transport,
transport->allow_anonymous = value != FALSE;
}