From efc50df431b7a42a052b902aa89249860a947d6b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 17 Feb 2021 11:41:38 +0100 Subject: [PATCH 1/7] swrap: warn about unreachable addresses BUG: https://bugzilla.samba.org/show_bug.cgi?id=14640 Signed-off-by: Stefan Metzmacher --- src/socket_wrapper.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/socket_wrapper.c b/src/socket_wrapper.c index a950a0a..b6c7637 100644 --- a/src/socket_wrapper.c +++ b/src/socket_wrapper.c @@ -2027,6 +2027,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 +2069,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; } -- GitLab From 4985c3b535917729391abd6ba2cb33be350451b4 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 17 Feb 2021 11:00:53 +0100 Subject: [PATCH 2/7] 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 --- src/socket_wrapper.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/socket_wrapper.c b/src/socket_wrapper.c index b6c7637..3bf60f1 100644 --- a/src/socket_wrapper.c +++ b/src/socket_wrapper.c @@ -3004,7 +3004,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; } @@ -3339,7 +3339,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; } @@ -5546,7 +5546,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) { -- GitLab From b70ab7586b383e8aead502a3167a0e4fbaa8e3bc Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 17 Feb 2021 12:14:06 +0100 Subject: [PATCH 3/7] swrap: remember the libc_close() errno in swrap_close() BUG: https://bugzilla.samba.org/show_bug.cgi?id=14640 Signed-off-by: Stefan Metzmacher --- src/socket_wrapper.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/socket_wrapper.c b/src/socket_wrapper.c index 3bf60f1..61dce97 100644 --- a/src/socket_wrapper.c +++ b/src/socket_wrapper.c @@ -7421,6 +7421,7 @@ static int swrap_close(int fd) { struct socket_info *si = NULL; int si_index; + int ret_errno = errno; int ret; swrap_mutex_lock(&socket_reset_mutex); @@ -7440,6 +7441,9 @@ static int swrap_close(int fd) SWRAP_LOCK_SI(si); ret = libc_close(fd); + if (ret == -1) { + ret_errno = errno; + } swrap_dec_refcount(si); @@ -7474,6 +7478,7 @@ out: swrap_mutex_unlock(&first_free_mutex); swrap_mutex_unlock(&socket_reset_mutex); + errno = ret_errno; return ret; } -- GitLab From 6381002e332a13eb238bd5cb038b0f7c0a222779 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 17 Feb 2021 12:14:06 +0100 Subject: [PATCH 4/7] 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 --- src/socket_wrapper.c | 69 +++++++++++++++----------------------------- 1 file changed, 24 insertions(+), 45 deletions(-) diff --git a/src/socket_wrapper.c b/src/socket_wrapper.c index 61dce97..22e0246 100644 --- a/src/socket_wrapper.c +++ b/src/socket_wrapper.c @@ -370,7 +370,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 */ @@ -2404,46 +2404,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, @@ -7417,7 +7378,9 @@ 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; @@ -7429,10 +7392,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); @@ -7440,7 +7403,7 @@ 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; } @@ -7482,6 +7445,22 @@ out: 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); +} + +static int swrap_close(int fd) +{ + return swrap_remove_wrapper(__func__, libc_close, fd); +} + int close(int fd) { return swrap_close(fd); -- GitLab From c5bedd96fa6a2a5b7f8e223ec9eb2134fc18d892 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 24 Feb 2021 12:45:26 +0100 Subject: [PATCH 5/7] 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 --- CMakeLists.txt | 10 +++++ doc/socket_wrapper.1 | 45 ++++++++++++++------ doc/socket_wrapper.1.adoc | 23 +++++++++++ socket_wrapper_noop.pc.cmake | 8 ++++ src/CMakeLists.txt | 32 ++++++++++++++ src/socket_wrapper.c | 8 ++-- src/socket_wrapper.h | 64 ++++++++++++++++++++++++++++ src/socket_wrapper_noop.c | 57 +++++++++++++++++++++++++ tests/CMakeLists.txt | 3 +- tests/test_public_functions.c | 78 +++++++++++++++++++++++++++++++++++ 10 files changed, 310 insertions(+), 18 deletions(-) create mode 100644 socket_wrapper_noop.pc.cmake create mode 100644 src/socket_wrapper.h create mode 100644 src/socket_wrapper_noop.c create mode 100644 tests/test_public_functions.c 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/doc/socket_wrapper.1 b/doc/socket_wrapper.1 index 0272c63..b6363cd 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,73 @@ 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 +.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 .SH "RESOURCES" .sp \fBProject web site:\fP \c diff --git a/doc/socket_wrapper.1.adoc b/doc/socket_wrapper.1.adoc index 9519fd4..fd0b745 100644 --- a/doc/socket_wrapper.1.adoc +++ b/doc/socket_wrapper.1.adoc @@ -133,6 +133,29 @@ 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 + +bool socket_wrapper_enabled(void); + +- This returns true when socket wrapper is actively in use. + + 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 22e0246..63de148 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 - * 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, @@ -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) diff --git a/src/socket_wrapper.h b/src/socket_wrapper.h new file mode 100644 index 0000000..f1a97e8 --- /dev/null +++ b/src/socket_wrapper.h @@ -0,0 +1,64 @@ +/* + * 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); + +#endif /* __SOCKET_WRAPPER_H__ */ diff --git a/src/socket_wrapper_noop.c b/src/socket_wrapper_noop.c new file mode 100644 index 0000000..45aff8f --- /dev/null +++ b/src/socket_wrapper_noop.c @@ -0,0 +1,57 @@ +/* + * 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. + */ + +/* + Socket wrapper noop library. + + Applications with the need to alter their behaviour when + socket wrapper is active, can link to this with -lsocket_wrapper_noop + in order to call get the required public functions at link time. + + During runtime these are overloaded with LD_PRELOAD by the real + libsocket_wrapper.so. +*/ + +#include "config.h" +#include "stdbool.h" +#include "socket_wrapper.h" + +bool socket_wrapper_enabled(void) +{ + return false; +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index db36bf3..2f98af1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -56,6 +56,7 @@ set(SWRAP_TESTS test_echo_udp_sendmsg_recvmsg test_swrap_unit test_max_sockets + test_public_functions test_close_failure test_tcp_socket_overwrite ${SWRAP_THREADED_TESTS}) @@ -111,7 +112,7 @@ foreach(_SWRAP_TEST ${SWRAP_TESTS}) add_cmocka_test(${_SWRAP_TEST} SOURCES ${_SWRAP_TEST}.c COMPILE_OPTIONS ${DEFAULT_C_COMPILE_FLAGS} -D_GNU_SOURCE - LINK_LIBRARIES ${TORTURE_LIBRARY} + LINK_LIBRARIES ${TORTURE_LIBRARY} socket_wrapper_noop LINK_OPTIONS ${DEFAULT_LINK_FLAGS}) add_cmocka_test_environment(${_SWRAP_TEST}) endforeach() diff --git a/tests/test_public_functions.c b/tests/test_public_functions.c new file mode 100644 index 0000000..11d03ef --- /dev/null +++ b/tests/test_public_functions.c @@ -0,0 +1,78 @@ +#include "torture.h" + +#include +#include +#include +#include +#include + +#include + +static int setup_enabled(void **state) +{ + torture_setup_socket_dir(state); + + return 0; +} + +static int teardown_enabled(void **state) +{ + torture_teardown_socket_dir(state); + + return 0; +} + +static int setup_disabled(void **state) +{ + (void) state; /* unused */ + + unsetenv("SOCKET_WRAPPER_DIR"); + unsetenv("SOCKET_WRAPPER_DEFAULT_IFACE"); + unsetenv("SOCKET_WRAPPER_PCAP_FILE"); + + return 0; +} + +static int teardown_disabled(void **state) +{ + (void) state; /* unused */ + + return 0; +} + +static void test_call_enabled_true(void **state) +{ + char *s = getenv("SOCKET_WRAPPER_DIR"); + + (void) state; /* unused */ + + assert_true(socket_wrapper_enabled()); + assert_true(s != NULL); +} + +static void test_call_enabled_false(void **state) +{ + char *s = getenv("SOCKET_WRAPPER_DIR"); + + (void) state; /* unused */ + + assert_false(socket_wrapper_enabled()); + assert_false(s != NULL); +} + +int main(void) { + int rc; + + const struct CMUnitTest max_sockets_tests[] = { + cmocka_unit_test_setup_teardown(test_call_enabled_true, + setup_enabled, + teardown_enabled), + cmocka_unit_test_setup_teardown(test_call_enabled_false, + setup_disabled, + teardown_disabled), + }; + + rc = cmocka_run_group_tests(max_sockets_tests, NULL, NULL); + + return rc; +} -- GitLab From 66904c0afcb859c1ccd851229f206623a7d8eece Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 17 Feb 2021 12:29:27 +0100 Subject: [PATCH 6/7] 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 --- doc/socket_wrapper.1 | 69 +++++++++++++++++++++++++++++++++++ doc/socket_wrapper.1.adoc | 25 +++++++++++++ src/socket_wrapper.c | 22 +++++++++++ src/socket_wrapper.h | 25 +++++++++++++ src/socket_wrapper_noop.c | 6 +++ tests/test_public_functions.c | 31 ++++++++++++++++ 6 files changed, 178 insertions(+) diff --git a/doc/socket_wrapper.1 b/doc/socket_wrapper.1 index b6363cd..c988227 100644 --- a/doc/socket_wrapper.1 +++ b/doc/socket_wrapper.1 @@ -281,6 +281,75 @@ bool socket_wrapper_enabled(void); .\} 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 fd0b745..39c46ee 100644 --- a/doc/socket_wrapper.1.adoc +++ b/doc/socket_wrapper.1.adoc @@ -156,6 +156,31 @@ 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/src/socket_wrapper.c b/src/socket_wrapper.c index 63de148..714cd25 100644 --- a/src/socket_wrapper.c +++ b/src/socket_wrapper.c @@ -7456,6 +7456,28 @@ 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); diff --git a/src/socket_wrapper.h b/src/socket_wrapper.h index f1a97e8..3ec5031 100644 --- a/src/socket_wrapper.h +++ b/src/socket_wrapper.h @@ -61,4 +61,29 @@ */ 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/src/socket_wrapper_noop.c b/src/socket_wrapper_noop.c index 45aff8f..aadf350 100644 --- a/src/socket_wrapper_noop.c +++ b/src/socket_wrapper_noop.c @@ -55,3 +55,9 @@ bool socket_wrapper_enabled(void) { return false; } + +void socket_wrapper_indicate_no_inet_fd(int fd) +{ + (void) fd; /* unused */ + return; +} diff --git a/tests/test_public_functions.c b/tests/test_public_functions.c index 11d03ef..816cd7d 100644 --- a/tests/test_public_functions.c +++ b/tests/test_public_functions.c @@ -60,6 +60,31 @@ static void test_call_enabled_false(void **state) assert_false(s != NULL); } +static void test_call_indicate_no_inet_fd(void **state) +{ + int rc; + int s = -1; + + (void) state; /* unused */ + + socket_wrapper_indicate_no_inet_fd(987654321); + socket_wrapper_indicate_no_inet_fd(-1); + + rc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (rc >= 0) { + s = rc; + rc = 0; + } + assert_return_code(rc, errno); + + socket_wrapper_indicate_no_inet_fd(987654321); + socket_wrapper_indicate_no_inet_fd(-1); + socket_wrapper_indicate_no_inet_fd(s); + socket_wrapper_indicate_no_inet_fd(0); + socket_wrapper_indicate_no_inet_fd(1); + socket_wrapper_indicate_no_inet_fd(2); +} + int main(void) { int rc; @@ -70,6 +95,12 @@ int main(void) { cmocka_unit_test_setup_teardown(test_call_enabled_false, setup_disabled, teardown_disabled), + cmocka_unit_test_setup_teardown(test_call_indicate_no_inet_fd, + setup_enabled, + teardown_enabled), + cmocka_unit_test_setup_teardown(test_call_indicate_no_inet_fd, + setup_disabled, + teardown_disabled), }; rc = cmocka_run_group_tests(max_sockets_tests, NULL, NULL); -- GitLab From ad9c8c5d3948c7ec900ec3b5ffac75e2c4638ade Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 17 Feb 2021 10:58:29 +0100 Subject: [PATCH 7/7] 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 --- ConfigureChecks.cmake | 1 + config.h.cmake | 1 + src/socket_wrapper.c | 33 +++++++++++++++++++++++++++++++++ tests/test_tcp_dup2.c | 20 +++++++++++++++++++- 4 files changed, 54 insertions(+), 1 deletion(-) 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/src/socket_wrapper.c b/src/socket_wrapper.c index 714cd25..44cfad8 100644 --- a/src/socket_wrapper.c +++ b/src/socket_wrapper.c @@ -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); @@ -7488,6 +7506,21 @@ 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/tests/test_tcp_dup2.c b/tests/test_tcp_dup2.c index fd6adc2..238b9a8 100644 --- a/tests/test_tcp_dup2.c +++ b/tests/test_tcp_dup2.c @@ -2,6 +2,11 @@ #include #include +#include + +#ifdef HAVE___CLOSE_NOCANCEL +extern int __close_nocancel(int fd); +#endif static int setup(void **state) { @@ -20,6 +25,7 @@ static int teardown(void **state) static void test_dup2_existing_open_fd(void **state) { int s, dup_s; + int rc; (void) state; /* unused */ @@ -34,7 +40,19 @@ static void test_dup2_existing_open_fd(void **state) dup_s = dup2(s, s); assert_int_equal(dup_s, s); - close(s); +#ifdef HAVE___CLOSE_NOCANCEL + rc = __close_nocancel(s); + assert_return_code(rc, errno); + rc = close(s); + assert_int_equal(rc, -1); + assert_int_equal(errno, EBADF); + rc = __close_nocancel(s); + assert_int_equal(rc, -1); + assert_int_equal(errno, EBADF); +#else + rc = close(s); + assert_return_code(rc, errno); +#endif } int main(void) { -- GitLab