Openwall GNU/*/Linux - a small security-enhanced Linux distro for servers
[<prev] [next>] [day] [month] [year] [list]
Date: Wed, 02 Jul 2014 17:04:16 +0100
From: Simon McVittie <simon.mcvittie@...labora.co.uk>
To: oss-security@...ts.openwall.com, 
 "dbus@...ts.freedesktop.org" <dbus@...ts.freedesktop.org>
CC: Alban Créquy <alban.crequy@...labora.co.uk>, 
 Colin Walters <walters@...bum.org>,
 Thiago Macieira <thiago@....org>
Subject: CVE-2014-3532, -3533: two local DoS vulnerabilities in dbus-daemon

Impact: denial of service (force system services to exit)
Access required: local
Versions affected by CVE-2014-3532: dbus >= 1.3.0 on Linux >= 2.6.37-rc4
Versions affected by CVE-2014-3533: dbus >= 1.3.0 on all Unix platforms

Alban Crequy at Collabora Ltd. discovered a bug in dbus-daemon's support
for file descriptor passing. A malicious process could force system
services or user applications to be disconnected from the D-Bus system
bus by sending them a message containing a file descriptor, then causing
that file descriptor to exceed the kernel's maximum recursion depth
(itself introduced to fix a DoS) before dbus-daemon forwards the message
to the victim process. Most services and applications exit when
disconnected from the system bus, leading to a denial of service. This
is tracked as fd.o#80163 and CVE-2014-3532.

Additionally, Alban discovered that bug fd.o#79694, a bug previously
reported by Alejandro Martínez Suárez which was not believed to be a
security flaw, could be used for a similar denial of service, by causing
dbus-daemon to attempt to forward invalid file descriptors to a victim
process when file descriptors become associated with the wrong message.
Its security implications are tracked as fd.o#80469 and CVE-2014-3533.

For the 1.8.x stable branch, these vulnerabilities are fixed in version
1.8.6. For the 1.6.x old-stable branch, these vulnerabilities are fixed
in version 1.6.22.

All earlier versions of dbus with the file descriptor passing feature
(1.3.0 and up) are believed to be vulnerable. Distributions that
backport security fixes should backport git commits
07f4c12efe3b9bd45d109bc5fbaf6d9dbf69d78e and
9ca90648fc870c24d852ce6d7ce9387a9fc9a94a, attached.

References:

[fd.o#79694] https://bugs.freedesktop.org/show_bug.cgi?id=79694
[fd.o#80469] https://bugs.freedesktop.org/show_bug.cgi?id=80469
[fd.o#80163] https://bugs.freedesktop.org/show_bug.cgi?id=80163

Regards,
    S


>>From 07f4c12efe3b9bd45d109bc5fbaf6d9dbf69d78e Mon Sep 17 00:00:00 2001
From: Simon McVittie <simon.mcvittie@...labora.co.uk>
Date: Wed, 11 Jun 2014 12:24:20 +0100
Subject: [PATCH 1/2] If loader contains two messages with fds, don't corrupt
 the second

There were two bugs here: we would previously overwrite the unused
fds with the already-used fds instead of the other way round, and
we would copy n bytes where we should have copied n ints.

Additionally, sending crafted messages in a chosen sequence to a victim
system service could cause an invalid file descriptor to be present
when dbus-daemon tries to forward one of those crafted messages to the
victim, causing sendmsg() to fail with EBADF, which resulted in
disconnecting the victim service, which would likely respond to that
by exiting. This is a denial of service (fd.o #80469, CVE-2014-3533).

Bug: https://bugs.freedesktop.org/show_bug.cgi?id=79694
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=80469
Reviewed-by: Alban Crequy <alban.crequy@...labora.co.uk>
---
 dbus/dbus-message.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c
index c6953d0..78df755 100644
--- a/dbus/dbus-message.c
+++ b/dbus/dbus-message.c
@@ -4204,7 +4204,7 @@ 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 + n_unix_fds, loader->unix_fds, loader->n_unix_fds);
+      memmove (loader->unix_fds, loader->unix_fds + n_unix_fds, loader->n_unix_fds * sizeof (loader->unix_fds[0]));
     }
   else
     message->unix_fds = NULL;
-- 
2.0.0



>>From 9ca90648fc870c24d852ce6d7ce9387a9fc9a94a Mon Sep 17 00:00:00 2001
From: Alban Crequy <alban.crequy@...labora.co.uk>
Date: Tue, 24 Jun 2014 17:57:14 +0100
Subject: [PATCH 2/2] Handle ETOOMANYREFS when sending recursive fds
 (SCM_RIGHTS)

Since Linux commit 25888e (from 2.6.37-rc4, Nov 2010), sendmsg() on Unix
sockets returns -1 errno=ETOOMANYREFS ("Too many references: cannot splice")
when the passfd mechanism (SCM_RIGHTS) is "abusively" used recursively by
applications. A malicious client could use this to force a victim system
service to be disconnected from the system bus; the victim would likely
respond by exiting. This is a denial of service (fd.o #80163,
CVE-2014-3532).

This patch silently drops the D-Bus message on ETOOMANYREFS and does not close
the connection.

Bug: https://bugs.freedesktop.org/show_bug.cgi?id=80163
Reviewed-by: Thiago Macieira <thiago@....org>
[altered commit message to explain DoS significance -smcv]
Reviewed-by: Simon McVittie <simon.mcvittie@...labora.co.uk>
---
 dbus/dbus-sysdeps.c          | 14 ++++++++++++++
 dbus/dbus-sysdeps.h          |  1 +
 dbus/dbus-transport-socket.c | 34 +++++++++++++++++++++++++++++++++-
 3 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c
index de3a18c..f4ba0fa 100644
--- a/dbus/dbus-sysdeps.c
+++ b/dbus/dbus-sysdeps.c
@@ -762,6 +762,20 @@ _dbus_get_is_errno_epipe (void)
 }
 
 /**
+ * See if errno is ETOOMANYREFS
+ * @returns #TRUE if errno == ETOOMANYREFS
+ */
+dbus_bool_t
+_dbus_get_is_errno_etoomanyrefs (void)
+{
+#ifdef ETOOMANYREFS
+  return errno == ETOOMANYREFS;
+#else
+  return FALSE;
+#endif
+}
+
+/**
  * Get error message from errno
  * @returns _dbus_strerror(errno)
  */
diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h
index e586946..21033eb 100644
--- a/dbus/dbus-sysdeps.h
+++ b/dbus/dbus-sysdeps.h
@@ -384,6 +384,7 @@ dbus_bool_t _dbus_get_is_errno_eagain_or_ewouldblock (void);
 dbus_bool_t _dbus_get_is_errno_enomem                (void);
 dbus_bool_t _dbus_get_is_errno_eintr                 (void);
 dbus_bool_t _dbus_get_is_errno_epipe                 (void);
+dbus_bool_t _dbus_get_is_errno_etoomanyrefs           (void);
 const char* _dbus_strerror_from_errno                (void);
 
 void _dbus_disable_sigpipe (void);
diff --git a/dbus/dbus-transport-socket.c b/dbus/dbus-transport-socket.c
index 774f459..199d3b5 100644
--- a/dbus/dbus-transport-socket.c
+++ b/dbus/dbus-transport-socket.c
@@ -645,12 +645,44 @@ do_writing (DBusTransport *transport)
         {
           /* EINTR already handled for us */
           
-          /* For some discussion of why we also ignore EPIPE here, see
+          /* If the other end closed the socket with close() or shutdown(), we
+           * receive EPIPE here but we must not close the socket yet: there
+           * might still be some data to read. See:
            * http://lists.freedesktop.org/archives/dbus/2008-March/009526.html
            */
           
           if (_dbus_get_is_errno_eagain_or_ewouldblock () || _dbus_get_is_errno_epipe ())
             goto out;
+
+          /* Since Linux commit 25888e (from 2.6.37-rc4, Nov 2010), sendmsg()
+           * on Unix sockets returns -1 errno=ETOOMANYREFS when the passfd
+           * mechanism (SCM_RIGHTS) is used recursively with a recursion level
+           * of maximum 4. The kernel does not have an API to check whether
+           * the passed fds can be forwarded and it can change asynchronously.
+           * See:
+           * https://bugs.freedesktop.org/show_bug.cgi?id=80163
+           */
+
+          else if (_dbus_get_is_errno_etoomanyrefs ())
+            {
+              /* We only send fds in the first byte of the message.
+               * ETOOMANYREFS cannot happen after.
+               */
+              _dbus_assert (socket_transport->message_bytes_written == 0);
+
+              _dbus_verbose (" discard message of %d bytes due to ETOOMANYREFS\n",
+                             total_bytes_to_write);
+
+              socket_transport->message_bytes_written = 0;
+              _dbus_string_set_length (&socket_transport->encoded_outgoing, 0);
+              _dbus_string_compact (&socket_transport->encoded_outgoing, 2048);
+
+              /* The message was not actually sent but it needs to be removed
+               * from the outgoing queue
+               */
+              _dbus_connection_message_sent_unlocked (transport->connection,
+                                                      message);
+            }
           else
             {
               _dbus_verbose ("Error writing to remote app: %s\n",
-- 
2.0.0



Powered by blists - more mailing lists

Your e-mail address:

Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.

Powered by Openwall GNU/*/Linux - Powered by OpenVZ