diff options
author | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2014-09-12 15:51:39 +0100 |
---|---|---|
committer | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2014-09-15 12:27:26 +0100 |
commit | 6465e37c8ff70a714e302d0c9e6534fa6181fce6 (patch) | |
tree | 03de84640498b9533e0f42f065132b843b5d92c7 | |
parent | 5bc7f9519ebc6117ba300c704794b36b87c2194b (diff) | |
download | dbus-6465e37c8ff70a714e302d0c9e6534fa6181fce6.tar.gz |
config: change DEFAULT_MESSAGE_UNIX_FDS to 16
This addresses CVE-2014-3636.
Based on a patch by Alban Crequy. Now that it's the same on all
platforms, there's little point in it being set by configure/cmake.
This change fixes two distinct denials of service:
fd.o#82820, part A
------------------
Before this patch, the system bus had the following default configuration:
- max_connections_per_user: 256
- DBUS_DEFAULT_MESSAGE_UNIX_FDS: usually 1024 (or 256 on QNX, see fd.o#61176)
as defined by configure.ac
- max_incoming_unix_fds: DBUS_DEFAULT_MESSAGE_UNIX_FDS*4 = usually 4096
- max_outgoing_unix_fds: DBUS_DEFAULT_MESSAGE_UNIX_FDS*4 = usually 4096
- max_message_unix_fds: DBUS_DEFAULT_MESSAGE_UNIX_FDS = usually 1024
This means that a single user could create 256 connections and transmit
256*4096 = 1048576 file descriptors.
The file descriptors stay attached to the dbus-daemon process while they are
in the message loader, in the outgoing queue or waiting to be dispatched before
D-Bus activation.
dbus-daemon is usually limited to 65536 file descriptors (ulimit -n). If the
limit is reached and dbus-daemon needs to receive a message with a file
descriptor attached, this is signalled by recvfrom with the flag MSG_CTRUNC.
Dbus-daemon cannot recover from that error because the kernel does not have any
API to retrieve a file descriptor which has been discarded with MSG_CTRUNC.
Therefore, it closes the connection of the sender. This is not necessarily the
connection which generated the most file descriptors so it can lead to
denial-of-service attacks.
In order to prevent DoS issues, this patch reduces DEFAULT_MESSAGE_UNIX_FDS to
16:
max_connections_per_user * max_incoming_unix_fds = 256 * 64 = 16384
This is less than the usual "ulimit -n" (65536) with a good margin to
accomodate the other sources of file descriptors (stdin/stdout/stderr,
listening sockets, message loader, etc.).
Distributors on non-Linux may need to configure a smaller limit in
system.conf, if their limit on the number of fds is smaller than
Linux's.
fd.o#82820, part B
------------------
On Linux, it's not possible to send more than 253 fds in a single sendmsg()
call: sendmsg() would return -EINVAL.
#define SCM_MAX_FD 253
SCM_MAX_FD changed value during Linux history:
- it used to be (OPEN_MAX-1)
- commit c09edd6eb (Jul 2007) changed it to 255
- commit bba14de98 (Nov 2010) changed it to 253
Libdbus always sends all of a message's fds, and the beginning
of the message itself, in a single sendmsg() call. Combining these
two, a malicious sender could split a message across two or more
sendmsg() calls to construct a composite message with 254 or more
fds. When dbus-daemon attempted to relay that message to its
recipient in a single sendmsg() call, it would receive EINVAL,
interpret that as a fatal socket error and disconnect the recipient,
resulting in denial of service.
This is fixed by keeping max_message_unix_fds <= SCM_MAX_FD.
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=82820
Reviewed-by: Alban Crequy <alban.crequy@collabora.co.uk>
-rw-r--r-- | bus/session.conf.in | 3 | ||||
-rw-r--r-- | cmake/CMakeLists.txt | 4 | ||||
-rw-r--r-- | cmake/config.h.cmake | 2 | ||||
-rw-r--r-- | configure.ac | 11 | ||||
-rw-r--r-- | dbus/dbus-message.c | 1 | ||||
-rw-r--r-- | dbus/dbus-sysdeps.h | 8 |
6 files changed, 11 insertions, 18 deletions
diff --git a/bus/session.conf.in b/bus/session.conf.in index 74d9d1fd..d4730363 100644 --- a/bus/session.conf.in +++ b/bus/session.conf.in @@ -49,7 +49,8 @@ <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="max_completed_connections">100000</limit> diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index b7c25299..c767c171 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -417,10 +417,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. # diff --git a/cmake/config.h.cmake b/cmake/config.h.cmake index bd4cd444..eaec1e98 100644 --- a/cmake/config.h.cmake +++ b/cmake/config.h.cmake @@ -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 diff --git a/configure.ac b/configure.ac index c41426f6..8a530b29 100644 --- a/configure.ac +++ b/configure.ac @@ -1242,17 +1242,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" AC_SUBST([LIBDBUS_LIBS]) diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index 78df7558..f4787b06 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -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 diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h index 21033ebf..47ba2f43 100644 --- a/dbus/dbus-sysdeps.h +++ b/dbus/dbus-sysdeps.h @@ -558,6 +558,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 |