Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita460251

Browse files
committed
Make cancel request keys longer
Currently, the cancel request key is a 32-bit token, which isn't verymuch entropy. If you want to cancel another session's query, you canbrute-force it. In most environments, an unauthorized cancellation ofa query isn't very serious, but it nevertheless would be nice to havemore protection from it. Hence make the key longer, to make it harderto guess.The longer cancellation keys are generated when using the new protocolversion 3.2. For connections using version 3.0, short 4-bytes keys arestill 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 256bytes. This flexibility allows e.g. a connection pooler to add moreinformation to the cancel key, which might be useful for finding theconnection.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
1 parent285613c commita460251

File tree

14 files changed

+252
-84
lines changed

14 files changed

+252
-84
lines changed

‎doc/src/sgml/protocol.sgml

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4062,7 +4062,7 @@ psql "dbname=postgres replication=database" -c "IDENTIFY_SYSTEM;"
40624062
</varlistentry>
40634063

40644064
<varlistentry>
4065-
<term>Int32(12)</term>
4065+
<term>Int32</term>
40664066
<listitem>
40674067
<para>
40684068
Length of message contents in bytes, including self.
@@ -4080,14 +4080,29 @@ psql "dbname=postgres replication=database" -c "IDENTIFY_SYSTEM;"
40804080
</varlistentry>
40814081

40824082
<varlistentry>
4083-
<term>Int32</term>
4083+
<term>Byte<replaceable>n</replaceable></term>
40844084
<listitem>
40854085
<para>
4086-
The secret key of this backend.
4086+
The secret key of this backend. This field extends to the end of the
4087+
message, indicated by the length field.
4088+
</para>
4089+
<para>
4090+
The maximum key length is 256 bytes. The
4091+
<productname>PostgreSQL</productname> server only sends keys up to
4092+
32 bytes, but the larger maximum size allows for future server
4093+
versions, as well as connection poolers and other middleware, to use
4094+
longer keys. One possible use case is augmenting the server's key
4095+
with extra information. Middleware is therefore also encouraged to
4096+
not use up all of the bytes, in case multiple middleware
4097+
applications are layered on top of each other, each of which may
4098+
wrap the key with extra data.
40874099
</para>
40884100
</listitem>
40894101
</varlistentry>
40904102
</variablelist>
4103+
<para>
4104+
Before protocol version 3.2, the secret key was always 4 bytes long.
4105+
</para>
40914106
</listitem>
40924107
</varlistentry>
40934108

@@ -4293,14 +4308,18 @@ psql "dbname=postgres replication=database" -c "IDENTIFY_SYSTEM;"
42934308
</varlistentry>
42944309

42954310
<varlistentry>
4296-
<term>Int32</term>
4311+
<term>Byte<replaceable>n</replaceable></term>
42974312
<listitem>
42984313
<para>
4299-
The secret key for the target backend.
4314+
The secret key for the target backend. This field extends to the end of the
4315+
message, indicated by the length field. The maximum key length is 256 bytes.
43004316
</para>
43014317
</listitem>
43024318
</varlistentry>
43034319
</variablelist>
4320+
<para>
4321+
Before protocol version 3.2, the secret key was always 4 bytes long.
4322+
</para>
43044323
</listitem>
43054324
</varlistentry>
43064325

‎src/backend/storage/ipc/procsignal.c

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@
6363
typedefstruct
6464
{
6565
pg_atomic_uint32pss_pid;
66-
boolpss_cancel_key_valid;
67-
int32pss_cancel_key;
66+
intpss_cancel_key_len;/* 0 means no cancellation is possible */
67+
charpss_cancel_key[MAX_CANCEL_KEY_LENGTH];
6868
volatilesig_atomic_tpss_signalFlags[NUM_PROCSIGNALS];
6969
slock_tpss_mutex;/* protects the above fields */
7070

@@ -148,8 +148,7 @@ ProcSignalShmemInit(void)
148148

149149
SpinLockInit(&slot->pss_mutex);
150150
pg_atomic_init_u32(&slot->pss_pid,0);
151-
slot->pss_cancel_key_valid= false;
152-
slot->pss_cancel_key=0;
151+
slot->pss_cancel_key_len=0;
153152
MemSet(slot->pss_signalFlags,0,sizeof(slot->pss_signalFlags));
154153
pg_atomic_init_u64(&slot->pss_barrierGeneration,PG_UINT64_MAX);
155154
pg_atomic_init_u32(&slot->pss_barrierCheckMask,0);
@@ -163,12 +162,13 @@ ProcSignalShmemInit(void)
163162
*Register the current process in the ProcSignal array
164163
*/
165164
void
166-
ProcSignalInit(boolcancel_key_valid,int32cancel_key)
165+
ProcSignalInit(char*cancel_key,intcancel_key_len)
167166
{
168167
ProcSignalSlot*slot;
169168
uint64barrier_generation;
170169
uint32old_pss_pid;
171170

171+
Assert(cancel_key_len >=0&&cancel_key_len <=MAX_CANCEL_KEY_LENGTH);
172172
if (MyProcNumber<0)
173173
elog(ERROR,"MyProcNumber not set");
174174
if (MyProcNumber >=NumProcSignalSlots)
@@ -199,8 +199,9 @@ ProcSignalInit(bool cancel_key_valid, int32 cancel_key)
199199
pg_atomic_read_u64(&ProcSignal->psh_barrierGeneration);
200200
pg_atomic_write_u64(&slot->pss_barrierGeneration,barrier_generation);
201201

202-
slot->pss_cancel_key_valid=cancel_key_valid;
203-
slot->pss_cancel_key=cancel_key;
202+
if (cancel_key_len>0)
203+
memcpy(slot->pss_cancel_key,cancel_key,cancel_key_len);
204+
slot->pss_cancel_key_len=cancel_key_len;
204205
pg_atomic_write_u32(&slot->pss_pid,MyProcPid);
205206

206207
SpinLockRelease(&slot->pss_mutex);
@@ -254,8 +255,7 @@ CleanupProcSignalState(int status, Datum arg)
254255

255256
/* Mark the slot as unused */
256257
pg_atomic_write_u32(&slot->pss_pid,0);
257-
slot->pss_cancel_key_valid= false;
258-
slot->pss_cancel_key=0;
258+
slot->pss_cancel_key_len=0;
259259

260260
/*
261261
* Make this slot look like it's absorbed all possible barriers, so that
@@ -725,7 +725,7 @@ procsignal_sigusr1_handler(SIGNAL_ARGS)
725725
* fields in the ProcSignal slots.
726726
*/
727727
void
728-
SendCancelRequest(intbackendPID,int32cancelAuthCode)
728+
SendCancelRequest(intbackendPID,char*cancel_key,intcancel_key_len)
729729
{
730730
Assert(backendPID!=0);
731731

@@ -754,7 +754,8 @@ SendCancelRequest(int backendPID, int32 cancelAuthCode)
754754
}
755755
else
756756
{
757-
match=slot->pss_cancel_key_valid&&slot->pss_cancel_key==cancelAuthCode;
757+
match=slot->pss_cancel_key_len==cancel_key_len&&
758+
timingsafe_bcmp(slot->pss_cancel_key,cancel_key,cancel_key_len)==0;
758759

759760
SpinLockRelease(&slot->pss_mutex);
760761

‎src/backend/tcop/backend_startup.c

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ ConnectionTiming conn_timing = {.ready_for_use = TIMESTAMP_MINUS_INFINITY};
6060
staticvoidBackendInitialize(ClientSocket*client_sock,CAC_statecac);
6161
staticintProcessSSLStartup(Port*port);
6262
staticintProcessStartupPacket(Port*port,boolssl_done,boolgss_done);
63+
staticvoidProcessCancelRequestPacket(Port*port,void*pkt,intpktlen);
6364
staticvoidSendNegotiateProtocolVersion(List*unrecognized_protocol_options);
6465
staticvoidprocess_startup_packet_die(SIGNAL_ARGS);
6566
staticvoidStartupPacketTimeoutHandler(void);
@@ -565,28 +566,7 @@ ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done)
565566

566567
if (proto==CANCEL_REQUEST_CODE)
567568
{
568-
/*
569-
* The client has sent a cancel request packet, not a normal
570-
* start-a-new-connection packet. Perform the necessary processing.
571-
* Nothing is sent back to the client.
572-
*/
573-
CancelRequestPacket*canc;
574-
intbackendPID;
575-
int32cancelAuthCode;
576-
577-
if (len!=sizeof(CancelRequestPacket))
578-
{
579-
ereport(COMMERROR,
580-
(errcode(ERRCODE_PROTOCOL_VIOLATION),
581-
errmsg("invalid length of startup packet")));
582-
returnSTATUS_ERROR;
583-
}
584-
canc= (CancelRequestPacket*)buf;
585-
backendPID= (int)pg_ntoh32(canc->backendPID);
586-
cancelAuthCode= (int32)pg_ntoh32(canc->cancelAuthCode);
587-
588-
if (backendPID!=0)
589-
SendCancelRequest(backendPID,cancelAuthCode);
569+
ProcessCancelRequestPacket(port,buf,len);
590570
/* Not really an error, but we don't want to proceed further */
591571
returnSTATUS_ERROR;
592572
}
@@ -886,6 +866,37 @@ ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done)
886866
returnSTATUS_OK;
887867
}
888868

869+
/*
870+
* The client has sent a cancel request packet, not a normal
871+
* start-a-new-connection packet. Perform the necessary processing. Nothing
872+
* is sent back to the client.
873+
*/
874+
staticvoid
875+
ProcessCancelRequestPacket(Port*port,void*pkt,intpktlen)
876+
{
877+
CancelRequestPacket*canc;
878+
intlen;
879+
880+
if (pktlen< offsetof(CancelRequestPacket,cancelAuthCode))
881+
{
882+
ereport(COMMERROR,
883+
(errcode(ERRCODE_PROTOCOL_VIOLATION),
884+
errmsg("invalid length of query cancel packet")));
885+
return;
886+
}
887+
len=pktlen- offsetof(CancelRequestPacket,cancelAuthCode);
888+
if (len==0||len>256)
889+
{
890+
ereport(COMMERROR,
891+
(errcode(ERRCODE_PROTOCOL_VIOLATION),
892+
errmsg("invalid length of query cancel key")));
893+
return;
894+
}
895+
896+
canc= (CancelRequestPacket*)pkt;
897+
SendCancelRequest(pg_ntoh32(canc->backendPID),canc->cancelAuthCode,len);
898+
}
899+
889900
/*
890901
* Send a NegotiateProtocolVersion to the client. This lets the client know
891902
* that they have either requested a newer minor protocol version than we are

‎src/backend/tcop/postgres.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4259,16 +4259,20 @@ PostgresMain(const char *dbname, const char *username)
42594259
* Generate a random cancel key, if this is a backend serving a
42604260
* connection. InitPostgres() will advertise it in shared memory.
42614261
*/
4262-
Assert(!MyCancelKeyValid);
4262+
Assert(MyCancelKeyLength==0);
42634263
if (whereToSendOutput==DestRemote)
42644264
{
4265-
if (!pg_strong_random(&MyCancelKey,sizeof(int32)))
4265+
intlen;
4266+
4267+
len= (MyProcPort==NULL||MyProcPort->proto >=PG_PROTOCOL(3,2))
4268+
?MAX_CANCEL_KEY_LENGTH :4;
4269+
if (!pg_strong_random(&MyCancelKey,len))
42664270
{
42674271
ereport(ERROR,
42684272
(errcode(ERRCODE_INTERNAL_ERROR),
42694273
errmsg("could not generate random cancel key")));
42704274
}
4271-
MyCancelKeyValid=true;
4275+
MyCancelKeyLength=len;
42724276
}
42734277

42744278
/*
@@ -4323,10 +4327,11 @@ PostgresMain(const char *dbname, const char *username)
43234327
{
43244328
StringInfoDatabuf;
43254329

4326-
Assert(MyCancelKeyValid);
4330+
Assert(MyCancelKeyLength>0);
43274331
pq_beginmessage(&buf,PqMsg_BackendKeyData);
43284332
pq_sendint32(&buf, (int32)MyProcPid);
4329-
pq_sendint32(&buf, (int32)MyCancelKey);
4333+
4334+
pq_sendbytes(&buf,MyCancelKey,MyCancelKeyLength);
43304335
pq_endmessage(&buf);
43314336
/* Need not flush since ReadyForQuery will do it. */
43324337
}

‎src/backend/utils/init/globals.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include"miscadmin.h"
2525
#include"postmaster/postmaster.h"
2626
#include"storage/procnumber.h"
27+
#include"storage/procsignal.h"
2728

2829

2930
ProtocolVersionFrontendProtocol;
@@ -48,8 +49,8 @@ pg_time_tMyStartTime;
4849
TimestampTzMyStartTimestamp;
4950
structClientSocket*MyClientSocket;
5051
structPort*MyProcPort;
51-
boolMyCancelKeyValid= false;
52-
int32MyCancelKey=0;
52+
charMyCancelKey[MAX_CANCEL_KEY_LENGTH];
53+
uint8MyCancelKeyLength=0;
5354
intMyPMChildSlot;
5455

5556
/*

‎src/backend/utils/init/postinit.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -753,7 +753,7 @@ InitPostgres(const char *in_dbname, Oid dboid,
753753
*/
754754
SharedInvalBackendInit(false);
755755

756-
ProcSignalInit(MyCancelKeyValid,MyCancelKey);
756+
ProcSignalInit(MyCancelKey,MyCancelKeyLength);
757757

758758
/*
759759
* Also set up timeout handlers needed for backend operation. We need

‎src/include/libpq/pqcomm.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,15 +128,21 @@ typedef uint32 AuthRequest;
128128
*
129129
* The cancel request code must not match any protocol version number
130130
* we're ever likely to use. This random choice should do.
131+
*
132+
* Before PostgreSQL v18 and the protocol version bump from 3.0 to 3.2, the
133+
* cancel key was always 4 bytes. With protocol version 3.2, it's variable
134+
* length.
131135
*/
136+
132137
#defineCANCEL_REQUEST_CODE PG_PROTOCOL(1234,5678)
133138

134139
typedefstructCancelRequestPacket
135140
{
136141
/* Note that each field is stored in network byte order! */
137142
MsgTypecancelRequestCode;/* code to identify a cancel request */
138143
uint32backendPID;/* PID of client's backend */
139-
uint32cancelAuthCode;/* secret key to authorize cancel */
144+
charcancelAuthCode[FLEXIBLE_ARRAY_MEMBER];/* secret key to
145+
* authorize cancel */
140146
}CancelRequestPacket;
141147

142148
/* Application-Layer Protocol Negotiation is required for direct connections

‎src/include/miscadmin.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,8 @@ extern PGDLLIMPORT pg_time_t MyStartTime;
191191
externPGDLLIMPORTTimestampTzMyStartTimestamp;
192192
externPGDLLIMPORTstructPort*MyProcPort;
193193
externPGDLLIMPORTstructLatch*MyLatch;
194-
externPGDLLIMPORTboolMyCancelKeyValid;
195-
externPGDLLIMPORTint32MyCancelKey;
194+
externPGDLLIMPORTcharMyCancelKey[];
195+
externPGDLLIMPORTuint8MyCancelKeyLength;
196196
externPGDLLIMPORTintMyPMChildSlot;
197197

198198
externPGDLLIMPORTcharOutputFileName[];

‎src/include/storage/procsignal.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,26 @@ typedef enum
5656
PROCSIGNAL_BARRIER_SMGRRELEASE,/* ask smgr to close files */
5757
}ProcSignalBarrierType;
5858

59+
/*
60+
* Length of query cancel keys generated.
61+
*
62+
* Note that the protocol allows for longer keys, or shorter, but this is the
63+
* length we actually generate. Client code, and the server code that handles
64+
* incoming cancellation packets from clients, mustn't use this hardcoded
65+
* length.
66+
*/
67+
#defineMAX_CANCEL_KEY_LENGTH 32
68+
5969
/*
6070
* prototypes for functions in procsignal.c
6171
*/
6272
externSizeProcSignalShmemSize(void);
6373
externvoidProcSignalShmemInit(void);
6474

65-
externvoidProcSignalInit(boolcancel_key_valid,int32cancel_key);
75+
externvoidProcSignalInit(char*cancel_key,intcancel_key_len);
6676
externintSendProcSignal(pid_tpid,ProcSignalReasonreason,
6777
ProcNumberprocNumber);
68-
externvoidSendCancelRequest(intbackendPID,int32cancelAuthCode);
78+
externvoidSendCancelRequest(intbackendPID,char*cancel_key,intcancel_key_len);
6979

7080
externuint64EmitProcSignalBarrier(ProcSignalBarrierTypetype);
7181
externvoidWaitForProcSignalBarrier(uint64generation);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp