summaryrefslogtreecommitdiffstats
path: root/recipes-core/dbus/files/CVE-2014-3532.patch
blob: 95f110c8c2a536ad0d59726df208a5cec6c0459f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
Date: Tue, 24 Jun 2014 17:57:14 +0100
Subject: 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.

Upstream-Status: Backport

Bug: https://bugs.freedesktop.org/show_bug.cgi?id=80163
Reviewed-by: Thiago Macieira <thiago@kde.org>
[altered commit message to explain DoS significance -smcv]
Reviewed-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com>

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",
-- 
cgit v0.10.2