This is an automated email from the ASF dual-hosted git repository.

leborchuk pushed a commit to branch REL_2_STABLE
in repository https://gitbox.apache.org/repos/asf/cloudberry.git

commit 9f3990bf5ee8531c3c2e8e7ff73a2b0ef233d946
Author: Tom Lane <[email protected]>
AuthorDate: Mon Dec 11 11:51:56 2023 -0500

    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/[email protected]
    (cherry picked from commit 07ce2432682d1b2d593d15283fe66e88cb27285e)
---
 src/backend/libpq/be-secure-openssl.c    | 15 +++++++++++----
 src/backend/libpq/pqcomm.c               | 22 ++++++++++++++++------
 src/interfaces/libpq/fe-secure-openssl.c | 16 ++++++++++++----
 src/interfaces/libpq/fe-secure.c         |  7 +++++++
 4 files changed, 46 insertions(+), 14 deletions(-)

diff --git a/src/backend/libpq/be-secure-openssl.c 
b/src/backend/libpq/be-secure-openssl.c
index e39952494e6..25afb28facd 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -450,6 +450,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)
@@ -486,7 +487,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")));
@@ -711,7 +712,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;
@@ -769,8 +770,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;
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index 9decd399ae7..7da63160690 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -1012,6 +1012,8 @@ pq_recvbuf(void)
        {
                int                     r;
 
+               errno = 0;
+
                r = secure_read(MyProcPort, PqRecvBuffer + PqRecvLength,
                                                PQ_RECV_BUFFER_SIZE - 
PqRecvLength);
 
@@ -1024,10 +1026,13 @@ pq_recvbuf(void)
                         * Careful: an ereport() that tries to write to the 
client would
                         * cause recursion to here, leading to stack overflow 
and core
                         * dump!  This message must go *only* to the postmaster 
log.
+                        *
+                        * If errno is zero, assume it's EOF and let the caller 
complain.
                         */
-                       ereport(COMMERROR,
-                                       (errcode_for_socket_access(),
-                                        errmsg("could not receive data from 
client: %m")));
+                       if (errno != 0)
+                               ereport(COMMERROR,
+                                               (errcode_for_socket_access(),
+                                                errmsg("could not receive data 
from client: %m")));
                        return EOF;
                }
                if (r == 0)
@@ -1165,6 +1170,8 @@ pq_getbyte_if_available(unsigned char *c)
        /* Put the socket into non-blocking mode */
        socket_set_nonblocking(true);
 
+       errno = 0;
+
        r = secure_read(MyProcPort, c, 1);
        if (r < 0)
        {
@@ -1181,10 +1188,13 @@ pq_getbyte_if_available(unsigned char *c)
                         * Careful: an ereport() that tries to write to the 
client would
                         * cause recursion to here, leading to stack overflow 
and core
                         * dump!  This message must go *only* to the postmaster 
log.
+                        *
+                        * If errno is zero, assume it's EOF and let the caller 
complain.
                         */
-                       ereport(COMMERROR,
-                                       (errcode_for_socket_access(),
-                                        errmsg("could not receive data from 
client: %m")));
+                       if (errno != 0)
+                               ereport(COMMERROR,
+                                               (errcode_for_socket_access(),
+                                                errmsg("could not receive data 
from client: %m")));
                        r = EOF;
                }
        }
diff --git a/src/interfaces/libpq/fe-secure-openssl.c 
b/src/interfaces/libpq/fe-secure-openssl.c
index 186799acf24..9a47ebef65c 100644
--- a/src/interfaces/libpq/fe-secure-openssl.c
+++ b/src/interfaces/libpq/fe-secure-openssl.c
@@ -207,7 +207,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 ||
@@ -315,7 +315,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)
@@ -1354,10 +1360,12 @@ open_client_SSL(PGconn *conn)
 {
        int                     r;
 
+       SOCK_ERRNO_SET(0);
        ERR_clear_error();
        r = SSL_connect(conn->ssl);
        if (r <= 0)
        {
+               int                     save_errno = SOCK_ERRNO;
                int                     err = SSL_get_error(conn->ssl, r);
                unsigned long ecode;
 
@@ -1374,10 +1382,10 @@ open_client_SSL(PGconn *conn)
                                {
                                        char            
sebuf[PG_STRERROR_R_BUFLEN];
 
-                                       if (r == -1)
+                                       if (r == -1 && save_errno != 0)
                                                
appendPQExpBuffer(&conn->errorMessage,
                                                                                
  libpq_gettext("SSL SYSCALL error: %s\n"),
-                                                                               
  SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
+                                                                               
  SOCK_STRERROR(save_errno, sebuf, sizeof(sebuf)));
                                        else
                                                
appendPQExpBufferStr(&conn->errorMessage,
                                                                                
         libpq_gettext("SSL SYSCALL error: EOF detected\n"));
diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c
index 3a736831564..3baad20c367 100644
--- a/src/interfaces/libpq/fe-secure.c
+++ b/src/interfaces/libpq/fe-secure.c
@@ -242,6 +242,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)
@@ -269,6 +271,11 @@ pqsecure_raw_read(PGconn *conn, void *ptr, size_t len)
                                                                                
                   "\tbefore or while processing the request.\n"));
                                break;
 
+                       case 0:
+                               /* If errno didn't get set, treat it as regular 
EOF */
+                               n = 0;
+                               break;
+
                        default:
                                appendPQExpBuffer(&conn->errorMessage,
                                                                  
libpq_gettext("could not receive data from server: %s\n"),


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to