Avoid dclose(RTLD_NEXT)
[socket_wrapper.git] / src / socket_wrapper.c
index 22e024608fbac2b345a21d6e16b0085bcaf7a71b..aefd526ddfe633f4e158138534a0d0b8d6ea3095 100644 (file)
@@ -2,8 +2,8 @@
  * BSD 3-Clause License
  *
  * Copyright (c) 2005-2008, Jelmer Vernooij <jelmer@samba.org>
- * Copyright (c) 2006-2018, Stefan Metzmacher <metze@samba.org>
- * Copyright (c) 2013-2018, Andreas Schneider <asn@samba.org>
+ * Copyright (c) 2006-2021, Stefan Metzmacher <metze@samba.org>
+ * Copyright (c) 2013-2021, Andreas Schneider <asn@samba.org>
  * Copyright (c) 2014-2017, Michael Adam <obnox@samba.org>
  * Copyright (c) 2016-2018, Anoop C S <anoopcs@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,
@@ -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);
@@ -3797,7 +3815,6 @@ static int swrap_auto_bind(int fd, struct socket_info *si, int family)
        char type;
        int ret;
        int port;
-       struct stat st;
        char *swrap_dir = NULL;
 
        swrap_mutex_lock(&autobind_start_mutex);
@@ -3898,10 +3915,12 @@ static int swrap_auto_bind(int fd, struct socket_info *si, int family)
                              type,
                              socket_wrapper_default_iface(),
                              port);
-               if (stat(un_addr.sa.un.sun_path, &st) == 0) continue;
 
                ret = libc_bind(fd, &un_addr.sa.s, un_addr.sa_socklen);
                if (ret == -1) {
+                       if (errno == EALREADY || errno == EADDRINUSE) {
+                               continue;
+                       }
                        goto done;
                }
 
@@ -5306,7 +5325,7 @@ union __swrap_cmsghdr {
        struct cmsghdr *cmsg;
 };
 
-static int swrap_sendmsg_unix_scm_rights(const struct cmsghdr *cmsg,
+static int swrap_sendmsg_unix_scm_rights(struct cmsghdr *cmsg,
                                         uint8_t **cm_data,
                                         size_t *cm_data_space,
                                         int *scm_rights_pipe_fd)
@@ -5538,7 +5557,7 @@ static int swrap_sendmsg_unix_scm_rights(const struct cmsghdr *cmsg,
        return 0;
 }
 
-static int swrap_sendmsg_unix_sol_socket(const struct cmsghdr *cmsg,
+static int swrap_sendmsg_unix_sol_socket(struct cmsghdr *cmsg,
                                         uint8_t **cm_data,
                                         size_t *cm_data_space,
                                         int *scm_rights_pipe_fd)
@@ -5562,7 +5581,7 @@ static int swrap_sendmsg_unix_sol_socket(const struct cmsghdr *cmsg,
        return rc;
 }
 
-static int swrap_recvmsg_unix_scm_rights(const struct cmsghdr *cmsg,
+static int swrap_recvmsg_unix_scm_rights(struct cmsghdr *cmsg,
                                         uint8_t **cm_data,
                                         size_t *cm_data_space)
 {
@@ -5841,7 +5860,7 @@ static int swrap_recvmsg_unix_scm_rights(const struct cmsghdr *cmsg,
        return 0;
 }
 
-static int swrap_recvmsg_unix_sol_socket(const struct cmsghdr *cmsg,
+static int swrap_recvmsg_unix_sol_socket(struct cmsghdr *cmsg,
                                         uint8_t **cm_data,
                                         size_t *cm_data_space)
 {
@@ -6267,9 +6286,11 @@ static void swrap_sendmsg_after(int fd,
 
        for (i = 0; i < (size_t)msg->msg_iovlen; i++) {
                size_t this_time = MIN(remain, (size_t)msg->msg_iov[i].iov_len);
-               memcpy(buf + ofs,
-                      msg->msg_iov[i].iov_base,
-                      this_time);
+               if (this_time > 0) {
+                       memcpy(buf + ofs,
+                              msg->msg_iov[i].iov_base,
+                              this_time);
+               }
                ofs += this_time;
                remain -= this_time;
        }
@@ -7456,6 +7477,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);
@@ -7466,6 +7509,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
  ***************************/
@@ -7773,10 +7831,18 @@ void swrap_destructor(void)
 
        SAFE_FREE(sockets);
 
-       if (swrap.libc.handle != NULL) {
+       if (swrap.libc.handle != NULL
+#ifdef RTLD_NEXT
+           && swrap.libc.handle != RTLD_NEXT
+#endif
+                       ) {
                dlclose(swrap.libc.handle);
        }
-       if (swrap.libc.socket_handle) {
+       if (swrap.libc.socket_handle
+#ifdef RTLD_NEXT
+           && swrap.libc.socket_handle != RTLD_NEXT
+#endif
+                       ) {
                dlclose(swrap.libc.socket_handle);
        }
 }
@@ -7794,8 +7860,8 @@ void swrap_destructor(void)
  * related syscalls also with the '_' prefix.
  *
  * This is tested in Samba's 'make test',
- * there we noticed that providing '_read'
- * and '_open' would cause errors, which
+ * there we noticed that providing '_read',
+ * '_open' and '_close' would cause errors, which
  * means we skip '_read', '_write' and
  * all non socket related calls without
  * further analyzing the problem.
@@ -7808,7 +7874,6 @@ SWRAP_SYMBOL_ALIAS(accept4, _accept4);
 #endif
 SWRAP_SYMBOL_ALIAS(accept, _accept);
 SWRAP_SYMBOL_ALIAS(bind, _bind);
-SWRAP_SYMBOL_ALIAS(close, _close);
 SWRAP_SYMBOL_ALIAS(connect, _connect);
 SWRAP_SYMBOL_ALIAS(dup, _dup);
 SWRAP_SYMBOL_ALIAS(dup2, _dup2);