From: Stefan Metzmacher Date: Mon, 16 Jan 2023 18:46:13 +0000 (+0100) Subject: src/socket_wrapper.c: handle raw SYS_close, SYS_recvmmsg and SYS_sendmmsg syscall... X-Git-Tag: socket_wrapper-1.4.0~5 X-Git-Url: http://git.samba.org/?p=socket_wrapper.git;a=commitdiff_plain;h=72da1a76e78bcf9be733ec72cce7060a6e19606a src/socket_wrapper.c: handle raw SYS_close, SYS_recvmmsg and SYS_sendmmsg syscall() invocations 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 Reviewed-by: Andreas Schneider --- diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index ccf3c12..b820a65 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -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) diff --git a/config.h.cmake b/config.h.cmake index b7d189f..a637a34 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -13,9 +13,11 @@ #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 ***************************/ diff --git a/src/socket_wrapper.c b/src/socket_wrapper.c index 90ffc25..bddadbb 100644 --- a/src/socket_wrapper.c +++ b/src/socket_wrapper.c @@ -47,6 +47,12 @@ #include #include #include +#ifdef HAVE_SYS_SYSCALL_H +#include +#endif +#ifdef HAVE_SYSCALL_H +#include +#endif #include #include #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) { /*