]> git.ipfire.org Git - thirdparty/dbus.git/commitdiff
sysdeps-unix: On MSG_CTRUNC, close the fds we did receive
authorSimon McVittie <smcv@collabora.com>
Thu, 16 Apr 2020 13:45:11 +0000 (14:45 +0100)
committerSimon McVittie <smcv@collabora.com>
Tue, 2 Jun 2020 10:11:47 +0000 (11:11 +0100)
MSG_CTRUNC indicates that we have received fewer fds that we should
have done because the buffer was too small, but we were treating it
as though it indicated that we received *no* fds. If we received any,
we still have to make sure we close them, otherwise they will be leaked.

On the system bus, if an attacker can induce us to leak fds in this
way, that's a local denial of service via resource exhaustion.

[Backport to dbus-1.10: Change signedness of iterator due to
commit ab8cb96e "_dbus_read_socket_with_unix_fds: make n_fds unsigned"
not having been applied to this branch.]

Reported-by: Kevin Backhouse, GitHub Security Lab
Fixes: dbus#294
Fixes: CVE-2020-12049
Fixes: GHSL-2020-057
dbus/dbus-sysdeps-unix.c

index b73097124a31d2f0c20a7e305b2414486e0e7bd8..6303dbc4ce2977c916860cf0618db5af39c3be4d 100644 (file)
@@ -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)
+        {
+          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);