Patches for socket_wrapper

Nalin Dahyabhai nalin at redhat.com
Mon Jan 27 13:46:55 MST 2014


Hello, here are a couple of patches for socket_wrapper.

The first keeps the wrapper from incorrectly attempting to treat a
previously-closed socket descriptor, which is now pointing to a file, as
a socket.

The second handles cases where a client socket has been explicitly bound
to the wildcard address, but then implicitly bound to a particular
address when it was subsequently used to open a connection.

Thanks,

Nalin
-------------- next part --------------
>From 4cd05dee165f6a08dcdbdc627464232a8abc3e4b Mon Sep 17 00:00:00 2001
From: Nalin Dahyabhai <nalin at dahyabhai.net>
Date: Thu, 23 Jan 2014 14:27:19 -0500
Subject: [PATCH 1/2] Try to recover when sockets are closed elsewhere

There are methods for closing descriptors (libc-internal code paths,
direct syscalls) which close descriptors in ways that we can't
intercept, so try to recover when we notice that that's happened:
* If we see a descriptor being handed back from open() that we thought
  was a socket, stop intercepting uses of that descriptor.
* When attempting to read or writev to a descriptor, if an underlying
  autobind fails because it's not a socket, stop intercepting uses of
  that descriptor.
---
 src/socket_wrapper.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 71 insertions(+), 3 deletions(-)

diff --git a/src/socket_wrapper.c b/src/socket_wrapper.c
index 3047eb1..8408af7 100644
--- a/src/socket_wrapper.c
+++ b/src/socket_wrapper.c
@@ -297,6 +297,7 @@ struct swrap_libc_fns {
 			       socklen_t *optlen);
 	int (*libc_ioctl)(int d, unsigned long int request, ...);
 	int (*libc_listen)(int sockfd, int backlog);
+	int (*libc_open)(const char *pathname, int flags, mode_t mode);
 	int (*libc_read)(int fd, void *buf, size_t count);
 	ssize_t (*libc_readv)(int fd, const struct iovec *iov, int iovcnt);
 	int (*libc_recv)(int sockfd, void *buf, size_t len, int flags);
@@ -564,6 +565,13 @@ static int libc_listen(int sockfd, int backlog)
 	return swrap.fns.libc_listen(sockfd, backlog);
 }
 
+static int libc_open(const char *pathname, int flags, mode_t mode)
+{
+	swrap_load_lib_function(SWRAP_LIBC, open);
+
+	return swrap.fns.libc_open(pathname, flags, mode);
+}
+
 static int libc_read(int fd, void *buf, size_t count)
 {
 	swrap_load_lib_function(SWRAP_LIBC, read);
@@ -1096,6 +1104,27 @@ static struct socket_info *find_socket_info(int fd)
 	return NULL;
 }
 
+static void swrap_remove_stale(int fd)
+{
+	struct socket_info *si = find_socket_info(fd);
+	struct socket_info_fd *fi;
+
+	if (si != NULL) {
+		for (fi = si->fds; fi; fi = fi->next) {
+			if (fi->fd == fd) {
+				SWRAP_LOG(SWRAP_LOG_TRACE, "remove stale wrapper for %d", fd);
+				SWRAP_DLIST_REMOVE(si->fds, fi);
+				free(fi);
+				break;
+			}
+		}
+
+		if (si->fds == NULL) {
+			SWRAP_DLIST_REMOVE(sockets, si);
+		}
+	}
+}
+
 static int sockaddr_convert_to_un(struct socket_info *si,
 				  const struct sockaddr *in_addr,
 				  socklen_t in_len,
@@ -2436,6 +2465,32 @@ int listen(int s, int backlog)
 }
 
 /****************************************************************************
+ *   OPEN
+ ***************************************************************************/
+
+static int swrap_open(const char *pathname, int flags, mode_t mode)
+{
+	int ret;
+
+	ret = libc_open(pathname, flags, mode);
+	if (ret != -1) {
+		swrap_remove_stale(ret);
+	}
+	return ret;
+}
+
+int open(const char *pathname, int flags, ...)
+{
+	mode_t mode;
+	va_list ap;
+
+	va_start(ap, flags);
+	mode = va_arg(ap, mode_t);
+	va_end(ap);
+	return swrap_open(pathname, flags, mode);
+}
+
+/****************************************************************************
  *   GETPEERNAME
  ***************************************************************************/
 
@@ -3379,8 +3434,13 @@ static ssize_t swrap_read(int s, void *buf, size_t len)
 
 	tret = swrap_recvmsg_before(s, si, &msg, &tmp);
 	if (tret == -1) {
-		SWRAP_LOG(SWRAP_LOG_ERROR, "swrap_recvmsg_before failed");
-		return -1;
+		if (errno == ENOTSOCK) {
+			swrap_remove_stale(s);
+			return libc_read(s, buf, len);
+		} else {
+			SWRAP_LOG(SWRAP_LOG_ERROR, "swrap_recvmsg_before failed");
+			return -1;
+		}
 	}
 
 	buf = msg.msg_iov[0].iov_base;
@@ -3725,7 +3785,15 @@ static ssize_t swrap_writev(int s, const struct iovec *vector, int count)
 #endif
 
 	ret = swrap_sendmsg_before(s, si, &msg, &tmp, &un_addr, NULL, NULL, NULL);
-	if (ret == -1) return -1;
+	if (ret == -1) {
+		if (errno == ENOTSOCK) {
+			swrap_remove_stale(s);
+			return libc_writev(s, msg.msg_iov, msg.msg_iovlen);
+		} else {
+			SWRAP_LOG(SWRAP_LOG_ERROR, "swrap_recvmsg_before failed");
+			return -1;
+		}
+	}
 
 	ret = libc_writev(s, msg.msg_iov, msg.msg_iovlen);
 
-- 
1.8.5.3

-------------- next part --------------
>From 7853ac5d8b2d30bc0a4e18bdca57acc031ccbd28 Mon Sep 17 00:00:00 2001
From: Nalin Dahyabhai <nalin at dahyabhai.net>
Date: Sat, 25 Jan 2014 00:58:15 -0500
Subject: [PATCH 2/2] Rebind wildcard sockets on connect

When we connect() on a socket that was previously bound to the wildcard
listening address, adjust its idea of its bound address to the address
we would have assigned if it hadn't been explicitly bound.
---
 src/socket_wrapper.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/src/socket_wrapper.c b/src/socket_wrapper.c
index 8408af7..d35e1ac 100644
--- a/src/socket_wrapper.c
+++ b/src/socket_wrapper.c
@@ -2388,6 +2388,26 @@ static int swrap_connect(int s, const struct sockaddr *serv_addr,
 
 		swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_RECV, NULL, 0);
 		swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_ACK, NULL, 0);
+
+		switch (si->family) {
+		case AF_INET: {
+			struct sockaddr_in *sin = (struct sockaddr_in *) si->myname;
+			if (sin->sin_addr.s_addr == htonl(INADDR_ANY)) {
+				sin->sin_addr.s_addr = htonl(0x7F000000 | socket_wrapper_default_iface());
+			}
+			break;
+		}
+#ifdef HAVE_IPV6
+		case AF_INET6: {
+			struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) si->myname;
+			struct in6_addr cmp6 = *swrap_ipv6();
+			if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &cmp6)) {
+				sin6->sin6_addr.s6_addr[15] = socket_wrapper_default_iface();
+			}
+			break;
+		}
+#endif
+		}
 	} else {
 		swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_UNREACH, NULL, 0);
 	}
-- 
1.8.5.3



More information about the samba-technical mailing list