From 96107564e2eabbc13800fe7a7d930b67216d0805 Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Thu, 12 Jul 2012 21:37:54 -0400 Subject: [PATCH] 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. --- arch/arm/bits/socket.h | 7 +++++++ arch/i386/bits/socket.h | 7 +++++++ arch/mips/bits/socket.h | 7 +++++++ arch/x86_64/bits/socket.h | 8 ++++++++ include/sys/socket.h | 7 ------- src/network/sendmsg.c | 13 +++++++++++++ 6 files changed, 42 insertions(+), 7 deletions(-) diff --git a/arch/arm/bits/socket.h b/arch/arm/bits/socket.h index c464ed90..36febbc2 100644 --- a/arch/arm/bits/socket.h +++ b/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; +}; diff --git a/arch/i386/bits/socket.h b/arch/i386/bits/socket.h index c464ed90..36febbc2 100644 --- a/arch/i386/bits/socket.h +++ b/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; +}; diff --git a/arch/mips/bits/socket.h b/arch/mips/bits/socket.h index c464ed90..36febbc2 100644 --- a/arch/mips/bits/socket.h +++ b/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; +}; diff --git a/arch/x86_64/bits/socket.h b/arch/x86_64/bits/socket.h index 878ab117..a90c4cae 100644 --- a/arch/x86_64/bits/socket.h +++ b/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; +}; diff --git a/include/sys/socket.h b/include/sys/socket.h index 50de321b..88243ae5 100644 --- a/include/sys/socket.h +++ b/include/sys/socket.h @@ -17,13 +17,6 @@ extern "C" { #include -struct cmsghdr -{ - socklen_t cmsg_len; - int cmsg_level; - int cmsg_type; -}; - struct ucred { pid_t pid; diff --git a/src/network/sendmsg.c b/src/network/sendmsg.c index 164c28d7..5f080007 100644 --- a/src/network/sendmsg.c +++ b/src/network/sendmsg.c @@ -1,5 +1,7 @@ #include #include +#include +#include #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); -- 2.25.1