From db4456e674507480097259a2571838197a890693 Mon Sep 17 00:00:00 2001 From: Tatsuo Ishii Date: Mon, 17 Aug 2026 18:28:38 +0900 Subject: [PATCH v2] 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 Reported-by: Claude code Author: Tatsuo Ishii 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; -- 2.43.0