From 10c198827d977e07b411897556578d3aedce2184 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 17 Feb 2021 12:57:01 +0100 Subject: [PATCH] third_party: Update socket_wrapper to version 1.3.3 This fixes a deadlock abort() when SOCKET_WRAPPER_KEEP_PCAP=1 is used. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14640 Signed-off-by: Stefan Metzmacher Reviewed-by: Andreas Schneider Autobuild-User(master): Stefan Metzmacher Autobuild-Date(master): Wed Mar 17 23:53:04 UTC 2021 on sn-devel-184 --- buildtools/wafsamba/samba_third_party.py | 2 +- third_party/socket_wrapper/socket_wrapper.c | 157 +++++++++++++------- third_party/socket_wrapper/socket_wrapper.h | 89 +++++++++++ third_party/socket_wrapper/wscript | 3 +- 4 files changed, 197 insertions(+), 54 deletions(-) create mode 100644 third_party/socket_wrapper/socket_wrapper.h diff --git a/buildtools/wafsamba/samba_third_party.py b/buildtools/wafsamba/samba_third_party.py index d4d8f7a8dd0..1c027cb6870 100644 --- a/buildtools/wafsamba/samba_third_party.py +++ b/buildtools/wafsamba/samba_third_party.py @@ -24,7 +24,7 @@ Build.BuildContext.CHECK_CMOCKA = CHECK_CMOCKA @conf def CHECK_SOCKET_WRAPPER(conf): - return conf.CHECK_BUNDLED_SYSTEM_PKG('socket_wrapper', minversion='1.3.2') + return conf.CHECK_BUNDLED_SYSTEM_PKG('socket_wrapper', minversion='1.3.3') Build.BuildContext.CHECK_SOCKET_WRAPPER = CHECK_SOCKET_WRAPPER @conf diff --git a/third_party/socket_wrapper/socket_wrapper.c b/third_party/socket_wrapper/socket_wrapper.c index a950a0a0dbc..44cfad8c6cf 100644 --- a/third_party/socket_wrapper/socket_wrapper.c +++ b/third_party/socket_wrapper/socket_wrapper.c @@ -2,8 +2,8 @@ * BSD 3-Clause License * * Copyright (c) 2005-2008, Jelmer Vernooij - * Copyright (c) 2006-2018, Stefan Metzmacher - * Copyright (c) 2013-2018, Andreas Schneider + * Copyright (c) 2006-2021, Stefan Metzmacher + * Copyright (c) 2013-2021, Andreas Schneider * Copyright (c) 2014-2017, Michael Adam * Copyright (c) 2016-2018, Anoop C S * All rights reserved. @@ -86,6 +86,8 @@ #endif #include +#include "socket_wrapper.h" + enum swrap_dbglvl_e { SWRAP_LOG_ERROR = 0, SWRAP_LOG_WARN, @@ -370,7 +372,7 @@ static pthread_mutex_t autobind_start_mutex = PTHREAD_MUTEX_INITIALIZER; /* Mutex to guard the initialization of array of socket_info structures */ static pthread_mutex_t sockets_mutex = PTHREAD_MUTEX_INITIALIZER; -/* Mutex to guard the socket reset in swrap_close() and swrap_remove_stale() */ +/* Mutex to guard the socket reset in swrap_remove_wrapper() */ static pthread_mutex_t socket_reset_mutex = PTHREAD_MUTEX_INITIALIZER; /* Mutex to synchronize access to first free index in socket_info array */ @@ -392,8 +394,6 @@ static pthread_mutex_t mtu_update_mutex = PTHREAD_MUTEX_INITIALIZER; /* Function prototypes */ -bool socket_wrapper_enabled(void); - #if ! defined(HAVE_CONSTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_INIT) /* xlC and other oldschool compilers support (only) this */ #pragma init (swrap_constructor) @@ -492,6 +492,9 @@ typedef int (*__libc_bind)(int sockfd, const struct sockaddr *addr, socklen_t addrlen); typedef int (*__libc_close)(int fd); +#ifdef HAVE___CLOSE_NOCANCEL +typedef int (*__libc___close_nocancel)(int fd); +#endif typedef int (*__libc_connect)(int sockfd, const struct sockaddr *addr, socklen_t addrlen); @@ -572,6 +575,9 @@ struct swrap_libc_symbols { #endif SWRAP_SYMBOL_ENTRY(bind); SWRAP_SYMBOL_ENTRY(close); +#ifdef HAVE___CLOSE_NOCANCEL + SWRAP_SYMBOL_ENTRY(__close_nocancel); +#endif SWRAP_SYMBOL_ENTRY(connect); SWRAP_SYMBOL_ENTRY(dup); SWRAP_SYMBOL_ENTRY(dup2); @@ -851,6 +857,15 @@ static int libc_close(int fd) return swrap.libc.symbols._libc_close.f(fd); } +#ifdef HAVE___CLOSE_NOCANCEL +static int libc___close_nocancel(int fd) +{ + swrap_bind_symbol_all(); + + return swrap.libc.symbols._libc___close_nocancel.f(fd); +} +#endif /* HAVE___CLOSE_NOCANCEL */ + static int libc_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) @@ -1199,6 +1214,9 @@ static void __swrap_bind_symbol_all_once(void) #endif swrap_bind_symbol_libsocket(bind); swrap_bind_symbol_libc(close); +#ifdef HAVE___CLOSE_NOCANCEL + swrap_bind_symbol_libc(__close_nocancel); +#endif swrap_bind_symbol_libsocket(connect); swrap_bind_symbol_libc(dup); swrap_bind_symbol_libc(dup2); @@ -2027,6 +2045,13 @@ 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)); + SWRAP_LOG(SWRAP_LOG_WARN, + "str[%s] prt[%u]", + str, (unsigned)prt); errno = ENETUNREACH; return -1; } @@ -2062,6 +2087,13 @@ 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)); + SWRAP_LOG(SWRAP_LOG_WARN, + "str[%s] prt[%u]", + str, (unsigned)prt); errno = ENETUNREACH; return -1; } @@ -2390,46 +2422,7 @@ static bool check_addr_port_in_use(const struct sockaddr *sa, socklen_t len) } #endif -static void swrap_remove_stale(int fd) -{ - struct socket_info *si; - int si_index; - - SWRAP_LOG(SWRAP_LOG_TRACE, "remove stale wrapper for %d", fd); - - swrap_mutex_lock(&socket_reset_mutex); - - si_index = find_socket_info_index(fd); - if (si_index == -1) { - swrap_mutex_unlock(&socket_reset_mutex); - return; - } - - reset_socket_info_index(fd); - - si = swrap_get_socket_info(si_index); - - swrap_mutex_lock(&first_free_mutex); - SWRAP_LOCK_SI(si); - - swrap_dec_refcount(si); - - if (swrap_get_refcount(si) > 0) { - goto out; - } - - if (si->un_addr.sun_path[0] != '\0') { - unlink(si->un_addr.sun_path); - } - - swrap_set_next_free(si, first_free); - first_free = si_index; - -out: - SWRAP_UNLOCK_SI(si); - swrap_mutex_unlock(&first_free_mutex); - swrap_mutex_unlock(&socket_reset_mutex); -} +static void swrap_remove_stale(int fd); static int sockaddr_convert_to_un(struct socket_info *si, const struct sockaddr *in_addr, @@ -2990,7 +2983,7 @@ static int swrap_pcap_get_fd(const char *fname) file_hdr.frame_max_len = SWRAP_FRAME_LENGTH_MAX; file_hdr.link_type = 0x0065; /* 101 RAW IP */ - if (write(fd, &file_hdr, sizeof(file_hdr)) != sizeof(file_hdr)) { + if (libc_write(fd, &file_hdr, sizeof(file_hdr)) != sizeof(file_hdr)) { libc_close(fd); fd = -1; } @@ -3325,7 +3318,7 @@ static void swrap_pcap_dump_packet(struct socket_info *si, fd = swrap_pcap_get_fd(file_name); if (fd != -1) { - if (write(fd, packet, packet_len) != (ssize_t)packet_len) { + if (libc_write(fd, packet, packet_len) != (ssize_t)packet_len) { free(packet); goto done; } @@ -5532,7 +5525,7 @@ static int swrap_sendmsg_unix_scm_rights(const struct cmsghdr *cmsg, return -1; } - sret = write(pipefd[1], &info, sizeof(info)); + sret = libc_write(pipefd[1], &info, sizeof(info)); if (sret != sizeof(info)) { int saved_errno = errno; if (sret != -1) { @@ -7403,10 +7396,13 @@ ssize_t writev(int s, const struct iovec *vector, int count) * CLOSE ***************************/ -static int swrap_close(int fd) +static int swrap_remove_wrapper(const char *__func_name, + int (*__close_fd_fn)(int fd), + int fd) { struct socket_info *si = NULL; int si_index; + int ret_errno = errno; int ret; swrap_mutex_lock(&socket_reset_mutex); @@ -7414,10 +7410,10 @@ static int swrap_close(int fd) si_index = find_socket_info_index(fd); if (si_index == -1) { swrap_mutex_unlock(&socket_reset_mutex); - return libc_close(fd); + return __close_fd_fn(fd); } - SWRAP_LOG(SWRAP_LOG_TRACE, "Close wrapper for fd=%d", fd); + swrap_log(SWRAP_LOG_TRACE, __func_name, "Remove wrapper for fd=%d", fd); reset_socket_info_index(fd); si = swrap_get_socket_info(si_index); @@ -7425,7 +7421,10 @@ static int swrap_close(int fd) swrap_mutex_lock(&first_free_mutex); SWRAP_LOCK_SI(si); - ret = libc_close(fd); + ret = __close_fd_fn(fd); + if (ret == -1) { + ret_errno = errno; + } swrap_dec_refcount(si); @@ -7460,14 +7459,68 @@ out: swrap_mutex_unlock(&first_free_mutex); swrap_mutex_unlock(&socket_reset_mutex); + errno = ret_errno; return ret; } +static int swrap_noop_close(int fd) +{ + (void)fd; /* unused */ + return 0; +} + +static void swrap_remove_stale(int fd) +{ + swrap_remove_wrapper(__func__, swrap_noop_close, fd); +} + +/* + * This allows socket_wrapper aware applications to + * indicate that the given fd does not belong to + * an inet socket. + * + * We already overload a lot of unrelated functions + * like eventfd(), timerfd_create(), ... in order to + * call swrap_remove_stale() on the returned fd, but + * we'll never be able to handle all possible syscalls. + * + * socket_wrapper_indicate_no_inet_fd() gives them a way + * to do the same. + * + * We don't export swrap_remove_stale() in order to + * make it easier to analyze SOCKET_WRAPPER_DEBUGLEVEL=3 + * log files. + */ +void socket_wrapper_indicate_no_inet_fd(int fd) +{ + swrap_remove_wrapper(__func__, swrap_noop_close, fd); +} + +static int swrap_close(int fd) +{ + return swrap_remove_wrapper(__func__, libc_close, fd); +} + int close(int fd) { return swrap_close(fd); } +#ifdef HAVE___CLOSE_NOCANCEL + +static int swrap___close_nocancel(int fd) +{ + return swrap_remove_wrapper(__func__, libc___close_nocancel, fd); +} + +int __close_nocancel(int fd); +int __close_nocancel(int fd) +{ + return swrap___close_nocancel(fd); +} + +#endif /* HAVE___CLOSE_NOCANCEL */ + /**************************** * DUP ***************************/ diff --git a/third_party/socket_wrapper/socket_wrapper.h b/third_party/socket_wrapper/socket_wrapper.h new file mode 100644 index 00000000000..3ec5031f7d1 --- /dev/null +++ b/third_party/socket_wrapper/socket_wrapper.h @@ -0,0 +1,89 @@ +/* + * BSD 3-Clause License + * + * Copyright (c) 2005-2008, Jelmer Vernooij + * Copyright (c) 2006-2021, Stefan Metzmacher + * Copyright (c) 2013-2021, Andreas Schneider + * Copyright (c) 2014-2017, Michael Adam + * Copyright (c) 2016-2018, Anoop C S + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the author nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __SOCKET_WRAPPER_H__ +#define __SOCKET_WRAPPER_H__ 1 + +#include + +/* + Socket wrapper advanced helpers. + + Applications with the need to alter their behaviour when + socket wrapper is active, can link use these functions. + + By default it's required for applications to use any of these + functions as libsocket_wrapper.so is injected at runtime via + LD_PRELOAD. + + Applications using these functions should link against + libsocket_wrapper_noop.so by using -lsocket_wrapper_noop, + or implement their own noop stubs. +*/ + +/* + * This returns true when socket wrapper is actively in use. + */ +bool socket_wrapper_enabled(void); + +/* + * This allows socket_wrapper aware applications to + * indicate that the given fd does not belong to + * an inet socket. + * + * socket_wrapper may not be able to intercept the __close_nocancel() + * syscall made from within libc.so. As result it's possible + * that the in memory meta date of socket_wrapper references + * stale file descriptors, which are already reused for unrelated + * kernel objects, e.g. files, directories, ... + * + * Socket wrapper already intercepts a lot of unrelated + * functions like eventfd(), timerfd_create(), ... in order + * to remove stale meta data for the returned fd, but + * it will never be able to handle all possible syscalls. + * + * socket_wrapper_indicate_no_inet_fd() gives applications a way + * to do the same, explicitly without waiting for new syscalls to + * be added to libsocket_wrapper.so. + * + * This is a no-op if socket_wrapper is not in use or + * if the there is no in memory meta data for the given fd. + */ +void socket_wrapper_indicate_no_inet_fd(int fd); + +#endif /* __SOCKET_WRAPPER_H__ */ diff --git a/third_party/socket_wrapper/wscript b/third_party/socket_wrapper/wscript index 5f237d30057..15ceefd168d 100644 --- a/third_party/socket_wrapper/wscript +++ b/third_party/socket_wrapper/wscript @@ -2,7 +2,7 @@ import os -VERSION="1.3.2" +VERSION="1.3.3" def configure(conf): if conf.CHECK_SOCKET_WRAPPER(): @@ -53,6 +53,7 @@ def configure(conf): conf.CHECK_FUNCS('bindresvport') conf.CHECK_FUNCS('pledge') conf.CHECK_FUNCS('accept4') + conf.CHECK_FUNCS('__close_nocancel') conf.CHECK_FUNCS_IN('bind', 'socket',