From: Andrew Dunstan Date: Sun, 29 Mar 2026 13:12:40 +0000 (-0400) Subject: Fix multiple bugs in astreamer pipeline code. X-Git-Tag: REL_15_18~63 X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=d3bb7841b4be7e7aad0bd666117c022acb5a2c64;p=thirdparty%2Fpostgresql.git 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 Backpatch-through: 15 --- diff --git a/src/bin/pg_basebackup/bbstreamer_file.c b/src/bin/pg_basebackup/bbstreamer_file.c index 1a94fb2796c..265e80214af 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 40caf8f94cb..dfe901a3860 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 ef5586c488f..8c28e1c8e2a 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. */ @@ -344,6 +345,7 @@ bbstreamer_tar_parser_free(bbstreamer *streamer) { pfree(streamer->bbs_buffer.data); bbstreamer_free(streamer->bbs_next); + pfree(streamer); } /*