The branch, master has been updated via 181a3fa swrap: wrap __close_nocancel() if available via ba970e5 swrap: export a public socket_wrapper_indicate_no_inet_fd() helper function via efd2967 swrap: introduce a socket_wrapper_noop.so and socket_wrapper.h to provide noop stubs via 4ad5a5a swrap: split out swrap_remove_wrapper() to handle swrap_close() and swrap_remove_stale() via d28fdbf swrap: remember the libc_close() errno in swrap_close() via 167009f swrap: call libc_write() directly for internal fds via 2cf4c54 swrap: warn about unreachable addresses from 85b51c2 Bump version to 1.3.2
https://git.samba.org/?p=socket_wrapper.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 181a3fa5e4c242d72d311f5baa771c680647eda7 Author: Stefan Metzmacher <me...@samba.org> Date: Wed Feb 17 10:58:29 2021 +0100 swrap: wrap __close_nocancel() if available While it's no possible to inject swrap__close_nocancel() into libc.so.6 directly, because it's no weak symbol, it seems to be possible to inject it to other glibc libraries like libpthread.so.0, which is better than nothing. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14640 Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit ba970e5d32cceb0750eaa71fb83da3e2eef881d5 Author: Stefan Metzmacher <me...@samba.org> Date: Wed Feb 17 12:29:27 2021 +0100 swrap: export a public socket_wrapper_indicate_no_inet_fd() helper function BUG: https://bugzilla.samba.org/show_bug.cgi?id=14640 Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit efd2967e060a3a7ca3de589a23511bb38151ed8b Author: Stefan Metzmacher <me...@samba.org> Date: Wed Feb 24 12:45:26 2021 +0100 swrap: introduce a socket_wrapper_noop.so and socket_wrapper.h to provide noop stubs Applications with the need to call socket_wrapper_enabled() should link against -lsocket_wrapper_noop in order to resolve the symbol at link time. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14640 Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit 4ad5a5af0bdf94497f068f10d6c09520702fd50f Author: Stefan Metzmacher <me...@samba.org> Date: Wed Feb 17 12:14:06 2021 +0100 swrap: split out swrap_remove_wrapper() to handle swrap_close() and swrap_remove_stale() Except of closing the fd, both should do the same, even indicating a TCP close in the pcap file. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14640 Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit d28fdbf203976290e6ba97577e1979df8f99bb61 Author: Stefan Metzmacher <me...@samba.org> Date: Wed Feb 17 12:14:06 2021 +0100 swrap: remember the libc_close() errno in swrap_close() BUG: https://bugzilla.samba.org/show_bug.cgi?id=14640 Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit 167009f6ac1186aeeabffc29368bd5b375d9861f Author: Stefan Metzmacher <me...@samba.org> Date: Wed Feb 17 11:00:53 2021 +0100 swrap: call libc_write() directly for internal fds Otherwise we may deadlock with a backtrace like this: swrap_accept(): ... SWRAP_LOCK_SI(si); swrap_pcap_dump_packet() -> write() -> swrap_write() -> SWRAP_LOCK_SI(si) -> abort() This can happen if libc_open() called from swrap_pcap_get_fd() return a stale fd. This may happen if glibc calls socket() and closes it with __close_nocancel() instead of close(). BUG: https://bugzilla.samba.org/show_bug.cgi?id=14640 Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit 2cf4c543d614e3263fa261e4584716d5b7771f09 Author: Stefan Metzmacher <me...@samba.org> Date: Wed Feb 17 11:41:38 2021 +0100 swrap: warn about unreachable addresses BUG: https://bugzilla.samba.org/show_bug.cgi?id=14640 Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> ----------------------------------------------------------------------- Summary of changes: CMakeLists.txt | 10 ++ ConfigureChecks.cmake | 1 + config.h.cmake | 1 + doc/socket_wrapper.1 | 114 +++++++++++++-- doc/socket_wrapper.1.adoc | 48 +++++++ socket_wrapper_noop.pc.cmake | 8 ++ src/CMakeLists.txt | 32 +++++ src/socket_wrapper.c | 157 ++++++++++++++------- src/socket_wrapper.h | 89 ++++++++++++ .../thread_deadlock.c => src/socket_wrapper_noop.c | 52 +++---- tests/CMakeLists.txt | 3 +- tests/test_public_functions.c | 109 ++++++++++++++ tests/test_tcp_dup2.c | 20 ++- 13 files changed, 546 insertions(+), 98 deletions(-) create mode 100644 socket_wrapper_noop.pc.cmake create mode 100644 src/socket_wrapper.h copy tests/thread_deadlock.c => src/socket_wrapper_noop.c (64%) create mode 100644 tests/test_public_functions.c Changeset truncated at 500 lines: diff --git a/CMakeLists.txt b/CMakeLists.txt index 13be7fb..8927ebb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,6 +71,16 @@ install( pkgconfig ) +configure_file(socket_wrapper_noop.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/socket_wrapper_noop.pc @ONLY) +install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/socket_wrapper_noop.pc + DESTINATION + ${CMAKE_INSTALL_LIBDIR}/pkgconfig + COMPONENT + pkgconfig +) + # cmake config files configure_file(socket_wrapper-config-version.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/socket_wrapper-config-version.cmake @ONLY) configure_file(socket_wrapper-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/socket_wrapper-config.cmake @ONLY) diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index bfb8c17..2c78b83 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -74,6 +74,7 @@ check_function_exists(getexecname HAVE_GETEXECNAME) check_function_exists(pledge HAVE_PLEDGE) check_function_exists(_socket HAVE__SOCKET) check_function_exists(_close HAVE__CLOSE) +check_function_exists(__close_nocancel HAVE___CLOSE_NOCANCEL) if (UNIX) find_library(DLFCN_LIBRARY dl) diff --git a/config.h.cmake b/config.h.cmake index 1148f74..0f2fb09 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -47,6 +47,7 @@ #cmakedefine HAVE_PLEDGE 1 #cmakedefine HAVE__SOCKET 1 #cmakedefine HAVE__CLOSE 1 +#cmakedefine HAVE___CLOSE_NOCANCEL 1 #cmakedefine HAVE_ACCEPT_PSOCKLEN_T 1 #cmakedefine HAVE_IOCTL_INT 1 diff --git a/doc/socket_wrapper.1 b/doc/socket_wrapper.1 index 0272c63..c988227 100644 --- a/doc/socket_wrapper.1 +++ b/doc/socket_wrapper.1 @@ -1,13 +1,13 @@ '\" t .\" Title: socket_wrapper .\" Author: Samba Team -.\" Generator: Asciidoctor 2.0.12 -.\" Date: 2021-02-02 +.\" Generator: Asciidoctor 2.0.10 +.\" Date: 2021-02-24 .\" Manual: \ \& .\" Source: \ \& .\" Language: English .\" -.TH "SOCKET_WRAPPER" "1" "2021-02-02" "\ \&" "\ \&" +.TH "SOCKET_WRAPPER" "1" "2021-02-24" "\ \&" "\ \&" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 @@ -214,54 +214,142 @@ to be usable. .sp .if n .RS 4 .nf -.fam C # Open a console and create a directory for the unix sockets. $ mktemp \-d /tmp/tmp.bQRELqDrhM -.fam .fi .if n .RE .sp .if n .RS 4 .nf -.fam C # Then start nc to listen for network traffic using the temporary directory. $ LD_PRELOAD=libsocket_wrapper.so \(rs SOCKET_WRAPPER_DIR=/tmp/tmp.bQRELqDrhM \(rs SOCKET_WRAPPER_DEFAULT_IFACE=10 nc \-v \-l 127.0.0.10 7 -.fam .fi .if n .RE .sp .if n .RS 4 .nf -.fam C # (If nc, listens on 0.0.0.0 then listener will be open on 127.0.0.10 because # it is the default interface) -.fam .fi .if n .RE .sp .if n .RS 4 .nf -.fam C # Now open another console and start \(aqnc\(aq as a client to connect to the server: $ LD_PRELOAD=libsocket_wrapper.so \(rs SOCKET_WRAPPER_DIR=/tmp/tmp.bQRELqDrhM \(rs SOCKET_WRAPPER_DEFAULT_IFACE=100 nc \-v 127.0.0.10 7 -.fam .fi .if n .RE .sp .if n .RS 4 .nf -.fam C # (The client will use the address 127.0.0.100 when connecting to the server) # Now you can type \(aqHello!\(aq which will be sent to the server and should appear # in the console output of the server. -.fam .fi .if n .RE +.SH "PUBLIC FUNCTIONS" +.sp +Socket wrapper advanced helpers. +.sp +Applications with the need to alter their behaviour when +socket wrapper is active, can link use these functions. +.sp +By default it\(cqs required for applications to use any of these +functions as libsocket_wrapper.so is injected at runtime via +LD_PRELOAD. +.sp +Applications using these functions should link against +libsocket_wrapper_noop.so by using \-lsocket_wrapper_noop, +or implement their own noop stubs. +.sp +#include <socket_wrapper.h> +.sp +bool socket_wrapper_enabled(void); +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +. sp -1 +. IP \(bu 2.3 +.\} +This returns true when socket wrapper is actively in use. +.RE +.sp +void socket_wrapper_indicate_no_inet_fd(int fd); +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +. sp -1 +. IP \(bu 2.3 +.\} +This allows socket_wrapper aware applications to +indicate that the given fd does not belong to +an inet socket. +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +. sp -1 +. IP \(bu 2.3 +.\} +socket_wrapper may not be able to intercept the __close_nocancel() +syscall made from within libc.so. As result it\(cqs 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, ... +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +. sp -1 +. IP \(bu 2.3 +.\} +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. +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +. sp -1 +. IP \(bu 2.3 +.\} +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. +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +. sp -1 +. IP \(bu 2.3 +.\} +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. +.RE .SH "RESOURCES" .sp \fBProject web site:\fP \c diff --git a/doc/socket_wrapper.1.adoc b/doc/socket_wrapper.1.adoc index 9519fd4..39c46ee 100644 --- a/doc/socket_wrapper.1.adoc +++ b/doc/socket_wrapper.1.adoc @@ -133,6 +133,54 @@ EXAMPLE # Now you can type 'Hello!' which will be sent to the server and should appear # in the console output of the server. +PUBLIC FUNCTIONS +---------------- + +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. + +#include <socket_wrapper.h> + +bool socket_wrapper_enabled(void); + +- This returns true when socket wrapper is actively in use. + + +void socket_wrapper_indicate_no_inet_fd(int fd); + +- 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. + + RESOURCES --------- diff --git a/socket_wrapper_noop.pc.cmake b/socket_wrapper_noop.pc.cmake new file mode 100644 index 0000000..5c8ac49 --- /dev/null +++ b/socket_wrapper_noop.pc.cmake @@ -0,0 +1,8 @@ +libdir=@CMAKE_INSTALL_FULL_LIBDIR@ +includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ + +Name: @PROJECT_NAME@ +Description: The socket_wrapper_noop library +Version: @PROJECT_VERSION@ +Libs: -L${libdir} -lsocket_wrapper_noop +Cflags: -I${includedir} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 73f8cd0..ac56c86 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,3 +27,35 @@ install(TARGETS socket_wrapper ) set(SOCKET_WRAPPER_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}socket_wrapper${CMAKE_SHARED_LIBRARY_SUFFIX}" PARENT_SCOPE) + +add_library(socket_wrapper_noop SHARED socket_wrapper_noop.c) +target_include_directories(socket_wrapper_noop + PRIVATE + ${CMAKE_BINARY_DIR}) +target_compile_options(socket_wrapper_noop + PRIVATE + ${DEFAULT_C_COMPILE_FLAGS} + -D_GNU_SOURCE) +target_link_libraries(socket_wrapper_noop ${SWRAP_REQUIRED_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) +set_target_properties(socket_wrapper_noop + PROPERTIES + VERSION ${LIBRARY_VERSION} + SOVERSION ${LIBRARY_SOVERSION}) +if (DEFINED DEFAULT_LINK_FLAGS) + set_target_properties(socket_wrapper_noop + PROPERTIES + LINK_FLAGS ${DEFAULT_LINK_FLAGS}) +endif() + +install(TARGETS socket_wrapper_noop + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + +install( + FILES + ${CMAKE_CURRENT_SOURCE_DIR}/socket_wrapper.h + DESTINATION + ${CMAKE_INSTALL_INCLUDEDIR} +) diff --git a/src/socket_wrapper.c b/src/socket_wrapper.c index a950a0a..44cfad8 100644 --- a/src/socket_wrapper.c +++ b/src/socket_wrapper.c @@ -2,8 +2,8 @@ * BSD 3-Clause License * * Copyright (c) 2005-2008, Jelmer Vernooij <jel...@samba.org> - * Copyright (c) 2006-2018, Stefan Metzmacher <me...@samba.org> - * Copyright (c) 2013-2018, Andreas Schneider <a...@samba.org> + * Copyright (c) 2006-2021, Stefan Metzmacher <me...@samba.org> + * Copyright (c) 2013-2021, Andreas Schneider <a...@samba.org> * Copyright (c) 2014-2017, Michael Adam <ob...@samba.org> * Copyright (c) 2016-2018, Anoop C S <anoo...@redhat.com> * All rights reserved. @@ -86,6 +86,8 @@ #endif #include <pthread.h> +#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 */ -- Socket Wrapper Repository