Commit 26ec6b59 authored by Peter Eisentraut's avatar Peter Eisentraut

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
parent afa0d53d
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "storage/procsignal.h" #include "storage/procsignal.h"
#include "storage/shm_mq.h" #include "storage/shm_mq.h"
#include "storage/spin.h" #include "storage/spin.h"
#include "utils/memutils.h"
/* /*
* This structure represents the actual queue, stored in shared memory. * This structure represents the actual queue, stored in shared memory.
...@@ -360,6 +361,13 @@ shm_mq_sendv(shm_mq_handle *mqh, shm_mq_iovec *iov, int iovcnt, bool nowait) ...@@ -360,6 +361,13 @@ shm_mq_sendv(shm_mq_handle *mqh, shm_mq_iovec *iov, int iovcnt, bool nowait)
for (i = 0; i < iovcnt; ++i) for (i = 0; i < iovcnt; ++i)
nbytes += iov[i].len; 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. */ /* Try to write, or finish writing, the length word into the buffer. */
while (!mqh->mqh_length_word_complete) while (!mqh->mqh_length_word_complete)
{ {
...@@ -675,6 +683,17 @@ shm_mq_receive(shm_mq_handle *mqh, Size *nbytesp, void **datap, bool nowait) ...@@ -675,6 +683,17 @@ shm_mq_receive(shm_mq_handle *mqh, Size *nbytesp, void **datap, bool nowait)
} }
nbytes = mqh->mqh_expected_bytes; 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) if (mqh->mqh_partial_bytes == 0)
{ {
/* /*
...@@ -703,8 +722,13 @@ shm_mq_receive(shm_mq_handle *mqh, Size *nbytesp, void **datap, bool nowait) ...@@ -703,8 +722,13 @@ shm_mq_receive(shm_mq_handle *mqh, Size *nbytesp, void **datap, bool nowait)
{ {
Size newbuflen = Max(mqh->mqh_buflen, MQH_INITIAL_BUFSIZE); Size newbuflen = Max(mqh->mqh_buflen, MQH_INITIAL_BUFSIZE);
/*
* Double the buffer size until the payload fits, but limit to
* MaxAllocSize.
*/
while (newbuflen < nbytes) while (newbuflen < nbytes)
newbuflen *= 2; newbuflen *= 2;
newbuflen = Min(newbuflen, MaxAllocSize);
if (mqh->mqh_buffer != NULL) if (mqh->mqh_buffer != NULL)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment