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

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

commit cccceecba69dd313f95644eb6065e1907435f20f
Author: Michael Paquier <[email protected]>
AuthorDate: Mon May 11 05:13:49 2026 -0700

    Apply timingsafe_bcmp() in authentication paths
    
    This commit applies timingsafe_bcmp() to authentication paths that
    handle attributes or data previously compared with memcpy() or strcmp(),
    which are sensitive to timing attacks.
    
    The following data is concerned by this change, some being in the
    backend and some in the frontend:
    - For a SCRAM or MD5 password, the computed key or the MD5 hash compared
    with a password during a plain authentication.
    - For a SCRAM exchange, the stored key, the client's final nonce and the
    server nonce.
    - RADIUS (up to v18), the encrypted password.
    - For MD5 authentication, the MD5(MD5()) hash.
    
    Reported-by: Joe Conway <[email protected]>
    Security: CVE-2026-6478
    Author: Michael Paquier <[email protected]>
    Reviewed-by: John Naylor <[email protected]>
    Backpatch-through: 14
---
 src/backend/libpq/auth-scram.c       | 8 ++++----
 src/backend/libpq/auth.c             | 2 +-
 src/backend/libpq/crypt.c            | 6 ++++--
 src/interfaces/libpq/fe-auth-scram.c | 6 +++---
 4 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/src/backend/libpq/auth-scram.c b/src/backend/libpq/auth-scram.c
index 9b286aa4d7f..1b9e1cc0cc1 100644
--- a/src/backend/libpq/auth-scram.c
+++ b/src/backend/libpq/auth-scram.c
@@ -577,7 +577,7 @@ scram_verify_plain_password(const char *username, const 
char *password,
         * Compare the secret's Server Key with the one computed from the
         * user-supplied password.
         */
-       return memcmp(computed_key, server_key, key_length) == 0;
+       return timingsafe_bcmp(computed_key, server_key, key_length) == 0;
 }
 
 
@@ -1125,9 +1125,9 @@ verify_final_nonce(scram_state *state)
 
        if (final_nonce_len != client_nonce_len + server_nonce_len)
                return false;
-       if (memcmp(state->client_final_nonce, state->client_nonce, 
client_nonce_len) != 0)
+       if (timingsafe_bcmp(state->client_final_nonce, state->client_nonce, 
client_nonce_len) != 0)
                return false;
-       if (memcmp(state->client_final_nonce + client_nonce_len, 
state->server_nonce, server_nonce_len) != 0)
+       if (timingsafe_bcmp(state->client_final_nonce + client_nonce_len, 
state->server_nonce, server_nonce_len) != 0)
                return false;
 
        return true;
@@ -1182,7 +1182,7 @@ verify_client_proof(scram_state *state)
                                client_StoredKey, &errstr) < 0)
                elog(ERROR, "could not hash stored key: %s", errstr);
 
-       if (memcmp(client_StoredKey, state->StoredKey, state->key_length) != 0)
+       if (timingsafe_bcmp(client_StoredKey, state->StoredKey, 
state->key_length) != 0)
                return false;
 
        return true;
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 98dd56b113e..b6021e169dd 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -3649,7 +3649,7 @@ PerformRadiusTransaction(const char *server, const char 
*secret, const char *por
                }
                pfree(cryptvector);
 
-               if (memcmp(receivepacket->vector, encryptedpassword, 
RADIUS_VECTOR_LENGTH) != 0)
+               if (timingsafe_bcmp(receivepacket->vector, encryptedpassword, 
RADIUS_VECTOR_LENGTH) != 0)
                {
                        ereport(LOG,
                                        (errmsg("RADIUS response from %s has 
incorrect MD5 signature",
diff --git a/src/backend/libpq/crypt.c b/src/backend/libpq/crypt.c
index ef496a0bea9..3e67e75fe84 100644
--- a/src/backend/libpq/crypt.c
+++ b/src/backend/libpq/crypt.c
@@ -197,7 +197,8 @@ md5_crypt_verify(const char *role, const char *shadow_pass,
                return STATUS_ERROR;
        }
 
-       if (strcmp(client_pass, crypt_pwd) == 0)
+       if (strlen(client_pass) == strlen(crypt_pwd) &&
+               timingsafe_bcmp(client_pass, crypt_pwd, strlen(crypt_pwd)) == 0)
                retval = STATUS_OK;
        else
        {
@@ -259,7 +260,8 @@ plain_crypt_verify(const char *role, const char 
*shadow_pass,
                                *logdetail = errstr;
                                return STATUS_ERROR;
                        }
-                       if (strcmp(crypt_client_pass, shadow_pass) == 0)
+                       if (strlen(crypt_client_pass) == strlen(shadow_pass) &&
+                               timingsafe_bcmp(crypt_client_pass, shadow_pass, 
strlen(shadow_pass)) == 0)
                                return STATUS_OK;
                        else
                        {
diff --git a/src/interfaces/libpq/fe-auth-scram.c 
b/src/interfaces/libpq/fe-auth-scram.c
index 36bd2cdb011..89344a0a956 100644
--- a/src/interfaces/libpq/fe-auth-scram.c
+++ b/src/interfaces/libpq/fe-auth-scram.c
@@ -639,7 +639,7 @@ read_server_first_message(fe_scram_state *state, char 
*input)
 
        /* Verify immediately that the server used our part of the nonce */
        if (strlen(nonce) < strlen(state->client_nonce) ||
-               memcmp(nonce, state->client_nonce, strlen(state->client_nonce)) 
!= 0)
+               timingsafe_bcmp(nonce, state->client_nonce, 
strlen(state->client_nonce)) != 0)
        {
                libpq_append_conn_error(conn, "invalid SCRAM response (nonce 
mismatch)");
                return false;
@@ -886,8 +886,8 @@ verify_server_signature(fe_scram_state *state, bool *match,
        pg_hmac_free(ctx);
 
        /* signature processed, so now check after it */
-       if (memcmp(expected_ServerSignature, state->ServerSignature,
-                          state->key_length) != 0)
+       if (timingsafe_bcmp(expected_ServerSignature, state->ServerSignature,
+                                               state->key_length) != 0)
                *match = false;
        else
                *match = true;


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

Reply via email to