Skip to content

Commit bf8835e

Browse files
committed
libpq: Bail out during SSL/GSS negotiation errors
This commit changes libpq so that errors reported by the backend during the protocol negotiation for SSL and GSS are discarded by the client, as these may include bytes that could be consumed by the client and write arbitrary bytes to a client's terminal. A failure with the SSL negotiation now leads to an error immediately reported, without a retry on any other methods allowed, like a fallback to a plaintext connection. A failure with GSS discards the error message received, and we allow a fallback as it may be possible that the error is caused by a connection attempt with a pre-11 server, GSS encryption having been introduced in v12. This was a problem only with v17 and newer versions; older versions discard the error message already in this case, assuming a failure caused by a lack of support for GSS encryption. Author: Jacob Champion Reviewed-by: Peter Eisentraut, Heikki Linnakangas, Michael Paquier Security: CVE-2024-10977 Backpatch-through: 12
1 parent 5d4298e commit bf8835e

File tree

3 files changed

+22
-35
lines changed

3 files changed

+22
-35
lines changed

doc/src/sgml/protocol.sgml

+11-10
Original file line numberDiff line numberDiff line change
@@ -1508,10 +1508,10 @@ SELCT 1/0;<!-- this typo is intentional -->
15081508

15091509
<para>
15101510
The frontend should also be prepared to handle an ErrorMessage
1511-
response to SSLRequest from the server. This would only occur if
1512-
the server predates the addition of <acronym>SSL</acronym> support
1513-
to <productname>PostgreSQL</productname>. (Such servers are now very ancient,
1514-
and likely do not exist in the wild anymore.)
1511+
response to SSLRequest from the server. The frontend should not display
1512+
this error message to the user/application, since the server has not been
1513+
authenticated
1514+
(<ulink url="https://www.postgresql.org/support/security/CVE-2024-10977/">CVE-2024-10977</ulink>).
15151515
In this case the connection must
15161516
be closed, but the frontend might choose to open a fresh connection
15171517
and proceed without requesting <acronym>SSL</acronym>.
@@ -1621,12 +1621,13 @@ SELCT 1/0;<!-- this typo is intentional -->
16211621

16221622
<para>
16231623
The frontend should also be prepared to handle an ErrorMessage
1624-
response to GSSENCRequest from the server. This would only occur if
1625-
the server predates the addition of <acronym>GSSAPI</acronym> encryption
1626-
support to <productname>PostgreSQL</productname>. In this case the
1627-
connection must be closed, but the frontend might choose to open a fresh
1628-
connection and proceed without requesting <acronym>GSSAPI</acronym>
1629-
encryption.
1624+
response to GSSENCRequest from the server. The frontend should not display
1625+
this error message to the user/application, since the server has not been
1626+
authenticated
1627+
(<ulink url="https://www.postgresql.org/support/security/CVE-2024-10977/">CVE-2024-10977</ulink>).
1628+
In this case the connection must be closed, but the frontend might choose
1629+
to open a fresh connection and proceed without requesting
1630+
<acronym>GSSAPI</acronym> encryption.
16301631
</para>
16311632

16321633
<para>

src/interfaces/libpq/fe-connect.c

+10-24
Original file line numberDiff line numberDiff line change
@@ -3509,22 +3509,12 @@ PQconnectPoll(PGconn *conn)
35093509
{
35103510
/*
35113511
* Server failure of some sort, such as failure to
3512-
* fork a backend process. We need to process and
3513-
* report the error message, which might be formatted
3514-
* according to either protocol 2 or protocol 3.
3515-
* Rather than duplicate the code for that, we flip
3516-
* into AWAITING_RESPONSE state and let the code there
3517-
* deal with it. Note we have *not* consumed the "E"
3518-
* byte here.
3512+
* fork a backend process. Don't bother retrieving
3513+
* the error message; we should not trust it as the
3514+
* server has not been authenticated yet.
35193515
*/
3520-
conn->status = CONNECTION_AWAITING_RESPONSE;
3521-
3522-
/*
3523-
* Don't fall back to a plaintext connection after
3524-
* reading the error.
3525-
*/
3526-
conn->failed_enc_methods |= conn->allowed_enc_methods & (~conn->current_enc_method);
3527-
goto keep_going;
3516+
libpq_append_conn_error(conn, "server sent an error response during SSL exchange");
3517+
goto error_return;
35283518
}
35293519
else
35303520
{
@@ -3600,13 +3590,9 @@ PQconnectPoll(PGconn *conn)
36003590
{
36013591
/*
36023592
* Server failure of some sort, possibly protocol
3603-
* version support failure. We need to process and
3604-
* report the error message, which might be formatted
3605-
* according to either protocol 2 or protocol 3.
3606-
* Rather than duplicate the code for that, we flip
3607-
* into AWAITING_RESPONSE state and let the code there
3608-
* deal with it. Note we have *not* consumed the "E"
3609-
* byte here.
3593+
* version support failure. Don't bother retrieving
3594+
* the error message; we should not trust it anyway as
3595+
* the server has not authenticated yet.
36103596
*
36113597
* Note that unlike on an error response to
36123598
* SSLRequest, we allow falling back to SSL or
@@ -3615,8 +3601,8 @@ PQconnectPoll(PGconn *conn)
36153601
* response might mean that we are connecting to a
36163602
* pre-v12 server.
36173603
*/
3618-
conn->status = CONNECTION_AWAITING_RESPONSE;
3619-
goto keep_going;
3604+
libpq_append_conn_error(conn, "server sent an error response during GSS encryption exchange");
3605+
CONNECTION_FAILED();
36203606
}
36213607

36223608
/* mark byte consumed */

src/interfaces/libpq/t/005_negotiate_encryption.pl

+1-1
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ BEGIN
455455
connect_test(
456456
$node,
457457
"user=testuser gssencmode=prefer sslmode=disable",
458-
'connect, v2error -> fail');
458+
'connect, v2error, reconnect, v2error -> fail');
459459
$node->restart;
460460

461461
$node->safe_psql(

0 commit comments

Comments
 (0)