aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Munro <tmunro@postgresql.org>2023-03-17 17:08:02 +1300
committerThomas Munro <tmunro@postgresql.org>2023-03-17 20:40:34 +1300
commitbfc9497ece01c7c45437bc36387cb1ebe346f4d2 (patch)
treec497f686beb80b9aab5df68dcab6903f7ce57d65
parent95a828378ed243a1b37cab6bda99746bfc0af509 (diff)
downloadpostgresql-bfc9497ece01c7c45437bc36387cb1ebe346f4d2.tar.gz
postgresql-bfc9497ece01c7c45437bc36387cb1ebe346f4d2.zip
libpq: Use modern socket flags, if available.
Since commit 7627b91cd5d, libpq has used FD_CLOEXEC so that sockets wouldn't be leaked to subprograms. With enough bad luck, a multi-threaded program might fork in between the socket() and fcntl() calls. We can close that tiny gap by using SOCK_CLOEXEC instead of a separate call. While here, we might as well do the same for SOCK_NONBLOCK, to save another syscall. These flags are expected to appear in the next revision of the POSIX standard, specifically to address this problem. Our Unixoid targets except macOS and AIX have had them for a long time, and macOS would hopefully use guarded availability to roll them out, so it seems enough to use a simple ifdef test for availability until we hear otherwise. Windows doesn't have them, but has non-inheritable sockets by default. Discussion: https://postgr.es/m/CA%2BhUKGKb6FsAdQWcRL35KJsftv%2B9zXqQbzwkfRf1i0J2e57%2BhQ%40mail.gmail.com
-rw-r--r--src/interfaces/libpq/fe-connect.c26
1 files changed, 25 insertions, 1 deletions
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 0c197589ab9..b9f899c552e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -2629,6 +2629,7 @@ keep_going: /* We will come back to here until there is
{
struct addrinfo *addr_cur = conn->addr_cur;
char host_addr[NI_MAXHOST];
+ int sock_type;
/*
* Advance to next possible host, if we've tried all of
@@ -2659,7 +2660,26 @@ keep_going: /* We will come back to here until there is
conn->connip = strdup(host_addr);
/* Try to create the socket */
- conn->sock = socket(addr_cur->ai_family, SOCK_STREAM, 0);
+ sock_type = SOCK_STREAM;
+#ifdef SOCK_CLOEXEC
+
+ /*
+ * Atomically mark close-on-exec, if possible on this
+ * platform, so that there isn't a window where a
+ * subprogram executed by another thread inherits the
+ * socket. See fallback code below.
+ */
+ sock_type |= SOCK_CLOEXEC;
+#endif
+#ifdef SOCK_NONBLOCK
+
+ /*
+ * We might as well skip a system call for nonblocking
+ * mode too, if we can.
+ */
+ sock_type |= SOCK_NONBLOCK;
+#endif
+ conn->sock = socket(addr_cur->ai_family, sock_type, 0);
if (conn->sock == PGINVALID_SOCKET)
{
int errorno = SOCK_ERRNO;
@@ -2705,6 +2725,7 @@ keep_going: /* We will come back to here until there is
goto keep_going;
}
}
+#ifndef SOCK_NONBLOCK
if (!pg_set_noblock(conn->sock))
{
libpq_append_conn_error(conn, "could not set socket to nonblocking mode: %s",
@@ -2712,7 +2733,9 @@ keep_going: /* We will come back to here until there is
conn->try_next_addr = true;
goto keep_going;
}
+#endif
+#ifndef SOCK_CLOEXEC
#ifdef F_SETFD
if (fcntl(conn->sock, F_SETFD, FD_CLOEXEC) == -1)
{
@@ -2722,6 +2745,7 @@ keep_going: /* We will come back to here until there is
goto keep_going;
}
#endif /* F_SETFD */
+#endif
if (addr_cur->ai_family != AF_UNIX)
{