summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2023-01-16 22:13:35 +0100
committerStefan Metzmacher <metze@samba.org>2023-01-18 11:49:38 +0000
commit77110bc9e8a09ebefaa42eb4fd3a7449373fec9a (patch)
tree05214f79e8bcf76d4ddbd3eefae94efb93a42ab8
parent35ee3e0231ac95cc81dee32eb8efd97e0c3016f9 (diff)
downloadsamba-77110bc9e8a09ebefaa42eb4fd3a7449373fec9a.tar.gz
third_party: Update socket_wrapper to version 1.4.0
The key feature is support for sendmmsg and recvmmsg, which is required by modern libuv versions, e.g. nsupdate -g makes use of libuv, so we need this for samba. Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Andreas Schneider <asn@samba.org>
-rw-r--r--third_party/socket_wrapper/socket_wrapper.c887
-rw-r--r--third_party/socket_wrapper/wscript14
2 files changed, 884 insertions, 17 deletions
diff --git a/third_party/socket_wrapper/socket_wrapper.c b/third_party/socket_wrapper/socket_wrapper.c
index bedda07a72b..bf4a976eaee 100644
--- a/third_party/socket_wrapper/socket_wrapper.c
+++ b/third_party/socket_wrapper/socket_wrapper.c
@@ -47,6 +47,12 @@
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
+#ifdef HAVE_SYS_SYSCALL_H
+#include <sys/syscall.h>
+#endif
+#ifdef HAVE_SYSCALL_H
+#include <syscall.h>
+#endif
#include <sys/socket.h>
#include <sys/ioctl.h>
#ifdef HAVE_SYS_FILIO_H
@@ -537,8 +543,29 @@ typedef int (*__libc_recvfrom)(int sockfd,
struct sockaddr *src_addr,
socklen_t *addrlen);
typedef int (*__libc_recvmsg)(int sockfd, const struct msghdr *msg, int flags);
+#ifdef HAVE_RECVMMSG
+#if defined(HAVE_RECVMMSG_SSIZE_T_CONST_TIMEOUT)
+/* FreeBSD */
+typedef ssize_t (*__libc_recvmmsg)(int sockfd, struct mmsghdr *msgvec, size_t vlen, int flags, const struct timespec *timeout);
+#elif defined(HAVE_RECVMMSG_CONST_TIMEOUT)
+/* Linux legacy glibc < 2.21 */
+typedef int (*__libc_recvmmsg)(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, const struct timespec *timeout);
+#else
+/* Linux glibc >= 2.21 */
+typedef int (*__libc_recvmmsg)(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, struct timespec *timeout);
+#endif
+#endif /* HAVE_RECVMMSG */
typedef int (*__libc_send)(int sockfd, const void *buf, size_t len, int flags);
typedef int (*__libc_sendmsg)(int sockfd, const struct msghdr *msg, int flags);
+#ifdef HAVE_SENDMMSG
+#if defined(HAVE_SENDMMSG_SSIZE_T)
+/* FreeBSD */
+typedef ssize_t (*__libc_sendmmsg)(int sockfd, struct mmsghdr *msgvec, size_t vlen, int flags);
+#else
+/* Linux */
+typedef int (*__libc_sendmmsg)(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags);
+#endif
+#endif /* HAVE_SENDMMSG */
typedef int (*__libc_sendto)(int sockfd,
const void *buf,
size_t len,
@@ -560,6 +587,9 @@ typedef int (*__libc_timerfd_create)(int clockid, int flags);
#endif
typedef ssize_t (*__libc_write)(int fd, const void *buf, size_t count);
typedef ssize_t (*__libc_writev)(int fd, const struct iovec *iov, int iovcnt);
+#ifdef HAVE_SYSCALL
+typedef long int (*__libc_syscall)(long int sysno, ...);
+#endif
#define SWRAP_SYMBOL_ENTRY(i) \
union { \
@@ -605,8 +635,14 @@ struct swrap_libc_symbols {
SWRAP_SYMBOL_ENTRY(recv);
SWRAP_SYMBOL_ENTRY(recvfrom);
SWRAP_SYMBOL_ENTRY(recvmsg);
+#ifdef HAVE_RECVMMSG
+ SWRAP_SYMBOL_ENTRY(recvmmsg);
+#endif
SWRAP_SYMBOL_ENTRY(send);
SWRAP_SYMBOL_ENTRY(sendmsg);
+#ifdef HAVE_SENDMMSG
+ SWRAP_SYMBOL_ENTRY(sendmmsg);
+#endif
SWRAP_SYMBOL_ENTRY(sendto);
SWRAP_SYMBOL_ENTRY(setsockopt);
#ifdef HAVE_SIGNALFD
@@ -619,7 +655,32 @@ struct swrap_libc_symbols {
#endif
SWRAP_SYMBOL_ENTRY(write);
SWRAP_SYMBOL_ENTRY(writev);
+#ifdef HAVE_SYSCALL
+ SWRAP_SYMBOL_ENTRY(syscall);
+#endif
};
+#undef SWRAP_SYMBOL_ENTRY
+
+#define SWRAP_SYMBOL_ENTRY(i) \
+ union { \
+ __rtld_default_##i f; \
+ void *obj; \
+ } _rtld_default_##i
+
+#ifdef HAVE_SYSCALL
+typedef bool (*__rtld_default_uid_wrapper_syscall_valid)(long int sysno);
+typedef long int (*__rtld_default_uid_wrapper_syscall_va)(long int sysno, va_list va);
+#endif
+
+struct swrap_rtld_default_symbols {
+#ifdef HAVE_SYSCALL
+ SWRAP_SYMBOL_ENTRY(uid_wrapper_syscall_valid);
+ SWRAP_SYMBOL_ENTRY(uid_wrapper_syscall_va);
+#else
+ uint8_t dummy;
+#endif
+};
+#undef SWRAP_SYMBOL_ENTRY
struct swrap {
struct {
@@ -627,6 +688,10 @@ struct swrap {
void *socket_handle;
struct swrap_libc_symbols symbols;
} libc;
+
+ struct {
+ struct swrap_rtld_default_symbols symbols;
+ } rtld_default;
};
static struct swrap swrap;
@@ -807,6 +872,11 @@ static void _swrap_mutex_unlock(pthread_mutex_t *mutex, const char *name, const
#define swrap_bind_symbol_libsocket(sym_name) \
_swrap_bind_symbol_generic(SWRAP_LIBSOCKET, sym_name)
+#define swrap_bind_symbol_rtld_default_optional(sym_name) do { \
+ swrap.rtld_default.symbols._rtld_default_##sym_name.obj = \
+ dlsym(RTLD_DEFAULT, #sym_name); \
+} while(0);
+
static void swrap_bind_symbol_all(void);
/****************************************************************************
@@ -1131,6 +1201,24 @@ static int libc_recvmsg(int sockfd, struct msghdr *msg, int flags)
return swrap.libc.symbols._libc_recvmsg.f(sockfd, msg, flags);
}
+#ifdef HAVE_RECVMMSG
+#if defined(HAVE_RECVMMSG_SSIZE_T_CONST_TIMEOUT)
+/* FreeBSD */
+static ssize_t libc_recvmmsg(int sockfd, struct mmsghdr *msgvec, size_t vlen, int flags, const struct timespec *timeout)
+#elif defined(HAVE_RECVMMSG_CONST_TIMEOUT)
+/* Linux legacy glibc < 2.21 */
+static int libc_recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, const struct timespec *timeout)
+#else
+/* Linux glibc >= 2.21 */
+static int libc_recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, struct timespec *timeout)
+#endif
+{
+ swrap_bind_symbol_all();
+
+ return swrap.libc.symbols._libc_recvmmsg.f(sockfd, msgvec, vlen, flags, timeout);
+}
+#endif
+
static int libc_send(int sockfd, const void *buf, size_t len, int flags)
{
swrap_bind_symbol_all();
@@ -1145,6 +1233,21 @@ static int libc_sendmsg(int sockfd, const struct msghdr *msg, int flags)
return swrap.libc.symbols._libc_sendmsg.f(sockfd, msg, flags);
}
+#ifdef HAVE_SENDMMSG
+#if defined(HAVE_SENDMMSG_SSIZE_T)
+/* FreeBSD */
+static ssize_t libc_sendmmsg(int sockfd, struct mmsghdr *msgvec, size_t vlen, int flags)
+#else
+/* Linux */
+static int libc_sendmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags)
+#endif
+{
+ swrap_bind_symbol_all();
+
+ return swrap.libc.symbols._libc_sendmmsg.f(sockfd, msgvec, vlen, flags);
+}
+#endif
+
static int libc_sendto(int sockfd,
const void *buf,
size_t len,
@@ -1223,6 +1326,64 @@ static ssize_t libc_writev(int fd, const struct iovec *iov, int iovcnt)
return swrap.libc.symbols._libc_writev.f(fd, iov, iovcnt);
}
+#ifdef HAVE_SYSCALL
+DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
+static long int libc_vsyscall(long int sysno, va_list va)
+{
+ long int args[8];
+ long int rc;
+ int i;
+
+ swrap_bind_symbol_all();
+
+ for (i = 0; i < 8; i++) {
+ args[i] = va_arg(va, long int);
+ }
+
+ rc = swrap.libc.symbols._libc_syscall.f(sysno,
+ args[0],
+ args[1],
+ args[2],
+ args[3],
+ args[4],
+ args[5],
+ args[6],
+ args[7]);
+
+ return rc;
+}
+
+static bool swrap_uwrap_syscall_valid(long int sysno)
+{
+ swrap_bind_symbol_all();
+
+ if (swrap.rtld_default.symbols._rtld_default_uid_wrapper_syscall_valid.f == NULL) {
+ return false;
+ }
+
+ return swrap.rtld_default.symbols._rtld_default_uid_wrapper_syscall_valid.f(
+ sysno);
+}
+
+DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
+static long int swrap_uwrap_syscall_va(long int sysno, va_list va)
+{
+ swrap_bind_symbol_all();
+
+ if (swrap.rtld_default.symbols._rtld_default_uid_wrapper_syscall_va.f == NULL) {
+ /*
+ * Fallback to libc, if uid_wrapper_syscall_va is not
+ * available.
+ */
+ return libc_vsyscall(sysno, va);
+ }
+
+ return swrap.rtld_default.symbols._rtld_default_uid_wrapper_syscall_va.f(
+ sysno,
+ va);
+}
+#endif /* HAVE_SYSCALL */
+
/* DO NOT call this function during library initialization! */
static void __swrap_bind_symbol_all_once(void)
{
@@ -1263,8 +1424,14 @@ static void __swrap_bind_symbol_all_once(void)
swrap_bind_symbol_libsocket(recv);
swrap_bind_symbol_libsocket(recvfrom);
swrap_bind_symbol_libsocket(recvmsg);
+#ifdef HAVE_RECVMMSG
+ swrap_bind_symbol_libsocket(recvmmsg);
+#endif
swrap_bind_symbol_libsocket(send);
swrap_bind_symbol_libsocket(sendmsg);
+#ifdef HAVE_SENDMMSG
+ swrap_bind_symbol_libsocket(sendmmsg);
+#endif
swrap_bind_symbol_libsocket(sendto);
swrap_bind_symbol_libsocket(setsockopt);
#ifdef HAVE_SIGNALFD
@@ -1277,6 +1444,11 @@ static void __swrap_bind_symbol_all_once(void)
#endif
swrap_bind_symbol_libc(write);
swrap_bind_symbol_libsocket(writev);
+#ifdef HAVE_SYSCALL
+ swrap_bind_symbol_libc(syscall);
+ swrap_bind_symbol_rtld_default_optional(uid_wrapper_syscall_valid);
+ swrap_bind_symbol_rtld_default_optional(uid_wrapper_syscall_va);
+#endif
}
static void swrap_bind_symbol_all(void)
@@ -1429,6 +1601,55 @@ static size_t socket_length(int family)
return 0;
}
+struct swrap_sockaddr_buf {
+ char str[128];
+};
+
+static const char *swrap_sockaddr_string(struct swrap_sockaddr_buf *buf,
+ const struct sockaddr *saddr)
+{
+ unsigned int port = 0;
+ char addr[64] = {0,};
+
+ switch (saddr->sa_family) {
+ case AF_INET: {
+ const struct sockaddr_in *in =
+ (const struct sockaddr_in *)(const void *)saddr;
+
+ port = ntohs(in->sin_port);
+
+ inet_ntop(saddr->sa_family,
+ &in->sin_addr,
+ addr, sizeof(addr));
+ break;
+ }
+#ifdef HAVE_IPV6
+ case AF_INET6: {
+ const struct sockaddr_in6 *in6 =
+ (const struct sockaddr_in6 *)(const void *)saddr;
+
+ port = ntohs(in6->sin6_port);
+
+ inet_ntop(saddr->sa_family,
+ &in6->sin6_addr,
+ addr, sizeof(addr));
+ break;
+ }
+#endif
+ default:
+ snprintf(addr, sizeof(addr),
+ "<Unknown address family %u>",
+ saddr->sa_family);
+ break;
+ }
+
+ snprintf(buf->str, sizeof(buf->str),
+ "addr[%s]/port[%u]",
+ addr, port);
+
+ return buf->str;
+}
+
static struct socket_info *swrap_get_socket_info(int si_index)
{
return (struct socket_info *)(&(sockets[si_index].info));
@@ -2064,13 +2285,10 @@ static int convert_in_un_remote(struct socket_info *si, const struct sockaddr *i
type = u_type;
iface = (addr & 0x000000FF);
} else {
- char str[256] = {0,};
- inet_ntop(inaddr->sa_family,
- &in->sin_addr,
- str, sizeof(str));
+ struct swrap_sockaddr_buf buf = {};
SWRAP_LOG(SWRAP_LOG_WARN,
- "str[%s] prt[%u]",
- str, (unsigned)prt);
+ "%s",
+ swrap_sockaddr_string(&buf, inaddr));
errno = ENETUNREACH;
return -1;
}
@@ -2106,13 +2324,10 @@ static int convert_in_un_remote(struct socket_info *si, const struct sockaddr *i
if (IN6_ARE_ADDR_EQUAL(&cmp1, &cmp2)) {
iface = in->sin6_addr.s6_addr[15];
} else {
- char str[256] = {0,};
- inet_ntop(inaddr->sa_family,
- &in->sin6_addr,
- str, sizeof(str));
+ struct swrap_sockaddr_buf buf = {};
SWRAP_LOG(SWRAP_LOG_WARN,
- "str[%s] prt[%u]",
- str, (unsigned)prt);
+ "%s",
+ swrap_sockaddr_string(&buf, inaddr));
errno = ENETUNREACH;
return -1;
}
@@ -3984,6 +4199,7 @@ static int swrap_connect(int s, const struct sockaddr *serv_addr,
.sa_socklen = sizeof(struct sockaddr_un),
};
struct socket_info *si = find_socket_info(s);
+ struct swrap_sockaddr_buf buf = {};
int bcast = 0;
if (!si) {
@@ -4032,7 +4248,8 @@ static int swrap_connect(int s, const struct sockaddr *serv_addr,
}
SWRAP_LOG(SWRAP_LOG_TRACE,
- "connect() path=%s, fd=%d",
+ "connect(%s) path=%s, fd=%d",
+ swrap_sockaddr_string(&buf, serv_addr),
un_addr.sa.un.sun_path, s);
@@ -4098,6 +4315,8 @@ static int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
.sa_socklen = sizeof(struct sockaddr_un),
};
struct socket_info *si = find_socket_info(s);
+ struct swrap_sockaddr_buf buf = {};
+ int ret_errno = errno;
int bind_error = 0;
#if 0 /* FIXME */
bool in_use;
@@ -4155,7 +4374,7 @@ static int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
}
if (bind_error != 0) {
- errno = bind_error;
+ ret_errno = bind_error;
ret = -1;
goto out;
}
@@ -4179,16 +4398,21 @@ static int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
1,
&si->bcast);
if (ret == -1) {
+ ret_errno = errno;
goto out;
}
unlink(un_addr.sa.un.sun_path);
ret = libc_bind(s, &un_addr.sa.s, un_addr.sa_socklen);
+ if (ret == -1) {
+ ret_errno = errno;
+ }
SWRAP_LOG(SWRAP_LOG_TRACE,
- "bind() path=%s, fd=%d",
- un_addr.sa.un.sun_path, s);
+ "bind(%s) path=%s, fd=%d ret=%d ret_errno=%d",
+ swrap_sockaddr_string(&buf, myaddr),
+ un_addr.sa.un.sun_path, s, ret, ret_errno);
if (ret == 0) {
si->bound = 1;
@@ -4196,7 +4420,7 @@ static int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
out:
SWRAP_UNLOCK_SI(si);
-
+ errno = ret_errno;
return ret;
}
@@ -6120,6 +6344,7 @@ static ssize_t swrap_sendmsg_before(int fd,
{
size_t i, len = 0;
ssize_t ret = -1;
+ struct swrap_sockaddr_buf buf = {};
if (to_un) {
*to_un = NULL;
@@ -6181,6 +6406,10 @@ static ssize_t swrap_sendmsg_before(int fd,
msg->msg_name = NULL;
msg->msg_namelen = 0;
}
+ SWRAP_LOG(SWRAP_LOG_TRACE,
+ "connected(%s) fd=%d",
+ swrap_sockaddr_string(&buf, &si->peername.sa.s),
+ fd);
} else {
const struct sockaddr *msg_name;
msg_name = (const struct sockaddr *)msg->msg_name;
@@ -6235,6 +6464,11 @@ static ssize_t swrap_sendmsg_before(int fd,
goto out;
}
+ SWRAP_LOG(SWRAP_LOG_TRACE,
+ "deferred connect(%s) path=%s, fd=%d",
+ swrap_sockaddr_string(&buf, &si->peername.sa.s),
+ tmp_un->sun_path, fd);
+
ret = libc_connect(fd,
(struct sockaddr *)(void *)tmp_un,
sizeof(*tmp_un));
@@ -7136,6 +7370,219 @@ ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)
}
/****************************************************************************
+ * RECVMMSG
+ ***************************************************************************/
+
+#ifdef HAVE_RECVMMSG
+#if defined(HAVE_RECVMMSG_SSIZE_T_CONST_TIMEOUT)
+/* FreeBSD */
+static ssize_t swrap_recvmmsg(int s, struct mmsghdr *omsgvec, size_t _vlen, int flags, const struct timespec *timeout)
+#elif defined(HAVE_RECVMMSG_CONST_TIMEOUT)
+/* Linux legacy glibc < 2.21 */
+static int swrap_recvmmsg(int s, struct mmsghdr *omsgvec, unsigned int _vlen, int flags, const struct timespec *timeout)
+#else
+/* Linux glibc >= 2.21 */
+static int swrap_recvmmsg(int s, struct mmsghdr *omsgvec, unsigned int _vlen, int flags, struct timespec *timeout)
+#endif
+{
+ struct socket_info *si = find_socket_info(s);
+#define __SWRAP_RECVMMSG_MAX_VLEN 16
+ struct mmsghdr msgvec[__SWRAP_RECVMMSG_MAX_VLEN] = {};
+ struct {
+ struct iovec iov;
+ struct swrap_address from_addr;
+ struct swrap_address convert_addr;
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+ size_t msg_ctrllen_filled;
+ size_t msg_ctrllen_left;
+#endif
+ } tmp[__SWRAP_RECVMMSG_MAX_VLEN] = {};
+ int vlen;
+ int i;
+ int ret;
+ int rc;
+ int saved_errno;
+
+ if (_vlen > __SWRAP_RECVMMSG_MAX_VLEN) {
+ vlen = __SWRAP_RECVMMSG_MAX_VLEN;
+ } else {
+ vlen = _vlen;
+ }
+
+ if (si == NULL) {
+ uint8_t *tmp_control[__SWRAP_RECVMMSG_MAX_VLEN] = { NULL, };
+
+ for (i = 0; i < vlen; i++) {
+ struct msghdr *omsg = &omsgvec[i].msg_hdr;
+ struct msghdr *msg = &msgvec[i].msg_hdr;
+
+ rc = swrap_recvmsg_before_unix(omsg, msg,
+ &tmp_control[i]);
+ if (rc < 0) {
+ ret = rc;
+ goto fail_libc;
+ }
+ }
+
+ ret = libc_recvmmsg(s, msgvec, vlen, flags, timeout);
+ if (ret < 0) {
+ goto fail_libc;
+ }
+
+ for (i = 0; i < ret; i++) {
+ omsgvec[i].msg_len = msgvec[i].msg_len;
+ }
+
+fail_libc:
+ saved_errno = errno;
+ for (i = 0; i < vlen; i++) {
+ struct msghdr *omsg = &omsgvec[i].msg_hdr;
+ struct msghdr *msg = &msgvec[i].msg_hdr;
+
+ if (i == 0 || i < ret) {
+ swrap_recvmsg_after_unix(msg, &tmp_control[i], omsg, ret);
+ }
+ SAFE_FREE(tmp_control[i]);
+ }
+ errno = saved_errno;
+
+ return ret;
+ }
+
+ for (i = 0; i < vlen; i++) {
+ struct msghdr *omsg = &omsgvec[i].msg_hdr;
+ struct msghdr *msg = &msgvec[i].msg_hdr;
+
+ tmp[i].from_addr.sa_socklen = sizeof(struct sockaddr_un);
+ tmp[i].convert_addr.sa_socklen = sizeof(struct sockaddr_storage);
+
+ msg->msg_name = &tmp[i].from_addr.sa; /* optional address */
+ msg->msg_namelen = tmp[i].from_addr.sa_socklen; /* size of address */
+ msg->msg_iov = omsg->msg_iov; /* scatter/gather array */
+ msg->msg_iovlen = omsg->msg_iovlen; /* # elements in msg_iov */
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+ tmp[i].msg_ctrllen_filled = 0;
+ tmp[i].msg_ctrllen_left = omsg->msg_controllen;
+
+ msg->msg_control = omsg->msg_control; /* ancillary data, see below */
+ msg->msg_controllen = omsg->msg_controllen; /* ancillary data buffer len */
+ msg->msg_flags = omsg->msg_flags; /* flags on received message */
+#endif
+
+ rc = swrap_recvmsg_before(s, si, msg, &tmp[i].iov);
+ if (rc < 0) {
+ ret = rc;
+ goto fail_swrap;
+ }
+ }
+
+ ret = libc_recvmmsg(s, msgvec, vlen, flags, timeout);
+ if (ret < 0) {
+ goto fail_swrap;
+ }
+
+ for (i = 0; i < ret; i++) {
+ omsgvec[i].msg_len = msgvec[i].msg_len;
+ }
+
+fail_swrap:
+
+ saved_errno = errno;
+ for (i = 0; i < vlen; i++) {
+ struct msghdr *omsg = &omsgvec[i].msg_hdr;
+ struct msghdr *msg = &msgvec[i].msg_hdr;
+
+ if (!(i == 0 || i < ret)) {
+ break;
+ }
+
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+ tmp[i].msg_ctrllen_filled += msg->msg_controllen;
+ tmp[i].msg_ctrllen_left -= msg->msg_controllen;
+
+ if (omsg->msg_control != NULL) {
+ uint8_t *p;
+
+ p = omsg->msg_control;
+ p += tmp[i].msg_ctrllen_filled;
+
+ msg->msg_control = p;
+ msg->msg_controllen = tmp[i].msg_ctrllen_left;
+ } else {
+ msg->msg_control = NULL;
+ msg->msg_controllen = 0;
+ }
+#endif
+
+ /*
+ * We convert the unix address to a IP address so we need a buffer
+ * which can store the address in case of SOCK_DGRAM, see below.
+ */
+ msg->msg_name = &tmp[i].convert_addr.sa;
+ msg->msg_namelen = tmp[i].convert_addr.sa_socklen;
+
+ swrap_recvmsg_after(s, si, msg,
+ &tmp[i].from_addr.sa.un,
+ tmp[i].from_addr.sa_socklen,
+ ret);
+
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+ if (omsg->msg_control != NULL) {
+ /* msg->msg_controllen = space left */
+ tmp[i].msg_ctrllen_left = msg->msg_controllen;
+ tmp[i].msg_ctrllen_filled = omsg->msg_controllen - tmp[i].msg_ctrllen_left;
+ }
+
+ /* Update the original message length */
+ omsg->msg_controllen = tmp[i].msg_ctrllen_filled;
+ omsg->msg_flags = msg->msg_flags;
+#endif
+ omsg->msg_iovlen = msg->msg_iovlen;
+
+ SWRAP_LOCK_SI(si);
+
+ /*
+ * From the manpage:
+ *
+ * The msg_name field points to a caller-allocated buffer that is
+ * used to return the source address if the socket is unconnected. The
+ * caller should set msg_namelen to the size of this buffer before this
+ * call; upon return from a successful call, msg_name will contain the
+ * length of the returned address. If the application does not need
+ * to know the source address, msg_name can be specified as NULL.
+ */
+ if (si->type == SOCK_STREAM) {
+ omsg->msg_namelen = 0;
+ } else if (omsg->msg_name != NULL &&
+ omsg->msg_namelen != 0 &&
+ omsg->msg_namelen >= msg->msg_namelen) {
+ memcpy(omsg->msg_name, msg->msg_name, msg->msg_namelen);
+ omsg->msg_namelen = msg->msg_namelen;
+ }
+
+ SWRAP_UNLOCK_SI(si);
+ }
+ errno = saved_errno;
+
+ return ret;
+}
+
+#if defined(HAVE_RECVMMSG_SSIZE_T_CONST_TIMEOUT)
+/* FreeBSD */
+ssize_t recvmmsg(int sockfd, struct mmsghdr *msgvec, size_t vlen, int flags, const struct timespec *timeout)
+#elif defined(HAVE_RECVMMSG_CONST_TIMEOUT)
+/* Linux legacy glibc < 2.21 */
+int recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, const struct timespec *timeout)
+#else
+/* Linux glibc >= 2.21 */
+int recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, struct timespec *timeout)
+#endif
+{
+ return swrap_recvmmsg(sockfd, msgvec, vlen, flags, timeout);
+}
+#endif /* HAVE_RECVMMSG */
+
+/****************************************************************************
* SENDMSG
***************************************************************************/
@@ -7307,6 +7754,249 @@ ssize_t sendmsg(int s, const struct msghdr *omsg, int flags)
}
/****************************************************************************
+ * SENDMMSG
+ ***************************************************************************/
+
+#ifdef HAVE_SENDMMSG
+#if defined(HAVE_SENDMMSG_SSIZE_T)
+/* FreeBSD */
+static ssize_t swrap_sendmmsg(int s, struct mmsghdr *omsgvec, size_t _vlen, int flags)
+#else
+/* Linux */
+static int swrap_sendmmsg(int s, struct mmsghdr *omsgvec, unsigned int _vlen, int flags)
+#endif
+{
+ struct socket_info *si = find_socket_info(s);
+#define __SWRAP_SENDMMSG_MAX_VLEN 16
+ struct mmsghdr msgvec[__SWRAP_SENDMMSG_MAX_VLEN] = {};
+ struct {
+ struct iovec iov;
+ struct sockaddr_un un_addr;
+ const struct sockaddr_un *to_un;
+ const struct sockaddr *to;
+ int bcast;
+ } tmp[__SWRAP_SENDMMSG_MAX_VLEN] = {};
+ int vlen;
+ int i;
+ char *swrap_dir = NULL;
+ int connected = 0;
+ int found_bcast = 0;
+ int ret;
+ int rc;
+ int saved_errno;
+
+ if (_vlen > __SWRAP_SENDMMSG_MAX_VLEN) {
+ vlen = __SWRAP_SENDMMSG_MAX_VLEN;
+ } else {
+ vlen = _vlen;
+ }
+
+ if (!si) {
+ int scm_rights_pipe_fd[__SWRAP_SENDMMSG_MAX_VLEN];
+
+ for (i = 0; i < __SWRAP_SENDMMSG_MAX_VLEN; i++) {
+ scm_rights_pipe_fd[i] = -1;
+ }
+
+ for (i = 0; i < vlen; i++) {
+ struct msghdr *omsg = &omsgvec[i].msg_hdr;
+ struct msghdr *msg = &msgvec[i].msg_hdr;
+
+ rc = swrap_sendmsg_before_unix(omsg, msg,
+ &scm_rights_pipe_fd[i]);
+ if (rc < 0) {
+ ret = rc;
+ goto fail_libc;
+ }
+ }
+
+ ret = libc_sendmmsg(s, msgvec, vlen, flags);
+ if (ret < 0) {
+ goto fail_libc;
+ }
+
+ for (i = 0; i < ret; i++) {
+ omsgvec[i].msg_len = msgvec[i].msg_len;
+ }
+
+fail_libc:
+ saved_errno = errno;
+ for (i = 0; i < vlen; i++) {
+ struct msghdr *msg = &msgvec[i].msg_hdr;
+
+ swrap_sendmsg_after_unix(msg, ret,
+ scm_rights_pipe_fd[i]);
+ }
+ errno = saved_errno;
+
+ return ret;
+ }
+
+ SWRAP_LOCK_SI(si);
+ connected = si->connected;
+ SWRAP_UNLOCK_SI(si);
+
+ for (i = 0; i < vlen; i++) {
+ struct msghdr *omsg = &omsgvec[i].msg_hdr;
+ struct msghdr *msg = &msgvec[i].msg_hdr;
+
+ if (connected == 0) {
+ msg->msg_name = omsg->msg_name; /* optional address */
+ msg->msg_namelen = omsg->msg_namelen; /* size of address */
+ }
+ msg->msg_iov = omsg->msg_iov; /* scatter/gather array */
+ msg->msg_iovlen = omsg->msg_iovlen; /* # elements in msg_iov */
+
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+ if (omsg->msg_controllen > 0 && omsg->msg_control != NULL) {
+ uint8_t *cmbuf = NULL;
+ size_t cmlen = 0;
+
+ rc = swrap_sendmsg_filter_cmsghdr(omsg, &cmbuf, &cmlen);
+ if (rc < 0) {
+ ret = rc;
+ goto fail_swrap;
+ }
+
+ if (cmlen != 0) {
+ msg->msg_control = cmbuf;
+ msg->msg_controllen = cmlen;
+ }
+ }
+ msg->msg_flags = omsg->msg_flags; /* flags on received message */
+#endif
+
+ rc = swrap_sendmsg_before(s, si, msg,
+ &tmp[i].iov,
+ &tmp[i].un_addr,
+ &tmp[i].to_un,
+ &tmp[i].to,
+ &tmp[i].bcast);
+ if (rc < 0) {
+ ret = rc;
+ goto fail_swrap;
+ }
+
+ if (tmp[i].bcast) {
+ found_bcast = 1;
+ }
+ }
+
+ if (found_bcast) {
+
+ swrap_dir = socket_wrapper_dir();
+ if (swrap_dir == NULL) {
+ ret = -1;
+ goto fail_swrap;
+ }
+
+ for (i = 0; i < vlen; i++) {
+ struct msghdr *msg = &msgvec[i].msg_hdr;
+ struct sockaddr_un *un_addr = &tmp[i].un_addr;
+ const struct sockaddr *to = tmp[i].to;
+ struct stat st;
+ unsigned int iface;
+ unsigned int prt = ntohs(((const struct sockaddr_in *)(const void *)to)->sin_port);
+ char type;
+ size_t l, len = 0;
+ uint8_t *buf;
+ off_t ofs = 0;
+ size_t avail = 0;
+ size_t remain;
+
+ for (l = 0; l < (size_t)msg->msg_iovlen; l++) {
+ avail += msg->msg_iov[l].iov_len;
+ }
+
+ len = avail;
+ remain = avail;
+
+ /* we capture it as one single packet */
+ buf = (uint8_t *)malloc(remain);
+ if (!buf) {
+ ret = -1;
+ goto fail_swrap;
+ }
+
+ for (l = 0; l < (size_t)msg->msg_iovlen; l++) {
+ size_t this_time = MIN(remain, (size_t)msg->msg_iov[l].iov_len);
+ memcpy(buf + ofs,
+ msg->msg_iov[l].iov_base,
+ this_time);
+ ofs += this_time;
+ remain -= this_time;
+ }
+
+ type = SOCKET_TYPE_CHAR_UDP;
+
+ for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) {
+ swrap_un_path(un_addr, swrap_dir, type, iface, prt);
+ if (stat(un_addr->sun_path, &st) != 0) continue;
+
+ msg->msg_name = un_addr; /* optional address */
+ msg->msg_namelen = sizeof(*un_addr); /* size of address */
+
+ /*
+ * ignore the any errors in broadcast sends and
+ * do a single sendmsg instead of sendmmsg
+ */
+ libc_sendmsg(s, msg, flags);
+ }
+
+ SWRAP_LOCK_SI(si);
+ swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
+ SWRAP_UNLOCK_SI(si);
+
+ SAFE_FREE(buf);
+
+ msgvec[i].msg_len = len;
+ }
+
+ ret = vlen;
+ goto bcast_done;
+ }
+
+ ret = libc_sendmmsg(s, msgvec, vlen, flags);
+ if (ret < 0) {
+ goto fail_swrap;
+ }
+
+bcast_done:
+ for (i = 0; i < ret; i++) {
+ omsgvec[i].msg_len = msgvec[i].msg_len;
+ }
+
+fail_swrap:
+ saved_errno = errno;
+ for (i = 0; i < vlen; i++) {
+ struct msghdr *msg = &msgvec[i].msg_hdr;
+
+ if (i == 0 || i < ret) {
+ swrap_sendmsg_after(s, si, msg, tmp[i].to, ret);
+ }
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+ SAFE_FREE(msg->msg_control);
+#endif
+ }
+ SAFE_FREE(swrap_dir);
+ errno = saved_errno;
+
+ return ret;
+}
+
+#if defined(HAVE_SENDMMSG_SSIZE_T)
+/* FreeBSD */
+ssize_t sendmmsg(int s, struct mmsghdr *msgvec, size_t vlen, int flags)
+#else
+/* Linux */
+int sendmmsg(int s, struct mmsghdr *msgvec, unsigned int vlen, int flags)
+#endif
+{
+ return swrap_sendmmsg(s, msgvec, vlen, flags);
+}
+#endif /* HAVE_SENDMMSG */
+
+/****************************************************************************
* READV
***************************************************************************/
@@ -7773,6 +8463,169 @@ int pledge(const char *promises, const char *paths[])
}
#endif /* HAVE_PLEDGE */
+#ifdef HAVE_SYSCALL
+static bool swrap_is_swrap_related_syscall(long int sysno)
+{
+ switch (sysno) {
+#ifdef SYS_close
+ case SYS_close:
+ return true;
+#endif /* SYS_close */
+
+#ifdef SYS_recvmmsg
+ case SYS_recvmmsg:
+ return true;
+#endif /* SYS_recvmmsg */
+
+#ifdef SYS_sendmmsg
+ case SYS_sendmmsg:
+ return true;
+#endif /* SYS_sendmmsg */
+
+ default:
+ return false;
+ }
+}
+
+static long int swrap_syscall(long int sysno, va_list vp)
+{
+ long int rc;
+
+ switch (sysno) {
+#ifdef SYS_close
+ case SYS_close:
+ {
+ int fd = (int)va_arg(vp, int);
+
+ SWRAP_LOG(SWRAP_LOG_TRACE,
+ "calling swrap_close syscall %lu",
+ sysno);
+ rc = swrap_close(fd);
+ }
+ break;
+#endif /* SYS_close */
+
+#ifdef SYS_recvmmsg
+ case SYS_recvmmsg:
+ {
+ int fd = (int)va_arg(vp, int);
+ struct mmsghdr *msgvec = va_arg(vp, struct mmsghdr *);
+ unsigned int vlen = va_arg(vp, unsigned int);
+ int flags = va_arg(vp, int);
+ struct timespec *timeout = va_arg(vp, struct timespec *);
+
+ SWRAP_LOG(SWRAP_LOG_TRACE,
+ "calling swrap_recvmmsg syscall %lu",
+ sysno);
+ rc = swrap_recvmmsg(fd, msgvec, vlen, flags, timeout);
+ }
+ break;
+#endif /* SYS_recvmmsg */
+
+#ifdef SYS_sendmmsg
+ case SYS_sendmmsg:
+ {
+ int fd = (int)va_arg(vp, int);
+ struct mmsghdr *msgvec = va_arg(vp, struct mmsghdr *);
+ unsigned int vlen = va_arg(vp, unsigned int);
+ int flags = va_arg(vp, int);
+
+ SWRAP_LOG(SWRAP_LOG_TRACE,
+ "calling swrap_sendmmsg syscall %lu",
+ sysno);
+ rc = swrap_sendmmsg(fd, msgvec, vlen, flags);
+ }
+ break;
+#endif /* SYS_sendmmsg */
+
+ default:
+ rc = -1;
+ errno = ENOSYS;
+ break;
+ }
+
+ return rc;
+}
+
+#ifdef HAVE_SYSCALL_INT
+int syscall(int sysno, ...)
+#else
+long int syscall(long int sysno, ...)
+#endif
+{
+#ifdef HAVE_SYSCALL_INT
+ int rc;
+#else
+ long int rc;
+#endif
+ va_list va;
+
+ va_start(va, sysno);
+
+ /*
+ * We should only handle the syscall numbers
+ * we care about...
+ */
+ if (!swrap_is_swrap_related_syscall(sysno)) {
+ /*
+ * We need to give socket_wrapper a
+ * chance to take over...
+ */
+ if (swrap_uwrap_syscall_valid(sysno)) {
+ rc = swrap_uwrap_syscall_va(sysno, va);
+ va_end(va);
+ return rc;
+ }
+
+ rc = libc_vsyscall(sysno, va);
+ va_end(va);
+ return rc;
+ }
+
+ if (!socket_wrapper_enabled()) {
+ rc = libc_vsyscall(sysno, va);
+ va_end(va);
+ return rc;
+ }
+
+ rc = swrap_syscall(sysno, va);
+ va_end(va);
+
+ return rc;
+}
+
+/* used by uid_wrapper */
+bool socket_wrapper_syscall_valid(long int sysno);
+bool socket_wrapper_syscall_valid(long int sysno)
+{
+ if (!swrap_is_swrap_related_syscall(sysno)) {
+ return false;
+ }
+
+ if (!socket_wrapper_enabled()) {
+ return false;
+ }
+
+ return true;
+}
+
+/* used by uid_wrapper */
+long int socket_wrapper_syscall_va(long int sysno, va_list va);
+long int socket_wrapper_syscall_va(long int sysno, va_list va)
+{
+ if (!swrap_is_swrap_related_syscall(sysno)) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ if (!socket_wrapper_enabled()) {
+ return libc_vsyscall(sysno, va);
+ }
+
+ return swrap_syscall(sysno, va);
+}
+#endif /* HAVE_SYSCALL */
+
static void swrap_thread_prepare(void)
{
/*
diff --git a/third_party/socket_wrapper/wscript b/third_party/socket_wrapper/wscript
index b87072038f8..af6eb303e0a 100644
--- a/third_party/socket_wrapper/wscript
+++ b/third_party/socket_wrapper/wscript
@@ -53,6 +53,7 @@ def configure(conf):
conf.CHECK_FUNCS('bindresvport')
conf.CHECK_FUNCS('pledge')
conf.CHECK_FUNCS('accept4')
+ conf.CHECK_FUNCS('sendmmsg recvmmsg')
conf.CHECK_FUNCS('__close_nocancel')
conf.CHECK_FUNCS_IN('bind',
@@ -64,6 +65,19 @@ def configure(conf):
'int accept(int s, struct sockaddr *addr, Psocklen_t addrlen)',
define='HAVE_ACCEPT_PSOCKLEN_T', headers='sys/types.h sys/socket.h')
+ # Linux legacy glibc < 2.21
+ conf.CHECK_C_PROTOTYPE('recvmmsg',
+ 'int recvmmsg(int __fd, struct mmsghdr *__vmessages, unsigned int __vlen, int __flags, const struct timespec *__tmo)',
+ define='HAVE_RECVMMSG_CONST_TIMEOUT', headers='sys/types.h sys/socket.h')
+ # FreeBSD
+ conf.CHECK_C_PROTOTYPE('recvmmsg',
+ 'ssize_t recvmmsg(int __fd, struct mmsghdr * __restrict __vmessages, size_t __vlen, int __flags, const struct timespec * __restrict __tmo)',
+ define='HAVE_RECVMMSG_SSIZE_T_CONST_TIMEOUT', headers='sys/types.h sys/socket.h')
+ # FreeBSD
+ conf.CHECK_C_PROTOTYPE('sendmmsg',
+ 'ssize_t sendmmsg(int __fd, struct mmsghdr * __restrict __vmessages, size_t __vlen, int __flags)',
+ define='HAVE_SENDMMSG_SSIZE_T', headers='sys/types.h sys/socket.h')
+
conf.CHECK_C_PROTOTYPE('ioctl',
'int ioctl(int s, int r, ...)',
define='HAVE_IOCTL_INT', headers='unistd.h sys/ioctl.h')