src/socket_wrapper.c: handle raw SYS_close, SYS_recvmmsg and SYS_sendmmsg syscall...
authorStefan Metzmacher <metze@samba.org>
Mon, 16 Jan 2023 18:46:13 +0000 (19:46 +0100)
committerAndreas Schneider <asn@samba.org>
Tue, 17 Jan 2023 16:47:25 +0000 (17:47 +0100)
This fixes a problem hit by 'nsupdate -g' and bind9 (dnsutils). If bind is built
against libuv <= 1.44.2 it will not use sendmmsg/recvmmsg functions from libc
but use the corresponding syscalls directly. Newer version of libuv removed
the syscall wrappers and use sendmmsg/recvmmsg from libc.

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
ConfigureChecks.cmake
config.h.cmake
src/socket_wrapper.c

index ccf3c12cde2ab799333f90e3ebb939574802abcb..b820a65d2dd6f204466ed2cd82cb0ca5c6d50b92 100644 (file)
@@ -48,8 +48,10 @@ check_include_file(sys/filio.h HAVE_SYS_FILIO_H)
 check_include_file(sys/signalfd.h HAVE_SYS_SIGNALFD_H)
 check_include_file(sys/eventfd.h HAVE_SYS_EVENTFD_H)
 check_include_file(sys/timerfd.h HAVE_SYS_TIMERFD_H)
+check_include_file(sys/syscall.h HAVE_SYS_SYSCALL_H)
 check_include_file(gnu/lib-names.h HAVE_GNU_LIB_NAMES_H)
 check_include_file(rpc/rpc.h HAVE_RPC_RPC_H)
+check_include_file(syscall.h HAVE_SYSCALL_H)
 
 # SYMBOLS
 set(CMAKE_REQUIRED_FLAGS -D_GNU_SOURCE)
@@ -77,6 +79,7 @@ check_function_exists(_close HAVE__CLOSE)
 check_function_exists(__close_nocancel HAVE___CLOSE_NOCANCEL)
 check_function_exists(recvmmsg HAVE_RECVMMSG)
 check_function_exists(sendmmsg HAVE_SENDMMSG)
+check_function_exists(syscall HAVE_SYSCALL)
 
 if (UNIX)
     find_library(DLFCN_LIBRARY dl)
@@ -149,6 +152,17 @@ if (HAVE_EVENTFD)
         HAVE_EVENTFD_UNSIGNED_INT)
 endif (HAVE_EVENTFD)
 
+if (HAVE_SYSCALL)
+    set(CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
+
+    check_prototype_definition(syscall
+        "int syscall(int sysno, ...)"
+        "-1"
+        "unistd.h;sys/syscall.h"
+        HAVE_SYSCALL_INT)
+    set(CMAKE_REQUIRED_DEFINITIONS)
+endif (HAVE_SYSCALL)
+
 if (HAVE_RECVMMSG)
     # Linux legacy glibc < 2.21
     set(CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
index b7d189f5aaf45fa55a70221891289ab44e4d7ab0..a637a34da5afbff5a8d04147db4fed09d2727701 100644 (file)
 #cmakedefine HAVE_SYS_FILIO_H 1
 #cmakedefine HAVE_SYS_SIGNALFD_H 1
 #cmakedefine HAVE_SYS_EVENTFD_H 1
+#cmakedefine HAVE_SYS_SYSCALL_H 1
 #cmakedefine HAVE_SYS_TIMERFD_H 1
 #cmakedefine HAVE_GNU_LIB_NAMES_H 1
 #cmakedefine HAVE_RPC_RPC_H 1
+#cmakedefine HAVE_SYSCALL_H 1
 
 /**************************** STRUCTS ****************************/
 
@@ -57,6 +59,8 @@
 #cmakedefine HAVE_RECVMMSG_SSIZE_T_CONST_TIMEOUT 1
 #cmakedefine HAVE_SENDMMSG 1
 #cmakedefine HAVE_SENDMMSG_SSIZE_T 1
+#cmakedefine HAVE_SYSCALL 1
+#cmakedefine HAVE_SYSCALL_INT 1
 
 /*************************** LIBRARIES ***************************/
 
index 90ffc25805495b62adeed4147b59f354e5d3699d..bddadbbaf81b0a7e9e30ef9983280078f7f664c9 100644 (file)
 #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
@@ -581,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 { \
@@ -646,6 +655,9 @@ struct swrap_libc_symbols {
 #endif
        SWRAP_SYMBOL_ENTRY(write);
        SWRAP_SYMBOL_ENTRY(writev);
+#ifdef HAVE_SYSCALL
+       SWRAP_SYMBOL_ENTRY(syscall);
+#endif
 };
 
 struct swrap {
@@ -1283,6 +1295,34 @@ 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;
+}
+#endif /* HAVE_SYSCALL */
+
 /* DO NOT call this function during library initialization! */
 static void __swrap_bind_symbol_all_once(void)
 {
@@ -1343,6 +1383,9 @@ 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);
+#endif
 }
 
 static void swrap_bind_symbol_all(void)
@@ -8357,6 +8400,128 @@ 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)) {
+               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;
+}
+#endif /* HAVE_SYSCALL */
+
 static void swrap_thread_prepare(void)
 {
        /*