[PATCH] network: Fix cmsghdr padding in sendmsg (BZ#16919)

Adhemerval Zanella adhemerval.zanella@linaro.org
Thu May 26 14:50:00 GMT 2016


This patch fixes the remaining issue in sendmsg POSIX compliance by
adjusting the cmsghdr padding accordingly for 64-bits ABIs.  Since
function contract does not allow to modify it in place, a temporary
buffer instead.  Although the value used is arbitrary (current 2048
bytes), it is expected to cover mostly common usar cases for this
facility (passing file descriptors and permission between processes).

I did not send this change on previous patches because I would like
some feedback about buffer size used in copy operations.

Tested on x86_64 and i686.

	* sysdeps/unix/sysv/linux/sendmsg.c (__libc_sendmsg): Fix cmsghdr
	padding for 64-bits.
---
 ChangeLog                         |  3 +++
 sysdeps/unix/sysv/linux/sendmsg.c | 23 +++++++++++++++++++++++
 2 files changed, 26 insertions(+)

diff --git a/ChangeLog b/ChangeLog
index ecedf6f..317d228 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -9,6 +9,9 @@
 
 2016-05-25  Adhemerval Zanella  <adhemerval.zanella@linaro.org>
 
+	* sysdeps/unix/sysv/linux/sendmsg.c (__libc_sendmsg): Fix cmsghdr
+	padding for 64-bits.
+
 	* sysdeps/unix/sysv/linux/Makefile
 	[$(subdir) = socket] (sysdep_routines): Add oldrecvmmsg and
 	oldsendmmsg.
diff --git a/sysdeps/unix/sysv/linux/sendmsg.c b/sysdeps/unix/sysv/linux/sendmsg.c
index a5ef238..4a5420a 100644
--- a/sysdeps/unix/sysv/linux/sendmsg.c
+++ b/sysdeps/unix/sysv/linux/sendmsg.c
@@ -19,6 +19,7 @@
 #include <sysdep-cancel.h>
 #include <socketcall.h>
 #include <shlib-compat.h>
+#include <string.h>
 
 ssize_t
 __libc_sendmsg (int fd, const struct msghdr *msg, int flags)
@@ -28,13 +29,35 @@ __libc_sendmsg (int fd, const struct msghdr *msg, int flags)
      both size_t.  So for 64-bit it requires some adjustments by copying to
      temporary header and zeroing the pad fields.  */
 #if __WORDSIZE == 64
+# define CMSGHDR_CONTROLLEN_MAX 2048
   struct msghdr hdr;
+  struct cmsghdr auxcbuf[CMSGHDR_CONTROLLEN_MAX/sizeof(struct cmsghdr)+1];
   if (msg != NULL)
     {
       hdr = *msg;
       hdr.__glibc_reserved1 = 0;
       hdr.__glibc_reserved2 = 0;
       msg = &hdr;
+
+      if (hdr.msg_controllen > 0)
+	{
+	  /* Since function contract does not allow modify the msg_controllen
+	     in place it requires to copy on a temporary buffer to make the
+	     adjustment required by POSIX.  Current limit is quite arbitrary
+	     and it is expected to cover the mostly common user cases for
+	     this (passing file descriptors and permission between processes
+	     over unix sockets).  */
+	  if (hdr.msg_controllen > CMSGHDR_CONTROLLEN_MAX)
+	    {
+	      __set_errno (ENOMEM);
+	      return -1;
+	    }
+	  memcpy (auxcbuf, hdr.msg_control, hdr.msg_controllen);
+	  hdr.msg_control = auxcbuf;
+	  for (struct cmsghdr *c = CMSG_FIRSTHDR (&hdr); c != NULL;
+	       c = CMSG_NXTHDR(&hdr, c))
+	    c->__glibc_reserved1 = 0;
+	}
     }
 #endif
 
-- 
2.7.4



More information about the Libc-alpha mailing list