diff options
| author | Tom Lane | 2023-12-11 16:51:56 +0000 |
|---|---|---|
| committer | Tom Lane | 2023-12-11 16:51:56 +0000 |
| commit | 0a5c46a7a488f2f4260a90843bb9de6c584c7f4e (patch) | |
| tree | 51eb387d27ae10529bab0201f8609c5ab39546cf /src/interfaces | |
| parent | d3fe6e90bab52b8cbf085cfad5e4da110a2cd373 (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/interfaces')
| -rw-r--r-- | src/interfaces/libpq/fe-secure-openssl.c | 15 | ||||
| -rw-r--r-- | src/interfaces/libpq/fe-secure.c | 7 |
2 files changed, 18 insertions, 4 deletions
diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c index e669bdbf1d2..2b221e7d151 100644 --- a/src/interfaces/libpq/fe-secure-openssl.c +++ b/src/interfaces/libpq/fe-secure-openssl.c @@ -200,7 +200,7 @@ rloop: */ goto rloop; case SSL_ERROR_SYSCALL: - if (n < 0) + if (n < 0 && SOCK_ERRNO != 0) { result_errno = SOCK_ERRNO; if (result_errno == EPIPE || @@ -301,7 +301,13 @@ pgtls_write(PGconn *conn, const void *ptr, size_t len) n = 0; break; case SSL_ERROR_SYSCALL: - if (n < 0) + + /* + * If errno is still zero then assume it's a read EOF situation, + * and report EOF. (This seems possible because SSL_write can + * also do reads.) + */ + if (n < 0 && SOCK_ERRNO != 0) { result_errno = SOCK_ERRNO; if (result_errno == EPIPE || result_errno == ECONNRESET) @@ -1510,11 +1516,12 @@ open_client_SSL(PGconn *conn) * was using the system CA pool. For other errors, log * them using the normal SYSCALL logging. */ - if (!save_errno && vcode == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY && + if (save_errno == 0 && + vcode == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY && strcmp(conn->sslrootcert, "system") == 0) libpq_append_conn_error(conn, "SSL error: certificate verify failed: %s", X509_verify_cert_error_string(vcode)); - else if (r == -1) + else if (r == -1 && save_errno != 0) libpq_append_conn_error(conn, "SSL SYSCALL error: %s", SOCK_STRERROR(save_errno, sebuf, sizeof(sebuf))); else diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c index bd72a87bbba..b2430362a90 100644 --- a/src/interfaces/libpq/fe-secure.c +++ b/src/interfaces/libpq/fe-secure.c @@ -211,6 +211,8 @@ pqsecure_raw_read(PGconn *conn, void *ptr, size_t len) int result_errno = 0; char sebuf[PG_STRERROR_R_BUFLEN]; + SOCK_ERRNO_SET(0); + n = recv(conn->sock, ptr, len, 0); if (n < 0) @@ -237,6 +239,11 @@ pqsecure_raw_read(PGconn *conn, void *ptr, size_t len) "\tbefore or while processing the request."); break; + case 0: + /* If errno didn't get set, treat it as regular EOF */ + n = 0; + break; + default: libpq_append_conn_error(conn, "could not receive data from server: %s", SOCK_STRERROR(result_errno, |
