aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/copyfromparse.c31
-rw-r--r--src/backend/libpq/auth.c3
-rw-r--r--src/backend/libpq/pqcomm.c5
-rw-r--r--src/backend/replication/walsender.c29
-rw-r--r--src/backend/tcop/postgres.c24
-rw-r--r--src/include/libpq/libpq.h9
6 files changed, 82 insertions, 19 deletions
diff --git a/src/backend/commands/copyfromparse.c b/src/backend/commands/copyfromparse.c
index 0813424768f..fdf57f15560 100644
--- a/src/backend/commands/copyfromparse.c
+++ b/src/backend/commands/copyfromparse.c
@@ -265,6 +265,7 @@ CopyGetData(CopyFromState cstate, void *databuf, int minread, int maxread)
{
/* Try to receive another message */
int mtype;
+ int maxmsglen;
readmessage:
HOLD_CANCEL_INTERRUPTS();
@@ -274,11 +275,33 @@ CopyGetData(CopyFromState cstate, void *databuf, int minread, int maxread)
ereport(ERROR,
(errcode(ERRCODE_CONNECTION_FAILURE),
errmsg("unexpected EOF on client connection with an open transaction")));
- if (pq_getmessage(cstate->fe_msgbuf, 0))
+ /* Validate message type and set packet size limit */
+ switch (mtype)
+ {
+ case 'd': /* CopyData */
+ maxmsglen = PQ_LARGE_MESSAGE_LIMIT;
+ break;
+ case 'c': /* CopyDone */
+ case 'f': /* CopyFail */
+ case 'H': /* Flush */
+ case 'S': /* Sync */
+ maxmsglen = PQ_SMALL_MESSAGE_LIMIT;
+ break;
+ default:
+ ereport(ERROR,
+ (errcode(ERRCODE_PROTOCOL_VIOLATION),
+ errmsg("unexpected message type 0x%02X during COPY from stdin",
+ mtype)));
+ maxmsglen = 0; /* keep compiler quiet */
+ break;
+ }
+ /* Now collect the message body */
+ if (pq_getmessage(cstate->fe_msgbuf, maxmsglen))
ereport(ERROR,
(errcode(ERRCODE_CONNECTION_FAILURE),
errmsg("unexpected EOF on client connection with an open transaction")));
RESUME_CANCEL_INTERRUPTS();
+ /* ... and process it */
switch (mtype)
{
case 'd': /* CopyData */
@@ -304,11 +327,7 @@ CopyGetData(CopyFromState cstate, void *databuf, int minread, int maxread)
*/
goto readmessage;
default:
- ereport(ERROR,
- (errcode(ERRCODE_PROTOCOL_VIOLATION),
- errmsg("unexpected message type 0x%02X during COPY from stdin",
- mtype)));
- break;
+ Assert(false); /* NOT REACHED */
}
}
avail = cstate->fe_msgbuf->len - cstate->fe_msgbuf->cursor;
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 27865b14a03..45a91235a45 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -210,6 +210,7 @@ static int PerformRadiusTransaction(const char *server, const char *secret, cons
/*
* Maximum accepted size of GSS and SSPI authentication tokens.
+ * We also use this as a limit on ordinary password packet lengths.
*
* Kerberos tickets are usually quite small, but the TGTs issued by Windows
* domain controllers include an authorization field known as the Privilege
@@ -724,7 +725,7 @@ recv_password_packet(Port *port)
}
initStringInfo(&buf);
- if (pq_getmessage(&buf, 0)) /* receive password */
+ if (pq_getmessage(&buf, PG_MAX_AUTH_TOKEN_LENGTH)) /* receive password */
{
/* EOF - pq_getmessage already logged a suitable message */
pfree(buf.data);
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index 8066ee1d1e0..b9ccd4473f7 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -1203,7 +1203,7 @@ pq_is_reading_msg(void)
* is removed. Also, s->cursor is initialized to zero for convenience
* in scanning the message contents.
*
- * If maxlen is not zero, it is an upper limit on the length of the
+ * maxlen is the upper limit on the length of the
* message we are willing to accept. We abort the connection (by
* returning EOF) if client tries to send more than that.
*
@@ -1230,8 +1230,7 @@ pq_getmessage(StringInfo s, int maxlen)
len = pg_ntoh32(len);
- if (len < 4 ||
- (maxlen > 0 && len > maxlen))
+ if (len < 4 || len > maxlen)
{
ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 52fe9aba660..6fefc3bedc4 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -1704,6 +1704,7 @@ static void
ProcessRepliesIfAny(void)
{
unsigned char firstchar;
+ int maxmsglen;
int r;
bool received = false;
@@ -1733,9 +1734,28 @@ ProcessRepliesIfAny(void)
break;
}
+ /* Validate message type and set packet size limit */
+ switch (firstchar)
+ {
+ case 'd':
+ maxmsglen = PQ_LARGE_MESSAGE_LIMIT;
+ break;
+ case 'c':
+ case 'X':
+ maxmsglen = PQ_SMALL_MESSAGE_LIMIT;
+ break;
+ default:
+ ereport(FATAL,
+ (errcode(ERRCODE_PROTOCOL_VIOLATION),
+ errmsg("invalid standby message type \"%c\"",
+ firstchar)));
+ maxmsglen = 0; /* keep compiler quiet */
+ break;
+ }
+
/* Read the message contents */
resetStringInfo(&reply_message);
- if (pq_getmessage(&reply_message, 0))
+ if (pq_getmessage(&reply_message, maxmsglen))
{
ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
@@ -1743,7 +1763,7 @@ ProcessRepliesIfAny(void)
proc_exit(0);
}
- /* Handle the very limited subset of commands expected in this phase */
+ /* ... and process it */
switch (firstchar)
{
/*
@@ -1776,10 +1796,7 @@ ProcessRepliesIfAny(void)
proc_exit(0);
default:
- ereport(FATAL,
- (errcode(ERRCODE_PROTOCOL_VIOLATION),
- errmsg("invalid standby message type \"%c\"",
- firstchar)));
+ Assert(false); /* NOT REACHED */
}
}
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 1216a2b397b..2d6d145ecc0 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -343,6 +343,7 @@ static int
SocketBackend(StringInfo inBuf)
{
int qtype;
+ int maxmsglen;
/*
* Get message type code from the frontend.
@@ -375,7 +376,9 @@ SocketBackend(StringInfo inBuf)
/*
* Validate message type code before trying to read body; if we have lost
* sync, better to say "command unknown" than to run out of memory because
- * we used garbage as a length word.
+ * we used garbage as a length word. We can also select a type-dependent
+ * limit on what a sane length word could be. (The limit could be chosen
+ * more granularly, but it's not clear it's worth fussing over.)
*
* This also gives us a place to set the doing_extended_query_message flag
* as soon as possible.
@@ -383,28 +386,37 @@ SocketBackend(StringInfo inBuf)
switch (qtype)
{
case 'Q': /* simple query */
+ maxmsglen = PQ_LARGE_MESSAGE_LIMIT;
doing_extended_query_message = false;
break;
case 'F': /* fastpath function call */
+ maxmsglen = PQ_LARGE_MESSAGE_LIMIT;
doing_extended_query_message = false;
break;
case 'X': /* terminate */
+ maxmsglen = PQ_SMALL_MESSAGE_LIMIT;
doing_extended_query_message = false;
ignore_till_sync = false;
break;
case 'B': /* bind */
+ case 'P': /* parse */
+ maxmsglen = PQ_LARGE_MESSAGE_LIMIT;
+ doing_extended_query_message = true;
+ break;
+
case 'C': /* close */
case 'D': /* describe */
case 'E': /* execute */
case 'H': /* flush */
- case 'P': /* parse */
+ maxmsglen = PQ_SMALL_MESSAGE_LIMIT;
doing_extended_query_message = true;
break;
case 'S': /* sync */
+ maxmsglen = PQ_SMALL_MESSAGE_LIMIT;
/* stop any active skip-till-Sync */
ignore_till_sync = false;
/* mark not-extended, so that a new error doesn't begin skip */
@@ -412,8 +424,13 @@ SocketBackend(StringInfo inBuf)
break;
case 'd': /* copy data */
+ maxmsglen = PQ_LARGE_MESSAGE_LIMIT;
+ doing_extended_query_message = false;
+ break;
+
case 'c': /* copy done */
case 'f': /* copy fail */
+ maxmsglen = PQ_SMALL_MESSAGE_LIMIT;
doing_extended_query_message = false;
break;
@@ -427,6 +444,7 @@ SocketBackend(StringInfo inBuf)
ereport(FATAL,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("invalid frontend message type %d", qtype)));
+ maxmsglen = 0; /* keep compiler quiet */
break;
}
@@ -435,7 +453,7 @@ SocketBackend(StringInfo inBuf)
* after the type code; we can read the message contents independently of
* the type.
*/
- if (pq_getmessage(inBuf, 0))
+ if (pq_getmessage(inBuf, maxmsglen))
return EOF; /* suitable message already logged */
RESUME_CANCEL_INTERRUPTS();
diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h
index 3ebbc8d6656..6c51b2f20fa 100644
--- a/src/include/libpq/libpq.h
+++ b/src/include/libpq/libpq.h
@@ -21,6 +21,15 @@
#include "storage/latch.h"
+/*
+ * Callers of pq_getmessage() must supply a maximum expected message size.
+ * By convention, if there's not any specific reason to use another value,
+ * use PQ_SMALL_MESSAGE_LIMIT for messages that shouldn't be too long, and
+ * PQ_LARGE_MESSAGE_LIMIT for messages that can be long.
+ */
+#define PQ_SMALL_MESSAGE_LIMIT 10000
+#define PQ_LARGE_MESSAGE_LIMIT (MaxAllocSize - 1)
+
typedef struct
{
void (*comm_reset) (void);