pgpool2.git / summary / log / commit / refs
commit 3fb1d89cea0a6d7a098ac0a8851663c1a531b3e9
Author: Tatsuo Ishii <ishii@postgresql.org>
Date: Tue Sep 29 08:22:42 2026 +0000
Reject negative read length in pool_read2.
pool_read2() allocates buf2 sized to cp->len + len, consumes that many
bytes from the pending buffer, then loops reading from the socket
while len > 0. When len is zero or negative the loop never executes a
fresh read and the function falls straight through to "return
cp->buf2", handing the caller a pointer to whatever the previous
pool_read2() invocation happened to leave in the per-connection
buffer.
Callers compute len from on-the-wire length fields, e.g.
len = ntohl(hdr) - sizeof(hdr);
and several do so without bounds-checking. A backend that ships a
malformed message with a length smaller than the header (or a
negative value once cast to int32) drives pool_read2() into the
stale-buffer path. The stale bytes are then forwarded to the
frontend as ParameterStatus / ErrorResponse / etc. payloads,
leaking whatever the previous reply contained on this same
backend connection.
Add a guard at the top of pool_read2() that logs and returns NULL when
len < 0, before any buffer setup runs.
When len == 0, just retuns cp->buf2, rather than returning NULL to not
break existing callers relying on the behavior.
Reported-by: Emond Papegaaij <emond.papegaaij@gmail.com>
Reported-by: Claude code
Author: Tatsuo Ishii <ishii@postgresql.org>
Discussion: https://github.com/pgpool/pgpool2/issues/168
Backpatch-through: v4.3
src/utils/pool_stream.c | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/src/utils/pool_stream.c b/src/utils/pool_stream.c
index 0a9cc3576..df88c87f7 100644
--- a/src/utils/pool_stream.c
+++ b/src/utils/pool_stream.c
@@ -303,9 +303,9 @@ pool_read(POOL_CONNECTION *cp, void *buf, int len)
}
/*
-* read exactly len bytes from cp
-* returns buffer address on success otherwise NULL.
-*/
+ * read exactly len bytes from cp returns buffer address on success otherwise
+ * NULL. Returns NULL too when len < 0.
+ */
char *
pool_read2(POOL_CONNECTION *cp, int len)
{
@@ -314,7 +314,16 @@ pool_read2(POOL_CONNECTION *cp, int len)
int alloc_size;
int consume_size;
int readlen;
- MemoryContext oldContext = SwitchToConnectionContext(cp->isbackend);
+ MemoryContext oldContext;
+
+ if (len < 0)
+ {
+ ereport(LOG,
+ (errmsg("pool_read2: negative len %d, returning NULL", len)));
+ return NULL;
+ }
+
+ oldContext = SwitchToConnectionContext(cp->isbackend);
req_size = cp->len + len;
[parent: 2bb4b1738191]