summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Eisentraut <peter@eisentraut.org>2020-10-19 08:52:25 +0200
committerPeter Eisentraut <peter@eisentraut.org>2020-10-20 15:35:31 +0200
commitd4e654d15467d68c85e05eaaa49291de9f81b3ed (patch)
tree3d8566a2c3764c9c60b01306108f4d1951c57250
parent5c78f797701b90546279b994791fc07af5bbb5c9 (diff)
Avoid invalid alloc size error in shm_mq
In shm_mq_receive(), a huge payload could trigger an unjustified "invalid memory alloc request size" error due to the way the buffer size is increased. Add error checks (documenting the upper limit) and avoid the error by limiting the allocation size to MaxAllocSize. Author: Markus Wanner <markus.wanner@2ndquadrant.com> Discussion: https://www.postgresql.org/message-id/flat/3bb363e7-ac04-0ac4-9fe8-db1148755bfa%402ndquadrant.com
-rw-r--r--src/backend/storage/ipc/shm_mq.c24
1 files changed, 24 insertions, 0 deletions
diff --git a/src/backend/storage/ipc/shm_mq.c b/src/backend/storage/ipc/shm_mq.c
index 3721029d254..2ca7e571ff2 100644
--- a/src/backend/storage/ipc/shm_mq.c
+++ b/src/backend/storage/ipc/shm_mq.c
@@ -23,6 +23,7 @@
#include "storage/procsignal.h"
#include "storage/shm_mq.h"
#include "storage/spin.h"
+#include "utils/memutils.h"
/*
* This structure represents the actual queue, stored in shared memory.
@@ -359,6 +360,13 @@ shm_mq_sendv(shm_mq_handle *mqh, shm_mq_iovec *iov, int iovcnt, bool nowait)
for (i = 0; i < iovcnt; ++i)
nbytes += iov[i].len;
+ /* Prevent writing messages overwhelming the receiver. */
+ if (nbytes > MaxAllocSize)
+ ereport(ERROR,
+ (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ errmsg("cannot send a message of size %zu via shared memory queue",
+ nbytes)));
+
/* Try to write, or finish writing, the length word into the buffer. */
while (!mqh->mqh_length_word_complete)
{
@@ -652,6 +660,17 @@ shm_mq_receive(shm_mq_handle *mqh, Size *nbytesp, void **datap, bool nowait)
}
nbytes = mqh->mqh_expected_bytes;
+ /*
+ * Should be disallowed on the sending side already, but better check and
+ * error out on the receiver side as well rather than trying to read a
+ * prohibitively large message.
+ */
+ if (nbytes > MaxAllocSize)
+ ereport(ERROR,
+ (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ errmsg("invalid message size %zu in shared memory queue",
+ nbytes)));
+
if (mqh->mqh_partial_bytes == 0)
{
/*
@@ -680,8 +699,13 @@ shm_mq_receive(shm_mq_handle *mqh, Size *nbytesp, void **datap, bool nowait)
{
Size newbuflen = Max(mqh->mqh_buflen, MQH_INITIAL_BUFSIZE);
+ /*
+ * Double the buffer size until the payload fits, but limit to
+ * MaxAllocSize.
+ */
while (newbuflen < nbytes)
newbuflen *= 2;
+ newbuflen = Min(newbuflen, MaxAllocSize);
if (mqh->mqh_buffer != NULL)
{