v2-0002-libpq-Be-strict-about-accept-cancel-key-lengths.patch

text/x-patch

Filename: v2-0002-libpq-Be-strict-about-accept-cancel-key-lengths.patch
Type: text/x-patch
Part: 1
Message: Re: BackendKeyData is mandatory?

Patch

Format: format-patch
Series: patch v2-0002
Subject: libpq: Be strict about accept cancel key lengths
File+
doc/src/sgml/protocol.sgml 1 1
src/interfaces/libpq/fe-connect.c 3 0
src/interfaces/libpq/fe-protocol3.c 24 2
From 99144bd01618dee1f6d6f5b95aaa61ceada285db Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <github-tech@jeltef.nl>
Date: Wed, 25 Jun 2025 08:54:15 +0200
Subject: [PATCH v2 2/2] libpq: Be strict about accept cancel key lengths

The protocol documentation states that the maximum length of a cancel key
is 256 bytes. This starts checking for that limit in libpq. Otherwise
third party backend implementations will probably start using more bytes
anyway. We also start requiring that a protocol 3.0 connection does not
send a longer cancel key, to make sure that servers don't start breaking
old 3.0-only clients by accident. Finally this also restricts the
minimum key length to 4 bytes (both in the protocol spec and in the
libpq implementation).
---
 doc/src/sgml/protocol.sgml          |  2 +-
 src/interfaces/libpq/fe-connect.c   |  3 +++
 src/interfaces/libpq/fe-protocol3.c | 26 ++++++++++++++++++++++++--
 3 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml
index 0eb96360134..982f4a8d210 100644
--- a/doc/src/sgml/protocol.sgml
+++ b/doc/src/sgml/protocol.sgml
@@ -4160,7 +4160,7 @@ psql "dbname=postgres replication=database" -c "IDENTIFY_SYSTEM;"
          message, indicated by the length field.
         </para>
         <para>
-          The maximum key length is 256 bytes. The
+          The minimum and maximum key length are 4 and 256 bytes respectively. The
           <productname>PostgreSQL</productname> server only sends keys up to
           32 bytes, but the larger maximum size allows for future server
           versions, as well as connection poolers and other middleware, to use
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 51a9c416584..f094611fe0d 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -4322,6 +4322,9 @@ keep_going:						/* We will come back to here until there is
 				if (PQisBusy(conn))
 					return PGRES_POLLING_READING;
 
+				if (conn->status == CONNECTION_BAD)
+					goto error_return;
+
 				res = PQgetResult(conn);
 
 				/*
diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c
index 1599de757d1..29c51ede7ce 100644
--- a/src/interfaces/libpq/fe-protocol3.c
+++ b/src/interfaces/libpq/fe-protocol3.c
@@ -1547,13 +1547,31 @@ getBackendKeyData(PGconn *conn, int msgLength)
 
 	cancel_key_len = 5 + msgLength - (conn->inCursor - conn->inStart);
 
+	if (cancel_key_len != 4 && conn->pversion == PG_PROTOCOL(3, 0))
+	{
+		libpq_append_conn_error(conn, "received invalid BackendKeyData message: cancel key length %d is different from 4, which is not supported in version 3.0 of the protocol", cancel_key_len);
+		goto failure;
+	}
+
+	if (cancel_key_len < 4)
+	{
+		libpq_append_conn_error(conn, "received invalid BackendKeyData message: cancel key length %d is below minimum of 4 bytes", cancel_key_len);
+		goto failure;
+	}
+
+	if (cancel_key_len > 256)
+	{
+		libpq_append_conn_error(conn, "received invalid BackendKeyData message: cancel key length %d exceeds maximum of 256 bytes", cancel_key_len);
+		goto failure;
+	}
+
 	conn->be_cancel_key = malloc(cancel_key_len);
 	if (conn->be_cancel_key == NULL)
 	{
 		libpq_append_conn_error(conn, "out of memory");
-		/* discard the message */
-		return EOF;
+		goto failure;
 	}
+
 	if (pqGetnchar(conn->be_cancel_key, cancel_key_len, conn))
 	{
 		free(conn->be_cancel_key);
@@ -1562,6 +1580,10 @@ getBackendKeyData(PGconn *conn, int msgLength)
 	}
 	conn->be_cancel_key_len = cancel_key_len;
 	return 0;
+
+failure:
+	conn->status = CONNECTION_BAD;
+	return EOF;
 }
 
 
-- 
2.43.0