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

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

commit e764fc2972cef0fa50132e69b919dd44a798cefb
Author: Michael Paquier <[email protected]>
AuthorDate: Mon May 11 05:13:51 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 | 5 +++--
 4 files changed, 12 insertions(+), 9 deletions(-)

diff --git a/src/backend/libpq/auth-scram.c b/src/backend/libpq/auth-scram.c
index f9e1026a12c..761507efc32 100644
--- a/src/backend/libpq/auth-scram.c
+++ b/src/backend/libpq/auth-scram.c
@@ -542,7 +542,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, SCRAM_KEY_LEN) == 0;
+       return timingsafe_bcmp(computed_key, server_key, SCRAM_KEY_LEN) == 0;
 }
 
 
@@ -1082,9 +1082,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;
@@ -1136,7 +1136,7 @@ verify_client_proof(scram_state *state)
        if (scram_H(ClientKey, SCRAM_KEY_LEN, client_StoredKey) < 0)
                elog(ERROR, "could not hash stored key");
 
-       if (memcmp(client_StoredKey, state->StoredKey, SCRAM_KEY_LEN) != 0)
+       if (timingsafe_bcmp(client_StoredKey, state->StoredKey, SCRAM_KEY_LEN) 
!= 0)
                return false;
 
        return true;
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 0809ff4e7ef..b0e1f15c829 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -3873,7 +3873,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 3fcad991a7e..69a7c67e716 100644
--- a/src/backend/libpq/crypt.c
+++ b/src/backend/libpq/crypt.c
@@ -196,7 +196,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
        {
@@ -261,7 +262,8 @@ plain_crypt_verify(const char *role, const char 
*shadow_pass,
                                 */
                                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 0c1c4cd7e53..b485305d728 100644
--- a/src/interfaces/libpq/fe-auth-scram.c
+++ b/src/interfaces/libpq/fe-auth-scram.c
@@ -635,7 +635,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)
        {
                appendPQExpBufferStr(&conn->errorMessage,
                                                         libpq_gettext("invalid 
SCRAM response (nonce mismatch)\n"));
@@ -864,7 +864,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, 
SCRAM_KEY_LEN) != 0)
+       if (timingsafe_bcmp(expected_ServerSignature, state->ServerSignature,
+                                               SCRAM_KEY_LEN) != 0)
                *match = false;
        else
                *match = true;


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

Reply via email to