libpq: Be strict about 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).

Author: Jelte Fennema-Nio <postgres@jeltef.nl>
Reviewed-by: Jacob Champion <jchampion@postgresql.org>
Discussion: https://www.postgresql.org/message-id/df892f9f-5923-4046-9d6f-8c48d8980b50@iki.fi
Backpatch-through: 18
master
Heikki Linnakangas 3 weeks ago
parent f6f0542266
commit e411a8d25a
  1. 2
      doc/src/sgml/protocol.sgml
  2. 21
      src/interfaces/libpq/fe-protocol3.c

@ -4136,7 +4136,7 @@ psql "dbname=postgres replication=database" -c "IDENTIFY_SYSTEM;"
message, indicated by the length field. message, indicated by the length field.
</para> </para>
<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 <productname>PostgreSQL</productname> server only sends keys up to
32 bytes, but the larger maximum size allows for future server 32 bytes, but the larger maximum size allows for future server
versions, as well as connection poolers and other middleware, to use versions, as well as connection poolers and other middleware, to use

@ -1569,6 +1569,27 @@ getBackendKeyData(PGconn *conn, int msgLength)
cancel_key_len = 5 + msgLength - (conn->inCursor - conn->inStart); 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 with length %d not allowed in protocol version 3.0 (must be 4 bytes)", cancel_key_len);
handleFatalError(conn);
return 0;
}
if (cancel_key_len < 4)
{
libpq_append_conn_error(conn, "received invalid BackendKeyData message: cancel key with length %d is too short (minimum 4 bytes)", cancel_key_len);
handleFatalError(conn);
return 0;
}
if (cancel_key_len > 256)
{
libpq_append_conn_error(conn, "received invalid BackendKeyData message: cancel key with length %d is too long (maximum 256 bytes)", cancel_key_len);
handleFatalError(conn);
return 0;
}
conn->be_cancel_key = malloc(cancel_key_len); conn->be_cancel_key = malloc(cancel_key_len);
if (conn->be_cancel_key == NULL) if (conn->be_cancel_key == NULL)
{ {

Loading…
Cancel
Save