aboutsummaryrefslogtreecommitdiff
path: root/src/interfaces/libpq/fe-protocol3.c
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2025-04-02 16:41:48 +0300
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2025-04-02 16:41:48 +0300
commita460251f0a1ac987f0225203ff9593704da0b1a9 (patch)
tree009893fb5dc0e934b15abf6eabfe20fda63b3d4d /src/interfaces/libpq/fe-protocol3.c
parent285613c60a7aff5daaf281c67002483b0d26e715 (diff)
downloadpostgresql-a460251f0a1ac987f0225203ff9593704da0b1a9.tar.gz
postgresql-a460251f0a1ac987f0225203ff9593704da0b1a9.zip
Make cancel request keys longer
Currently, the cancel request key is a 32-bit token, which isn't very much entropy. If you want to cancel another session's query, you can brute-force it. In most environments, an unauthorized cancellation of a query isn't very serious, but it nevertheless would be nice to have more protection from it. Hence make the key longer, to make it harder to guess. The longer cancellation keys are generated when using the new protocol version 3.2. For connections using version 3.0, short 4-bytes keys are still used. The new longer key length is not hardcoded in the protocol anymore, the client is expected to deal with variable length keys, up to 256 bytes. This flexibility allows e.g. a connection pooler to add more information to the cancel key, which might be useful for finding the connection. Reviewed-by: Jelte Fennema-Nio <postgres@jeltef.nl> Reviewed-by: Robert Haas <robertmhaas@gmail.com> (earlier versions) Discussion: https://www.postgresql.org/message-id/508d0505-8b7a-4864-a681-e7e5edfe32aa@iki.fi
Diffstat (limited to 'src/interfaces/libpq/fe-protocol3.c')
-rw-r--r--src/interfaces/libpq/fe-protocol3.c45
1 files changed, 42 insertions, 3 deletions
diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c
index 7ba49ea4592..d85910f41fc 100644
--- a/src/interfaces/libpq/fe-protocol3.c
+++ b/src/interfaces/libpq/fe-protocol3.c
@@ -48,6 +48,7 @@ static int getRowDescriptions(PGconn *conn, int msgLength);
static int getParamDescriptions(PGconn *conn, int msgLength);
static int getAnotherTuple(PGconn *conn, int msgLength);
static int getParameterStatus(PGconn *conn);
+static int getBackendKeyData(PGconn *conn, int msgLength);
static int getNotify(PGconn *conn);
static int getCopyStart(PGconn *conn, ExecStatusType copytype);
static int getReadyForQuery(PGconn *conn);
@@ -308,9 +309,7 @@ pqParseInput3(PGconn *conn)
* just as easy to handle it as part of the main loop.
* Save the data and continue processing.
*/
- if (pqGetInt(&(conn->be_pid), 4, conn))
- return;
- if (pqGetInt(&(conn->be_key), 4, conn))
+ if (getBackendKeyData(conn, msgLength))
return;
break;
case PqMsg_RowDescription:
@@ -1524,6 +1523,46 @@ getParameterStatus(PGconn *conn)
return 0;
}
+/*
+ * parseInput subroutine to read a BackendKeyData message.
+ * Entry: 'v' message type and length have already been consumed.
+ * Exit: returns 0 if successfully consumed message.
+ * returns EOF if not enough data.
+ */
+static int
+getBackendKeyData(PGconn *conn, int msgLength)
+{
+ uint8 cancel_key_len;
+
+ if (conn->be_cancel_key)
+ {
+ free(conn->be_cancel_key);
+ conn->be_cancel_key = NULL;
+ conn->be_cancel_key_len = 0;
+ }
+
+ if (pqGetInt(&(conn->be_pid), 4, conn))
+ return EOF;
+
+ cancel_key_len = 5 + msgLength - (conn->inCursor - conn->inStart);
+
+ 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;
+ }
+ if (pqGetnchar(conn->be_cancel_key, cancel_key_len, conn))
+ {
+ free(conn->be_cancel_key);
+ conn->be_cancel_key = NULL;
+ return EOF;
+ }
+ conn->be_cancel_key_len = cancel_key_len;
+ return 0;
+}
+
/*
* Attempt to read a Notify response message.