]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix multiple bugs in astreamer pipeline code.
authorAndrew Dunstan <andrew@dunslane.net>
Sun, 29 Mar 2026 13:12:28 +0000 (09:12 -0400)
committerAndrew Dunstan <andrew@dunslane.net>
Sun, 29 Mar 2026 13:12:28 +0000 (09:12 -0400)
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
src/bin/pg_basebackup/bbstreamer_gzip.c
src/bin/pg_basebackup/bbstreamer_tar.c

index 45f32974ff6e3ee171f951375c2c20e5aa13eceb..2da7d33b4891262e280a36997b15b2962cf9ac35 100644 (file)
@@ -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;
 
index 94f3b9a4de530f60c5254bbc09d14c326cbef747..19f692901a15cd55b97b4fab9db604bdd73ce0e3 100644 (file)
@@ -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);
 }
index 03d7fd3375a85b80305ee001e6a2b19d30a1ac93..d751ae91ea7436cd776d6f8a875339bfaae17213 100644 (file)
@@ -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);
 }
 
 /*