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.
</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

@ -1569,6 +1569,27 @@ 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 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);
if (conn->be_cancel_key == NULL)
{

Loading…
Cancel
Save