aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/storage/ipc/procsignal.c23
-rw-r--r--src/backend/tcop/backend_startup.c55
-rw-r--r--src/backend/tcop/postgres.c15
-rw-r--r--src/backend/utils/init/globals.c5
-rw-r--r--src/backend/utils/init/postinit.c2
5 files changed, 59 insertions, 41 deletions
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 7d201965503..b7c39a4c5f0 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -63,8 +63,8 @@
typedef struct
{
pg_atomic_uint32 pss_pid;
- bool pss_cancel_key_valid;
- int32 pss_cancel_key;
+ int pss_cancel_key_len; /* 0 means no cancellation is possible */
+ char pss_cancel_key[MAX_CANCEL_KEY_LENGTH];
volatile sig_atomic_t pss_signalFlags[NUM_PROCSIGNALS];
slock_t pss_mutex; /* protects the above fields */
@@ -148,8 +148,7 @@ ProcSignalShmemInit(void)
SpinLockInit(&slot->pss_mutex);
pg_atomic_init_u32(&slot->pss_pid, 0);
- slot->pss_cancel_key_valid = false;
- slot->pss_cancel_key = 0;
+ slot->pss_cancel_key_len = 0;
MemSet(slot->pss_signalFlags, 0, sizeof(slot->pss_signalFlags));
pg_atomic_init_u64(&slot->pss_barrierGeneration, PG_UINT64_MAX);
pg_atomic_init_u32(&slot->pss_barrierCheckMask, 0);
@@ -163,12 +162,13 @@ ProcSignalShmemInit(void)
* Register the current process in the ProcSignal array
*/
void
-ProcSignalInit(bool cancel_key_valid, int32 cancel_key)
+ProcSignalInit(char *cancel_key, int cancel_key_len)
{
ProcSignalSlot *slot;
uint64 barrier_generation;
uint32 old_pss_pid;
+ Assert(cancel_key_len >= 0 && cancel_key_len <= MAX_CANCEL_KEY_LENGTH);
if (MyProcNumber < 0)
elog(ERROR, "MyProcNumber not set");
if (MyProcNumber >= NumProcSignalSlots)
@@ -199,8 +199,9 @@ ProcSignalInit(bool cancel_key_valid, int32 cancel_key)
pg_atomic_read_u64(&ProcSignal->psh_barrierGeneration);
pg_atomic_write_u64(&slot->pss_barrierGeneration, barrier_generation);
- slot->pss_cancel_key_valid = cancel_key_valid;
- slot->pss_cancel_key = cancel_key;
+ if (cancel_key_len > 0)
+ memcpy(slot->pss_cancel_key, cancel_key, cancel_key_len);
+ slot->pss_cancel_key_len = cancel_key_len;
pg_atomic_write_u32(&slot->pss_pid, MyProcPid);
SpinLockRelease(&slot->pss_mutex);
@@ -254,8 +255,7 @@ CleanupProcSignalState(int status, Datum arg)
/* Mark the slot as unused */
pg_atomic_write_u32(&slot->pss_pid, 0);
- slot->pss_cancel_key_valid = false;
- slot->pss_cancel_key = 0;
+ slot->pss_cancel_key_len = 0;
/*
* Make this slot look like it's absorbed all possible barriers, so that
@@ -725,7 +725,7 @@ procsignal_sigusr1_handler(SIGNAL_ARGS)
* fields in the ProcSignal slots.
*/
void
-SendCancelRequest(int backendPID, int32 cancelAuthCode)
+SendCancelRequest(int backendPID, char *cancel_key, int cancel_key_len)
{
Assert(backendPID != 0);
@@ -754,7 +754,8 @@ SendCancelRequest(int backendPID, int32 cancelAuthCode)
}
else
{
- match = slot->pss_cancel_key_valid && slot->pss_cancel_key == cancelAuthCode;
+ match = slot->pss_cancel_key_len == cancel_key_len &&
+ timingsafe_bcmp(slot->pss_cancel_key, cancel_key, cancel_key_len) == 0;
SpinLockRelease(&slot->pss_mutex);
diff --git a/src/backend/tcop/backend_startup.c b/src/backend/tcop/backend_startup.c
index 84e1c6f2831..dde8d5b3517 100644
--- a/src/backend/tcop/backend_startup.c
+++ b/src/backend/tcop/backend_startup.c
@@ -60,6 +60,7 @@ ConnectionTiming conn_timing = {.ready_for_use = TIMESTAMP_MINUS_INFINITY};
static void BackendInitialize(ClientSocket *client_sock, CAC_state cac);
static int ProcessSSLStartup(Port *port);
static int ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done);
+static void ProcessCancelRequestPacket(Port *port, void *pkt, int pktlen);
static void SendNegotiateProtocolVersion(List *unrecognized_protocol_options);
static void process_startup_packet_die(SIGNAL_ARGS);
static void StartupPacketTimeoutHandler(void);
@@ -565,28 +566,7 @@ ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done)
if (proto == CANCEL_REQUEST_CODE)
{
- /*
- * The client has sent a cancel request packet, not a normal
- * start-a-new-connection packet. Perform the necessary processing.
- * Nothing is sent back to the client.
- */
- CancelRequestPacket *canc;
- int backendPID;
- int32 cancelAuthCode;
-
- if (len != sizeof(CancelRequestPacket))
- {
- ereport(COMMERROR,
- (errcode(ERRCODE_PROTOCOL_VIOLATION),
- errmsg("invalid length of startup packet")));
- return STATUS_ERROR;
- }
- canc = (CancelRequestPacket *) buf;
- backendPID = (int) pg_ntoh32(canc->backendPID);
- cancelAuthCode = (int32) pg_ntoh32(canc->cancelAuthCode);
-
- if (backendPID != 0)
- SendCancelRequest(backendPID, cancelAuthCode);
+ ProcessCancelRequestPacket(port, buf, len);
/* Not really an error, but we don't want to proceed further */
return STATUS_ERROR;
}
@@ -887,6 +867,37 @@ ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done)
}
/*
+ * The client has sent a cancel request packet, not a normal
+ * start-a-new-connection packet. Perform the necessary processing. Nothing
+ * is sent back to the client.
+ */
+static void
+ProcessCancelRequestPacket(Port *port, void *pkt, int pktlen)
+{
+ CancelRequestPacket *canc;
+ int len;
+
+ if (pktlen < offsetof(CancelRequestPacket, cancelAuthCode))
+ {
+ ereport(COMMERROR,
+ (errcode(ERRCODE_PROTOCOL_VIOLATION),
+ errmsg("invalid length of query cancel packet")));
+ return;
+ }
+ len = pktlen - offsetof(CancelRequestPacket, cancelAuthCode);
+ if (len == 0 || len > 256)
+ {
+ ereport(COMMERROR,
+ (errcode(ERRCODE_PROTOCOL_VIOLATION),
+ errmsg("invalid length of query cancel key")));
+ return;
+ }
+
+ canc = (CancelRequestPacket *) pkt;
+ SendCancelRequest(pg_ntoh32(canc->backendPID), canc->cancelAuthCode, len);
+}
+
+/*
* Send a NegotiateProtocolVersion to the client. This lets the client know
* that they have either requested a newer minor protocol version than we are
* able to speak, or at least one protocol option that we don't understand, or
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index aec65007bb6..89189848862 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -4259,16 +4259,20 @@ PostgresMain(const char *dbname, const char *username)
* Generate a random cancel key, if this is a backend serving a
* connection. InitPostgres() will advertise it in shared memory.
*/
- Assert(!MyCancelKeyValid);
+ Assert(MyCancelKeyLength == 0);
if (whereToSendOutput == DestRemote)
{
- if (!pg_strong_random(&MyCancelKey, sizeof(int32)))
+ int len;
+
+ len = (MyProcPort == NULL || MyProcPort->proto >= PG_PROTOCOL(3, 2))
+ ? MAX_CANCEL_KEY_LENGTH : 4;
+ if (!pg_strong_random(&MyCancelKey, len))
{
ereport(ERROR,
(errcode(ERRCODE_INTERNAL_ERROR),
errmsg("could not generate random cancel key")));
}
- MyCancelKeyValid = true;
+ MyCancelKeyLength = len;
}
/*
@@ -4323,10 +4327,11 @@ PostgresMain(const char *dbname, const char *username)
{
StringInfoData buf;
- Assert(MyCancelKeyValid);
+ Assert(MyCancelKeyLength > 0);
pq_beginmessage(&buf, PqMsg_BackendKeyData);
pq_sendint32(&buf, (int32) MyProcPid);
- pq_sendint32(&buf, (int32) MyCancelKey);
+
+ pq_sendbytes(&buf, MyCancelKey, MyCancelKeyLength);
pq_endmessage(&buf);
/* Need not flush since ReadyForQuery will do it. */
}
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index b844f9fdaef..2152aad97d9 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -24,6 +24,7 @@
#include "miscadmin.h"
#include "postmaster/postmaster.h"
#include "storage/procnumber.h"
+#include "storage/procsignal.h"
ProtocolVersion FrontendProtocol;
@@ -48,8 +49,8 @@ pg_time_t MyStartTime;
TimestampTz MyStartTimestamp;
struct ClientSocket *MyClientSocket;
struct Port *MyProcPort;
-bool MyCancelKeyValid = false;
-int32 MyCancelKey = 0;
+char MyCancelKey[MAX_CANCEL_KEY_LENGTH];
+uint8 MyCancelKeyLength = 0;
int MyPMChildSlot;
/*
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 7958ea11b73..c09c4d404ba 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -753,7 +753,7 @@ InitPostgres(const char *in_dbname, Oid dboid,
*/
SharedInvalBackendInit(false);
- ProcSignalInit(MyCancelKeyValid, MyCancelKey);
+ ProcSignalInit(MyCancelKey, MyCancelKeyLength);
/*
* Also set up timeout handlers needed for backend operation. We need