summaryrefslogtreecommitdiff
path: root/src/backend/libpq/be-secure-openssl.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2023-12-11 11:51:56 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2023-12-11 11:51:56 -0500
commitebbd499d4b55c6a6223e01e914308f4a3b936a88 (patch)
treec5d380f5f5e2e568a2eed4d167bb8a83aac363d6 /src/backend/libpq/be-secure-openssl.c
parent01cc92fa6251c4d1a0ac128806db6f7d8f31ec7f (diff)
Be more wary about OpenSSL not setting errno on error.
OpenSSL will sometimes return SSL_ERROR_SYSCALL without having set errno; this is apparently a reflection of recv(2)'s habit of not setting errno when reporting EOF. Ensure that we treat such cases the same as read EOF. Previously, we'd frequently report them like "could not accept SSL connection: Success" which is confusing, or worse report them with an unrelated errno left over from some previous syscall. To fix, ensure that errno is zeroed immediately before the call, and report its value only when it's not zero afterwards; otherwise report EOF. For consistency, I've applied the same coding pattern in libpq's pqsecure_raw_read(). Bare recv(2) shouldn't really return -1 without setting errno, but in case it does we might as well cope. Per report from Andres Freund. Back-patch to all supported versions. Discussion: https://postgr.es/m/20231208181451.deqnflwxqoehhxpe@awork3.anarazel.de
Diffstat (limited to 'src/backend/libpq/be-secure-openssl.c')
-rw-r--r--src/backend/libpq/be-secure-openssl.c15
1 files changed, 11 insertions, 4 deletions
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index 49dca0cda9f..4f1fd91ba4d 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -460,6 +460,7 @@ aloop:
* per-thread error queue following another call to an OpenSSL I/O
* routine.
*/
+ errno = 0;
ERR_clear_error();
r = SSL_accept(port->ssl);
if (r <= 0)
@@ -496,7 +497,7 @@ aloop:
WAIT_EVENT_SSL_OPEN_SERVER);
goto aloop;
case SSL_ERROR_SYSCALL:
- if (r < 0)
+ if (r < 0 && errno != 0)
ereport(COMMERROR,
(errcode_for_socket_access(),
errmsg("could not accept SSL connection: %m")));
@@ -732,7 +733,7 @@ be_tls_read(Port *port, void *ptr, size_t len, int *waitfor)
break;
case SSL_ERROR_SYSCALL:
/* leave it to caller to ereport the value of errno */
- if (n != -1)
+ if (n != -1 || errno == 0)
{
errno = ECONNRESET;
n = -1;
@@ -790,8 +791,14 @@ be_tls_write(Port *port, void *ptr, size_t len, int *waitfor)
n = -1;
break;
case SSL_ERROR_SYSCALL:
- /* leave it to caller to ereport the value of errno */
- if (n != -1)
+
+ /*
+ * Leave it to caller to ereport the value of errno. However, if
+ * errno is still zero then assume it's a read EOF situation, and
+ * report ECONNRESET. (This seems possible because SSL_write can
+ * also do reads.)
+ */
+ if (n != -1 || errno == 0)
{
errno = ECONNRESET;
n = -1;