commit c790a8d: [Fix] Add guards to avoid race condition on TCP connection

Vsevolod Stakhov vsevolod at highsecure.ru
Fri Jan 7 14:21:04 UTC 2022


Author: Vsevolod Stakhov
Date: 2022-01-07 14:12:05 +0000
URL: https://github.com/rspamd/rspamd/commit/c790a8db04ff2bd26e7a7606aa31d59647567531

[Fix] Add guards to avoid race condition on TCP connection

---
 contrib/librdns/dns_private.h |  1 +
 contrib/librdns/resolver.c    |  1 +
 contrib/librdns/util.c        | 18 ++++++++++++++++--
 3 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/contrib/librdns/dns_private.h b/contrib/librdns/dns_private.h
index adb753fd4..c240debea 100644
--- a/contrib/librdns/dns_private.h
+++ b/contrib/librdns/dns_private.h
@@ -142,6 +142,7 @@ enum rdns_io_channel_flags {
 	RDNS_CHANNEL_CONNECTED = 1u << 0u,
 	RDNS_CHANNEL_ACTIVE = 1u << 1u,
 	RDNS_CHANNEL_TCP = 1u << 2u,
+	RDNS_CHANNEL_TCP_CONNECTING = 1u << 3u,
 };
 
 #define IS_CHANNEL_CONNECTED(ioc) (((ioc)->flags & RDNS_CHANNEL_CONNECTED) != 0)
diff --git a/contrib/librdns/resolver.c b/contrib/librdns/resolver.c
index cd6a8f97d..9f5ca9872 100644
--- a/contrib/librdns/resolver.c
+++ b/contrib/librdns/resolver.c
@@ -431,6 +431,7 @@ static void
 rdns_process_tcp_connect (int fd, struct rdns_io_channel *ioc)
 {
 	ioc->flags |= RDNS_CHANNEL_CONNECTED|RDNS_CHANNEL_ACTIVE;
+	ioc->flags &= ~RDNS_CHANNEL_TCP_CONNECTING;
 
 	if (ioc->tcp->async_read == NULL) {
 		ioc->tcp->async_read = ioc->resolver->async->add_read(ioc->resolver->async->data,
diff --git a/contrib/librdns/util.c b/contrib/librdns/util.c
index 1ff8b1858..0f5533d53 100644
--- a/contrib/librdns/util.c
+++ b/contrib/librdns/util.c
@@ -730,6 +730,12 @@ rdns_ioc_tcp_connect (struct rdns_io_channel *ioc)
 		return false;
 	}
 
+	if (ioc->flags & RDNS_CHANNEL_TCP_CONNECTING) {
+		/* Already connecting channel, ignore connect request */
+
+		return true;
+	}
+
 	if (ioc->sock == -1) {
 		ioc->sock = rdns_make_client_socket (ioc->srv->name, ioc->srv->port,
 				SOCK_STREAM, &ioc->saddr, &ioc->slen);
@@ -765,13 +771,21 @@ rdns_ioc_tcp_connect (struct rdns_io_channel *ioc)
 		}
 		else {
 			/* We need to wait for write readiness here */
-			ioc->tcp->async_write = resolver->async->add_write (resolver->async->data,
-					ioc->sock, ioc);
+			if (ioc->tcp->async_write != NULL) {
+				rdns_err("internal rdns error: write event is already registered on connect");
+			}
+			else {
+				ioc->tcp->async_write = resolver->async->add_write(resolver->async->data,
+						ioc->sock, ioc);
+			}
+			/* Prevent double connect attempts */
+			ioc->flags |= RDNS_CHANNEL_TCP_CONNECTING;
 		}
 	}
 	else {
 		/* Always be ready to read from a TCP socket */
 		ioc->flags |= RDNS_CHANNEL_CONNECTED|RDNS_CHANNEL_ACTIVE;
+		ioc->flags &= ~RDNS_CHANNEL_TCP_CONNECTING;
 		ioc->tcp->async_read = resolver->async->add_read(resolver->async->data,
 				ioc->sock, ioc);
 	}


More information about the Commits mailing list