postgres.git / summary / log / commit / refs
commit f1298a4c207262efe023af92ca76bef2c5227c56
Author: Andrew Dunstan <andrew@dunslane.net>
Date: Sun Mar 29 13:06:54 2026 +0000
First released in: 15.18, 16.14, 17.10, 18.4
Fix multiple bugs in astreamer pipeline code.
astreamer_tar_parser_content() sent the wrong data pointer when
forwarding MEMBER_TRAILER padding to the next streamer. After
astreamer_buffer_until() buffers the padding bytes, the 'data'
pointer has been advanced past them, but the code passed 'data'
instead of bbs_buffer.data. This caused the downstream consumer
to receive bytes from after the padding rather than the padding
itself, and could read past the end of the input buffer.
astreamer_gzip_decompressor_content() only checked for
Z_STREAM_ERROR from inflate(), silently ignoring Z_DATA_ERROR
(corrupted data) and Z_MEM_ERROR (out of memory). Fix by
treating any return other than Z_OK, Z_STREAM_END, and
Z_BUF_ERROR as fatal.
astreamer_gzip_decompressor_free() missed calling inflateEnd() to
release zlib's internal decompression state.
astreamer_tar_parser_free() neglected to pfree() the streamer
struct itself, leaking it.
astreamer_extractor_content() did not check the return value of
fclose() when closing an extracted file. A deferred write error
(e.g., disk full on buffered I/O) would be silently lost.
Discussion: https://postgr.es/m/results/98c6b630-acbb-44a7-97fa-1692ce2b827c@dunslane.net
Reviewed-By: Tom Lane <tgl@sss.pgh.pa.us>
Backpatch-through: 15
src/bin/pg_basebackup/bbstreamer_file.c | 4 +++-
src/bin/pg_basebackup/bbstreamer_gzip.c | 10 ++++++++--
src/bin/pg_basebackup/bbstreamer_tar.c | 4 +++-
3 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/src/bin/pg_basebackup/bbstreamer_file.c b/src/bin/pg_basebackup/bbstreamer_file.c
index 0be39dddc97..2ccd772a40c 100644
--- a/src/bin/pg_basebackup/bbstreamer_file.c
+++ b/src/bin/pg_basebackup/bbstreamer_file.c
@@ -263,7 +263,9 @@ bbstreamer_extractor_content(bbstreamer *streamer, bbstreamer_member *member,
case BBSTREAMER_MEMBER_TRAILER:
if (mystreamer->file == NULL)
break;
- fclose(mystreamer->file);
+ if (fclose(mystreamer->file) != 0)
+ pg_fatal("could not close file \"%s\": %m",
+ mystreamer->filename);
mystreamer->file = NULL;
break;
diff --git a/src/bin/pg_basebackup/bbstreamer_gzip.c b/src/bin/pg_basebackup/bbstreamer_gzip.c
index d0fa38610c1..57aed9e26c3 100644
--- a/src/bin/pg_basebackup/bbstreamer_gzip.c
+++ b/src/bin/pg_basebackup/bbstreamer_gzip.c
@@ -292,8 +292,9 @@ bbstreamer_gzip_decompressor_content(bbstreamer *streamer,
*/
res = inflate(zs, Z_NO_FLUSH);
- if (res == Z_STREAM_ERROR)
- pg_fatal("could not decompress data: %s", zs->msg);
+ if (res != Z_OK && res != Z_STREAM_END && res != Z_BUF_ERROR)
+ pg_fatal("could not decompress data: %s",
+ zs->msg ? zs->msg : "unknown error");
mystreamer->bytes_written =
mystreamer->base.bbs_buffer.maxlen - zs->avail_out;
@@ -338,7 +339,12 @@ bbstreamer_gzip_decompressor_finalize(bbstreamer *streamer)
static void
bbstreamer_gzip_decompressor_free(bbstreamer *streamer)
{
+ bbstreamer_gzip_decompressor *mystreamer;
+
+ mystreamer = (bbstreamer_gzip_decompressor *) streamer;
+
bbstreamer_free(streamer->bbs_next);
+ inflateEnd(&mystreamer->zstream);
pfree(streamer->bbs_buffer.data);
pfree(streamer);
}
diff --git a/src/bin/pg_basebackup/bbstreamer_tar.c b/src/bin/pg_basebackup/bbstreamer_tar.c
index dec71ea65b3..d37db4d28a2 100644
--- a/src/bin/pg_basebackup/bbstreamer_tar.c
+++ b/src/bin/pg_basebackup/bbstreamer_tar.c
@@ -224,7 +224,8 @@ bbstreamer_tar_parser_content(bbstreamer *streamer, bbstreamer_member *member,
/* OK, now we can send it. */
bbstreamer_content(mystreamer->base.bbs_next,
&mystreamer->member,
- data, mystreamer->pad_bytes_expected,
+ mystreamer->base.bbs_buffer.data,
+ mystreamer->pad_bytes_expected,
BBSTREAMER_MEMBER_TRAILER);
/* Expect next file header. */
@@ -342,6 +343,7 @@ bbstreamer_tar_parser_free(bbstreamer *streamer)
{
pfree(streamer->bbs_buffer.data);
bbstreamer_free(streamer->bbs_next);
+ pfree(streamer);
}
/*
[parent: 351e59f344b5]