From 27c464e42a9e3cb3779d1ea63b835a3e191682d6 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Mon, 17 Jun 2019 22:14:04 +0900
Subject: [PATCH] Fix buffer overflow when processing SCRAM final message in
 libpq

When a client connects to a rogue server sending specifically-crafted
messages, this can suffice to execute arbitrary code as the operating
system account used by the client.

While on it, fix one error handling when decoding an incorrect salt
included in the first message received from server.

Author: Michael Paquier
Reviewed-by: Jonathan Katz, Heikki Linnakangas
Security: CVE-2019-10164
Backpatch-through: 10
---
 src/interfaces/libpq/fe-auth-scram.c | 21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/src/interfaces/libpq/fe-auth-scram.c b/src/interfaces/libpq/fe-auth-scram.c
index 603ef4c0020..a42cea966c4 100644
--- a/src/interfaces/libpq/fe-auth-scram.c
+++ b/src/interfaces/libpq/fe-auth-scram.c
@@ -586,6 +586,12 @@ read_server_first_message(fe_scram_state *state, char *input)
 	state->saltlen = pg_b64_decode(encoded_salt,
 								   strlen(encoded_salt),
 								   state->salt);
+	if (state->saltlen < 0)
+	{
+		printfPQExpBuffer(&conn->errorMessage,
+						  libpq_gettext("malformed SCRAM message (invalid salt)\n"));
+		return false;
+	}
 
 	iterations_str = read_attr_value(&input, 'i', &conn->errorMessage);
 	if (iterations_str == NULL)
@@ -616,6 +622,7 @@ read_server_final_message(fe_scram_state *state, char *input)
 {
 	PGconn	   *conn = state->conn;
 	char	   *encoded_server_signature;
+	char	   *decoded_server_signature;
 	int			server_signature_len;
 
 	state->server_final_message = strdup(input);
@@ -651,15 +658,27 @@ read_server_final_message(fe_scram_state *state, char *input)
 		printfPQExpBuffer(&conn->errorMessage,
 						  libpq_gettext("malformed SCRAM message (garbage at end of server-final-message)\n"));
 
+	server_signature_len = pg_b64_dec_len(strlen(encoded_server_signature));
+	decoded_server_signature = malloc(server_signature_len);
+	if (!decoded_server_signature)
+	{
+		printfPQExpBuffer(&conn->errorMessage,
+						  libpq_gettext("out of memory\n"));
+		return false;
+	}
+
 	server_signature_len = pg_b64_decode(encoded_server_signature,
 										 strlen(encoded_server_signature),
-										 state->ServerSignature);
+										 decoded_server_signature);
 	if (server_signature_len != SCRAM_KEY_LEN)
 	{
+		free(decoded_server_signature);
 		printfPQExpBuffer(&conn->errorMessage,
 						  libpq_gettext("malformed SCRAM message (invalid server signature)\n"));
 		return false;
 	}
+	memcpy(state->ServerSignature, decoded_server_signature, SCRAM_KEY_LEN);
+	free(decoded_server_signature);
 
 	return true;
 }
-- 
GitLab