summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Fiddaman <omnios@citrus-it.co.uk>2020-06-12 12:32:20 +0000
committerSimon McVittie <smcv@collabora.com>2020-07-02 10:09:01 +0100
commit80f7e5b28c48c0bd98970ef972182f743bda448e (patch)
tree383c4bd3326e50bcdeea296f8e77cc0bb2bae6fb
parent0b07b76c721539251c86a2fb0d31dc5c14ffe4fa (diff)
downloaddbus-80f7e5b28c48c0bd98970ef972182f743bda448e.tar.gz
Solaris and derivatives do not adjust cmsg_len on MSG_CTRUNC
(cherry picked from commit b96ef23e406baa08648339a53b0161fc80de7ce4)
-rw-r--r--dbus/dbus-sysdeps-unix.c21
1 files changed, 20 insertions, 1 deletions
diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c
index 6303dbc4..4989e4a9 100644
--- a/dbus/dbus-sysdeps-unix.c
+++ b/dbus/dbus-sysdeps-unix.c
@@ -438,7 +438,7 @@ _dbus_read_socket_with_unix_fds (DBusSocket fd,
size_t i;
int *payload = (int *) CMSG_DATA (cm);
size_t payload_len_bytes = (cm->cmsg_len - CMSG_LEN (0));
- size_t payload_len_fds = payload_len_bytes / sizeof (int);
+ size_t payload_len_fds;
size_t fds_to_use;
/* Every non-negative int fits in a size_t without truncation,
@@ -446,6 +446,25 @@ _dbus_read_socket_with_unix_fds (DBusSocket fd,
* casting (size_t) *n_fds is OK */
_DBUS_STATIC_ASSERT (sizeof (size_t) >= sizeof (int));
+ if ((m.msg_flags & MSG_CTRUNC) && CMSG_NXTHDR(&m, cm) == NULL &&
+ (char *) payload + payload_len_bytes >
+ (char *) m.msg_control + m.msg_controllen)
+ {
+ /* This is the last cmsg in a truncated message and using
+ * cmsg_len would apparently overrun the allocated buffer.
+ * Some operating systems (illumos and Solaris are known) do
+ * not adjust cmsg_len in the last cmsg when truncation occurs.
+ * Adjust the payload length here. The calculation for
+ * payload_len_fds below will discard any trailing bytes that
+ * belong to an incomplete file descriptor - the kernel will
+ * have already closed that (at least for illumos and Solaris)
+ */
+ payload_len_bytes = m.msg_controllen -
+ ((char *) payload - (char *) m.msg_control);
+ }
+
+ payload_len_fds = payload_len_bytes / sizeof (int);
+
if (_DBUS_LIKELY (payload_len_fds <= (size_t) *n_fds))
{
/* The fds in the payload will fit in our buffer */