Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -2810,7 +2810,7 @@ #define INIT_MODF #endif -#if SANITIZER_INTERCEPT_RECVMSG +#if SANITIZER_INTERCEPT_RECVMSG || SANITIZER_INTERCEPT_RECVMMSG static void write_msghdr(void *ctx, struct __sanitizer_msghdr *msg, SSIZE_T maxlen) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg, sizeof(*msg)); @@ -2823,7 +2823,9 @@ if (msg->msg_control && msg->msg_controllen) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_control, msg->msg_controllen); } +#endif +#if SANITIZER_INTERCEPT_RECVMSG INTERCEPTOR(SSIZE_T, recvmsg, int fd, struct __sanitizer_msghdr *msg, int flags) { void *ctx; @@ -2846,7 +2848,30 @@ #define INIT_RECVMSG #endif -#if SANITIZER_INTERCEPT_SENDMSG +#if SANITIZER_INTERCEPT_RECVMMSG +INTERCEPTOR(int, recvmmsg, int fd, struct __sanitizer_mmsghdr *msgvec, + unsigned int vlen, int flags, void *timeout) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, recvmmsg, fd, msgvec, vlen, flags, timeout); + if (timeout) COMMON_INTERCEPTOR_READ_RANGE(ctx, timeout, struct_timespec_sz); + int res = REAL(recvmmsg)(fd, msgvec, vlen, flags, timeout); + if (res >= 0) { + if (fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); + for (int i = 0; i < res; ++i) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &msgvec[i].msg_len, + sizeof(msgvec[i].msg_len)); + write_msghdr(ctx, &msgvec[i].msg_hdr, msgvec[i].msg_len); + COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, &msgvec[i].msg_hdr); + } + } + return res; +} +#define INIT_RECVMMSG COMMON_INTERCEPT_FUNCTION(recvmmsg); +#else +#define INIT_RECVMMSG +#endif + +#if SANITIZER_INTERCEPT_SENDMSG || SANITIZER_INTERCEPT_SENDMMSG static void read_msghdr_control(void *ctx, void *control, uptr controllen) { const unsigned kCmsgDataOffset = RoundUpTo(sizeof(__sanitizer_cmsghdr), sizeof(uptr)); @@ -2896,7 +2921,9 @@ if (msg->msg_control && msg->msg_controllen) read_msghdr_control(ctx, msg->msg_control, msg->msg_controllen); } +#endif +#if SANITIZER_INTERCEPT_SENDMSG INTERCEPTOR(SSIZE_T, sendmsg, int fd, struct __sanitizer_msghdr *msg, int flags) { void *ctx; @@ -2915,6 +2942,30 @@ #define INIT_SENDMSG #endif +#if SANITIZER_INTERCEPT_SENDMMSG +INTERCEPTOR(int, sendmmsg, int fd, struct __sanitizer_mmsghdr *msgvec, + unsigned vlen, int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sendmmsg, fd, msgvec, vlen, flags); + if (fd >= 0) { + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); + } + int res = REAL(sendmmsg)(fd, msgvec, vlen, flags); + if (res >= 0 && msgvec) + for (int i = 0; i < res; ++i) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &msgvec[i].msg_len, + sizeof(msgvec[i].msg_len)); + if (common_flags()->intercept_send) + read_msghdr(ctx, &msgvec[i].msg_hdr, msgvec[i].msg_len); + } + return res; +} +#define INIT_SENDMMSG COMMON_INTERCEPT_FUNCTION(sendmmsg); +#else +#define INIT_SENDMMSG +#endif + #if SANITIZER_INTERCEPT_GETPEERNAME INTERCEPTOR(int, getpeername, int sockfd, void *addr, unsigned *addrlen) { void *ctx; @@ -6483,6 +6534,8 @@ INIT_MODF; INIT_RECVMSG; INIT_SENDMSG; + INIT_RECVMMSG; + INIT_SENDMMSG; INIT_GETPEERNAME; INIT_IOCTL; INIT_INET_ATON; Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform_interceptors.h =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -221,6 +221,8 @@ #define SANITIZER_INTERCEPT_MODF SI_POSIX #define SANITIZER_INTERCEPT_RECVMSG SI_POSIX #define SANITIZER_INTERCEPT_SENDMSG SI_POSIX +#define SANITIZER_INTERCEPT_RECVMMSG SI_LINUX +#define SANITIZER_INTERCEPT_SENDMMSG SI_LINUX #define SANITIZER_INTERCEPT_GETPEERNAME SI_POSIX #define SANITIZER_INTERCEPT_IOCTL SI_POSIX #define SANITIZER_INTERCEPT_INET_ATON SI_POSIX Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform_limits_posix.h =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -482,6 +482,13 @@ }; #endif +#if SANITIZER_LINUX + struct __sanitizer_mmsghdr { + __sanitizer_msghdr msg_hdr; + unsigned int msg_len; + }; +#endif + #if SANITIZER_MAC struct __sanitizer_dirent { unsigned long long d_ino; Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform_limits_posix.cc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform_limits_posix.cc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform_limits_posix.cc @@ -1026,6 +1026,12 @@ CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); +#if SANITIZER_LINUX +CHECK_TYPE_SIZE(mmsghdr); +CHECK_SIZE_AND_OFFSET(mmsghdr, msg_hdr); +CHECK_SIZE_AND_OFFSET(mmsghdr, msg_len); +#endif + COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); CHECK_SIZE_AND_OFFSET(dirent, d_ino); #if SANITIZER_MAC Index: compiler-rt/trunk/test/msan/Linux/sendmsg.cc =================================================================== --- compiler-rt/trunk/test/msan/Linux/sendmsg.cc +++ compiler-rt/trunk/test/msan/Linux/sendmsg.cc @@ -1,10 +1,12 @@ // RUN: %clangxx_msan %s -DSEND -DPOISON -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=SEND // RUN: %clangxx_msan %s -DSENDTO -DPOISON -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=SENDTO // RUN: %clangxx_msan %s -DSENDMSG -DPOISON -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=SENDMSG +// RUN: %clangxx_msan %s -DSENDMMSG -DPOISON -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=SENDMMSG // RUN: %clangxx_msan %s -DSEND -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=NEGATIVE // RUN: %clangxx_msan %s -DSENDTO -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=NEGATIVE // RUN: %clangxx_msan %s -DSENDMSG -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=NEGATIVE +// RUN: %clangxx_msan %s -DSENDMMSG -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=NEGATIVE // RUN: %clangxx_msan %s -DSEND -DPOISON -o %t && \ // RUN: MSAN_OPTIONS=intercept_send=0 %run %t 2>&1 | FileCheck %s --check-prefix=NEGATIVE @@ -12,6 +14,8 @@ // RUN: MSAN_OPTIONS=intercept_send=0 %run %t 2>&1 | FileCheck %s --check-prefix=NEGATIVE // RUN: %clangxx_msan %s -DSENDMSG -DPOISON -o %t && \ // RUN: MSAN_OPTIONS=intercept_send=0 %run %t 2>&1 | FileCheck %s --check-prefix=NEGATIVE +// RUN: %clangxx_msan %s -DSENDMMSG -DPOISON -o %t && \ +// RUN: MSAN_OPTIONS=intercept_send=0 %run %t 2>&1 | FileCheck %s --check-prefix=NEGATIVE // UNSUPPORTED: android @@ -20,54 +24,32 @@ #include #include #include -#include #include #include #include const int kBufSize = 10; -int sockfd; +const int kRecvBufSize = 100; +int sockfd[2]; int main() { int ret; + int sent; char buf[kBufSize] = {0}; - pthread_t client_thread; - struct sockaddr_in serveraddr; - struct sockaddr_in6 serveraddr6; - - memset(&serveraddr, 0, sizeof(serveraddr)); - serveraddr.sin_family = AF_INET; - serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); - serveraddr.sin_port = 0; - struct sockaddr *addr = (struct sockaddr *)&serveraddr; - socklen_t addrlen = sizeof(serveraddr); - - sockfd = socket(addr->sa_family, SOCK_DGRAM, 0); - if (sockfd <= 0) { - // Try to fall-back to IPv6 - memset(&serveraddr6, 0, sizeof(serveraddr6)); - serveraddr6.sin6_family = AF_INET6; - serveraddr6.sin6_addr = in6addr_any; - serveraddr6.sin6_port = 0; - addr = (struct sockaddr *)&serveraddr6; - addrlen = sizeof(serveraddr6); - - sockfd = socket(addr->sa_family, SOCK_DGRAM, 0); - } - assert(sockfd > 0); + char rbuf[kRecvBufSize]; - bind(sockfd, addr, addrlen); - getsockname(sockfd, addr, &addrlen); + ret = socketpair(AF_LOCAL, SOCK_DGRAM, 0, sockfd); + assert(!ret); #if defined(POISON) __msan_poison(buf + 7, 1); #endif -#if defined(SENDMSG) +#if defined(SENDMSG) || defined(SENDMMSG) struct iovec iov[2] = {{buf, 5}, {buf + 5, 5}}; struct msghdr msg; - msg.msg_name = addr; - msg.msg_namelen = addrlen; + msg.msg_name = nullptr; + msg.msg_namelen = 0; msg.msg_iov = iov; msg.msg_iovlen = 2; msg.msg_control = 0; @@ -75,20 +57,95 @@ msg.msg_flags = 0; #endif +#if defined(SENDMMSG) + struct iovec iov0[1] = {{buf, 7}}; + struct msghdr msg0; + msg0.msg_name = nullptr; + msg0.msg_namelen = 0; + msg0.msg_iov = iov0; + msg0.msg_iovlen = 1; + msg0.msg_control = 0; + msg0.msg_controllen = 0; + msg0.msg_flags = 0; + + struct mmsghdr mmsg[2]; + mmsg[0].msg_hdr = msg0; // good + mmsg[1].msg_hdr = msg; // poisoned +#endif + #if defined(SEND) - ret = connect(sockfd, addr, addrlen); - assert(ret == 0); - ret = send(sockfd, buf, kBufSize, 0); + sent = send(sockfd[0], buf, kBufSize, 0); // SEND: Uninitialized bytes in __interceptor_send at offset 7 inside [{{.*}}, 10) - assert(ret > 0); + assert(sent > 0); + + ret = recv(sockfd[1], rbuf, kRecvBufSize, 0); + assert(ret == sent); + assert(__msan_test_shadow(rbuf, kRecvBufSize) == sent); #elif defined(SENDTO) - ret = sendto(sockfd, buf, kBufSize, 0, addr, addrlen); + sent = sendto(sockfd[0], buf, kBufSize, 0, nullptr, 0); // SENDTO: Uninitialized bytes in __interceptor_sendto at offset 7 inside [{{.*}}, 10) - assert(ret > 0); + assert(sent > 0); + + struct sockaddr_storage ss; + socklen_t sslen = sizeof(ss); + ret = recvfrom(sockfd[1], rbuf, kRecvBufSize, 0, (struct sockaddr *)&ss, + &sslen); + assert(ret == sent); + assert(__msan_test_shadow(rbuf, kRecvBufSize) == sent); + assert(__msan_test_shadow(&ss, sizeof(ss)) == sslen); #elif defined(SENDMSG) - ret = sendmsg(sockfd, &msg, 0); + sent = sendmsg(sockfd[0], &msg, 0); // SENDMSG: Uninitialized bytes in {{.*}} at offset 2 inside [{{.*}}, 5) - assert(ret > 0); + assert(sent > 0); + + struct iovec riov[2] = {{rbuf, 3}, {rbuf + 3, kRecvBufSize - 3}}; + struct msghdr rmsg; + rmsg.msg_name = nullptr; + rmsg.msg_namelen = 0; + rmsg.msg_iov = riov; + rmsg.msg_iovlen = 2; + rmsg.msg_control = 0; + rmsg.msg_controllen = 0; + rmsg.msg_flags = 0; + + ret = recvmsg(sockfd[1], &rmsg, 0); + assert(ret == sent); + assert(__msan_test_shadow(rbuf, kRecvBufSize) == sent); +#elif defined(SENDMMSG) + sent = sendmmsg(sockfd[0], mmsg, 2, 0); + // SENDMMSG: Uninitialized bytes in {{.*}} at offset 2 inside [{{.*}}, 5) + assert(sent == 2); + if (ret >= 2) + assert(mmsg[1].msg_len > 0); + + struct iovec riov[2] = {{rbuf + kRecvBufSize / 2, kRecvBufSize / 2}}; + struct msghdr rmsg; + rmsg.msg_name = nullptr; + rmsg.msg_namelen = 0; + rmsg.msg_iov = riov; + rmsg.msg_iovlen = 1; + rmsg.msg_control = 0; + rmsg.msg_controllen = 0; + rmsg.msg_flags = 0; + + struct iovec riov0[2] = {{rbuf, kRecvBufSize / 2}}; + struct msghdr rmsg0; + rmsg0.msg_name = nullptr; + rmsg0.msg_namelen = 0; + rmsg0.msg_iov = riov0; + rmsg0.msg_iovlen = 1; + rmsg0.msg_control = 0; + rmsg0.msg_controllen = 0; + rmsg0.msg_flags = 0; + + struct mmsghdr rmmsg[2]; + rmmsg[0].msg_hdr = rmsg0; + rmmsg[1].msg_hdr = rmsg; + + ret = recvmmsg(sockfd[1], rmmsg, 2, 0, nullptr); + assert(ret == sent); + assert(__msan_test_shadow(rbuf, kRecvBufSize) == 7); + assert(__msan_test_shadow(rbuf + kRecvBufSize / 2, kRecvBufSize / 2) == 10); #endif fprintf(stderr, "== done\n"); // NEGATIVE: == done