فهرست منبع

workaround another sendmsg kernel bug on 64-bit machines

the kernel wrongly expects the cmsg length field to be size_t instead
of socklen_t. in order to work around the issue, we have to impose a
length limit and copy to a local buffer. the length limit should be
more than sufficient for any real-world use; these headers are only
used for passing file descriptors and permissions between processes
over unix sockets.
Rich Felker 13 سال پیش
والد
کامیت
96107564e2
6فایلهای تغییر یافته به همراه42 افزوده شده و 7 حذف شده
  1. 7 0
      arch/arm/bits/socket.h
  2. 7 0
      arch/i386/bits/socket.h
  3. 7 0
      arch/mips/bits/socket.h
  4. 8 0
      arch/x86_64/bits/socket.h
  5. 0 7
      include/sys/socket.h
  6. 13 0
      src/network/sendmsg.c

+ 7 - 0
arch/arm/bits/socket.h

@@ -8,3 +8,10 @@ struct msghdr
 	socklen_t msg_controllen;
 	int msg_flags;
 };
+
+struct cmsghdr
+{
+	socklen_t cmsg_len;
+	int cmsg_level;
+	int cmsg_type;
+};

+ 7 - 0
arch/i386/bits/socket.h

@@ -8,3 +8,10 @@ struct msghdr
 	socklen_t msg_controllen;
 	int msg_flags;
 };
+
+struct cmsghdr
+{
+	socklen_t cmsg_len;
+	int cmsg_level;
+	int cmsg_type;
+};

+ 7 - 0
arch/mips/bits/socket.h

@@ -8,3 +8,10 @@ struct msghdr
 	socklen_t msg_controllen;
 	int msg_flags;
 };
+
+struct cmsghdr
+{
+	socklen_t cmsg_len;
+	int cmsg_level;
+	int cmsg_type;
+};

+ 8 - 0
arch/x86_64/bits/socket.h

@@ -8,3 +8,11 @@ struct msghdr
 	socklen_t msg_controllen, __pad2;
 	int msg_flags;
 };
+
+struct cmsghdr
+{
+	socklen_t cmsg_len;
+	int __pad1;
+	int cmsg_level;
+	int cmsg_type;
+};

+ 0 - 7
include/sys/socket.h

@@ -17,13 +17,6 @@ extern "C" {
 
 #include <bits/socket.h>
 
-struct cmsghdr
-{
-	socklen_t cmsg_len;
-	int cmsg_level;
-	int cmsg_type;
-};
-
 struct ucred
 {
 	pid_t pid;

+ 13 - 0
src/network/sendmsg.c

@@ -1,5 +1,7 @@
 #include <sys/socket.h>
 #include <limits.h>
+#include <string.h>
+#include <errno.h>
 #include "syscall.h"
 #include "libc.h"
 
@@ -7,10 +9,21 @@ ssize_t sendmsg(int fd, const struct msghdr *msg, int flags)
 {
 #if LONG_MAX > INT_MAX
 	struct msghdr h;
+	struct cmsghdr chbuf[1024/sizeof(struct cmsghdr)+1], *c;
 	if (msg) {
 		h = *msg;
 		h.__pad1 = h.__pad2 = 0;
 		msg = &h;
+		if (h.msg_controllen) {
+			if (h.msg_controllen > 1024) {
+				errno = ENOMEM;
+				return -1;
+			}
+			memcpy(chbuf, h.msg_control, h.msg_controllen);
+			h.msg_control = chbuf;
+			for (c=CMSG_FIRSTHDR(&h); c; c=CMSG_NXTHDR(&h,c))
+				c->__pad1 = 0;
+		}
 	}
 #endif
 	return socketcall_cp(sendmsg, fd, msg, flags, 0, 0, 0);