From 99144bd01618dee1f6d6f5b95aaa61ceada285db Mon Sep 17 00:00:00 2001 From: Jelte Fennema-Nio 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. - The maximum key length is 256 bytes. The + The minimum and maximum key length are 4 and 256 bytes respectively. The PostgreSQL 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