From e17a921be676bcc89373ec1a9f368fe8b36f1073 Mon Sep 17 00:00:00 2001
From: Alban Crequy <alban.crequy@collabora.co.uk>
Date: Mon, 21 Jul 2014 17:34:08 +0100
Subject: [PATCH 05/10] config: add new limit: pending_fd_timeout

This is one of four commits needed to address CVE-2014-3637.

When a file descriptor is passed to dbus-daemon, the associated D-Bus message
might not be fully sent to dbus-daemon yet. Dbus-daemon keeps the file
descriptor in the DBusMessageLoader of the connection, waiting for the rest of
the message. If the client stops sending the remaining bytes, dbus-daemon will
wait forever and keep that file descriptor.

This patch adds pending_fd_timeout (milliseconds) in the configuration to
disconnect a connection after a timeout when a file descriptor was sent but not
the remaining message.

Bug: https://bugs.freedesktop.org/show_bug.cgi?id=80559
Reviewed-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
(cherry picked from commit bbf11cd5f92064c7c8af61ad4d9ff41f3a039abc)
Conflicts:
	cmake/bus/dbus-daemon.xml
---
 bus/bus.c                 |  6 ++++++
 bus/bus.h                 |  2 ++
 bus/config-parser.c       | 12 ++++++++++++
 bus/session.conf.in       |  1 +
 cmake/bus/dbus-daemon.xml |  6 +++++-
 5 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/bus/bus.c b/bus/bus.c
index 7ffe772..c4eadc2 100644
--- a/bus/bus.c
+++ b/bus/bus.c
@@ -1229,6 +1229,12 @@ bus_context_get_auth_timeout (BusContext *context)
 }
 
 int
+bus_context_get_pending_fd_timeout (BusContext *context)
+{
+  return context->limits.pending_fd_timeout;
+}
+
+int
 bus_context_get_max_completed_connections (BusContext *context)
 {
   return context->limits.max_completed_connections;
diff --git a/bus/bus.h b/bus/bus.h
index 400c9d0..7d0b369 100644
--- a/bus/bus.h
+++ b/bus/bus.h
@@ -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);
diff --git a/bus/config-parser.c b/bus/config-parser.c
index 95d69a4..897667e 100644
--- a/bus/config-parser.c
+++ b/bus/config-parser.c
@@ -428,6 +428,11 @@ bus_config_parser_new (const DBusString      *basedir,
        * password) is allowed, then potentially it has to be quite long.
        */
       parser->limits.auth_timeout = 30000; /* 30 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;
@@ -1891,6 +1896,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;
@@ -3097,6 +3108,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
diff --git a/bus/session.conf.in b/bus/session.conf.in
index 6ce8503..2ee1c31 100644
--- a/bus/session.conf.in
+++ b/bus/session.conf.in
@@ -53,6 +53,7 @@
        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>
diff --git a/cmake/bus/dbus-daemon.xml b/cmake/bus/dbus-daemon.xml
index f331699..fb517e2 100644
--- a/cmake/bus/dbus-daemon.xml
+++ b/cmake/bus/dbus-daemon.xml
@@ -401,7 +401,11 @@ Available limit names are:</para>
       "auth_timeout"               : milliseconds (thousandths) a
                                      connection is given to
                                      authenticate
-      "max_completed_connections"  : max number of authenticated connections  
+      "pending_fd_timeout"         : milliseconds (thousandths) a
+                                     fd is given to be transmitted to
+                                     dbus-daemon before disconnecting the
+                                     connection
+      "max_completed_connections"  : max number of authenticated connections
       "max_incomplete_connections" : max number of unauthenticated
                                      connections
       "max_connections_per_user"   : max number of completed connections from
-- 
2.1.0

