aboutsummaryrefslogtreecommitdiffstats
path: root/main/dbus/CVE-2020-12049.patch
blob: f1b04b4a65067cb0427ac676946db36525747e40 (plain) (blame)
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
This is a combination of

https://gitlab.freedesktop.org/dbus/dbus/-/commit/8bc1381819e5a845331650bfa28dacf6d2ac1748.patch
https://gitlab.freedesktop.org/dbus/dbus/-/commit/272d484283883fa9ff95b69d924fff6cd34842f5.patch

Applied against the 1.10 tree (the commits are for 1.12)

diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c
index b730971..4b0e390 100644
--- a/dbus/dbus-sysdeps-unix.c
+++ b/dbus/dbus-sysdeps-unix.c
@@ -432,18 +432,6 @@ _dbus_read_socket_with_unix_fds (DBusSocket        fd,
       struct cmsghdr *cm;
       dbus_bool_t found = FALSE;
 
-      if (m.msg_flags & MSG_CTRUNC)
-        {
-          /* Hmm, apparently the control data was truncated. The bad
-             thing is that we might have completely lost a couple of fds
-             without chance to recover them. Hence let's treat this as a
-             serious error. */
-
-          errno = ENOSPC;
-          _dbus_string_set_length (buffer, start);
-          return -1;
-        }
-
       for (cm = CMSG_FIRSTHDR(&m); cm; cm = CMSG_NXTHDR(&m, cm))
         if (cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SCM_RIGHTS)
           {
@@ -498,6 +486,26 @@ _dbus_read_socket_with_unix_fds (DBusSocket        fd,
       if (!found)
         *n_fds = 0;
 
+      if (m.msg_flags & MSG_CTRUNC)
+        {
+          unsigned int i;
+
+          /* Hmm, apparently the control data was truncated. The bad
+             thing is that we might have completely lost a couple of fds
+             without chance to recover them. Hence let's treat this as a
+             serious error. */
+
+          /* We still need to close whatever fds we *did* receive,
+           * otherwise they'll never get closed. (CVE-2020-12049) */
+          for (i = 0; i < *n_fds; i++)
+            close (fds[i]);
+
+          *n_fds = 0;
+          errno = ENOSPC;
+          _dbus_string_set_length (buffer, start);
+          return -1;
+        }
+
       /* put length back (doesn't actually realloc) */
       _dbus_string_set_length (buffer, start + bytes_read);
 
diff --git a/test/fdpass.c b/test/fdpass.c
index 665b4a1..d8d9c67 100644
--- a/test/fdpass.c
+++ b/test/fdpass.c
@@ -50,6 +50,14 @@
 
 #include "test-utils-glib.h"
 
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
+#include <dbus/dbus-message-internal.h>
+#else
+typedef struct _DBusInitialFDs DBusInitialFDs;
+#define _dbus_check_fdleaks_enter() NULL
+#define _dbus_check_fdleaks_leave(fds) do {} while (0)
+#endif
+
 /* Arbitrary; included here to avoid relying on the default */
 #define MAX_MESSAGE_UNIX_FDS 20
 /* This test won't work on Linux unless this is true. */
@@ -91,6 +99,7 @@ typedef struct {
     GQueue messages;
 
     int fd_before;
+    DBusInitialFDs *initial_fds;
 } Fixture;
 
 static void oom (const gchar *doing) G_GNUC_NORETURN;
@@ -172,6 +181,8 @@ test_connect (Fixture *f,
 {
   char *address;
 
+  f->initial_fds = _dbus_check_fdleaks_enter ();
+
   g_assert (f->left_server_conn == NULL);
   g_assert (f->right_server_conn == NULL);
 
@@ -835,6 +846,9 @@ teardown (Fixture *f,
   if (f->fd_before >= 0 && close (f->fd_before) < 0)
     g_error ("%s", g_strerror (errno));
 #endif
+
+  if (f->initial_fds != NULL)
+    _dbus_check_fdleaks_leave (f->initial_fds);
 }
 
 int