]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Undo inadvertent loosening of archive filename checking.
authorRobert Haas <rhaas@postgresql.org>
Mon, 3 Aug 2026 16:25:01 +0000 (12:25 -0400)
committerRobert Haas <rhaas@postgresql.org>
Mon, 3 Aug 2026 16:25:01 +0000 (12:25 -0400)
Commit c8a350a439826267186c187dbfbf1f839f7521aa attempted to consolidate
code for identify possibly-compressed tar archives by suffix into a new
function parse_tar_compress_algorithm(). Unfortunately, the refactoring
wasn't perfect, and slightly changed the behavior at both existing call
sites.

In CreateBackupStreamer(), the previous code required the filename to
consist of more than just a suffix, so the aforementioned commit had the
effect of allowing pg_basebackup to accept a file from the server whose
entire name was something like .tar.gz -- which should never happen, but
let's reject it as previous releases did.

In precheck_tar_backup_file(), the previous code required the suffix to
be immediately adjacent to the prefix already checked, so the commit
in question allowed pg_verifybackup to accept not only filenames like
base.tar.gz but also filenames like baseFOOBARBAZ.tar.gz. While such
filenames are perhaps unlikely, rejecting them is correct, so let's go
back to that behavior.

Discussion: http://postgr.es/m/CA+TgmoYJY8FkoeYKGF_YF1S6uOK7fd0Bd3zrw0XY_oZXbmVFpQ@mail.gmail.com
Reported-by: Sarath Kumar <Sarath@iitmpravartak.net>
Reviewed-by: Andrew Dunstan <andrew@dunslane.net>
Backpatch-through: 19

src/bin/pg_basebackup/pg_basebackup.c
src/bin/pg_verifybackup/pg_verifybackup.c
src/bin/pg_waldump/pg_waldump.c
src/common/compression.c
src/include/common/compression.h

index 8a599fc986908cfbff2af5c8e5d599bb98c7d72d..12fc752bff5d138096b0e24d9b234c9490d7c966 100644 (file)
@@ -1083,8 +1083,8 @@ CreateBackupStreamer(char *archive_name, char *spclocation,
        inject_manifest = (format == 't' && strcmp(basedir, "-") == 0 && manifest);
 
        /* Check whether it is a tar archive and its compression type */
-       is_tar = parse_tar_compress_algorithm(archive_name,
-                                                                                 &compressed_tar_algorithm);
+       is_tar = (parse_tar_compress_algorithm(archive_name,
+                                                                                  &compressed_tar_algorithm) > 0);
 
        /* Is this any kind of compressed tar? */
        is_compressed_tar = (is_tar &&
index 796eeb6ec0413bec9213bcf15bc799a00bad5e32..81694144b465c90cbf5e8412e0ffd6fa6d96f3a6 100644 (file)
@@ -971,8 +971,12 @@ precheck_tar_backup_file(verifier_context *context, char *relpath,
                tblspc_oid = (Oid) num;
        }
 
-       /* Now, check the compression type of the tar */
-       if (!parse_tar_compress_algorithm(suffix, &compress_algorithm))
+       /*
+        * If parse_tar_compress_algorithm returns exactly 0, there are no
+        * characters between the prefix we already checked and the detected
+        * suffix. Any other case is unexpected.
+        */
+       if (parse_tar_compress_algorithm(suffix, &compress_algorithm) != 0)
        {
                report_backup_error(context,
                                                        "file \"%s\" is not expected in a tar format backup",
index cf760d8b236e11f7e5d19472805057780f26dec8..ffe6e8a6bca747b0062d6f560a19bc6d882935cb 100644 (file)
@@ -1242,7 +1242,7 @@ main(int argc, char **argv)
        if (waldir != NULL)
        {
                /* Check whether the path looks like a tar archive by its extension */
-               if (parse_tar_compress_algorithm(waldir, &compression))
+               if (parse_tar_compress_algorithm(waldir, &compression) >= 0)
                {
                        split_path(waldir, &private.archive_dir, &private.archive_name);
                }
@@ -1286,7 +1286,8 @@ main(int argc, char **argv)
                                pg_fatal("could not open directory \"%s\": %m", waldir);
                }
 
-               if (fname != NULL && parse_tar_compress_algorithm(fname, &compression))
+               if (fname != NULL &&
+                       parse_tar_compress_algorithm(fname, &compression) >= 0)
                {
                        private.archive_dir = waldir;
                        private.archive_name = fname;
index ae2089d9406d61586819ac8ab58198d138f34c7f..e78913ad9dcb69250b6d742e2bab3248ea6c9af7 100644 (file)
@@ -42,33 +42,47 @@ static bool expect_boolean_value(char *keyword, char *value,
                                                                 pg_compress_specification *result);
 
 /*
- * Look up a compression algorithm by archive file extension. Returns true and
- * sets *algorithm if the extension is recognized. Otherwise returns false.
+ * Look up a compression algorithm by archive file extension. Sets *algorithm
+ * and returns the length of the non-extension portion of the filename, or -1
+ * if the filename does not end with a recognized tar extension.
  */
-bool
+int
 parse_tar_compress_algorithm(const char *fname, pg_compress_algorithm *algorithm)
 {
-       size_t          fname_len = strlen(fname);
+       int                     fname_len = strlen(fname);
 
        if (fname_len >= 4 &&
                strcmp(fname + fname_len - 4, ".tar") == 0)
+       {
                *algorithm = PG_COMPRESSION_NONE;
+               return fname_len - 4;
+       }
        else if (fname_len >= 4 &&
                         strcmp(fname + fname_len - 4, ".tgz") == 0)
+       {
                *algorithm = PG_COMPRESSION_GZIP;
+               return fname_len - 4;
+       }
        else if (fname_len >= 7 &&
                         strcmp(fname + fname_len - 7, ".tar.gz") == 0)
+       {
                *algorithm = PG_COMPRESSION_GZIP;
+               return fname_len - 7;
+       }
        else if (fname_len >= 8 &&
                         strcmp(fname + fname_len - 8, ".tar.lz4") == 0)
+       {
                *algorithm = PG_COMPRESSION_LZ4;
+               return fname_len - 8;
+       }
        else if (fname_len >= 8 &&
                         strcmp(fname + fname_len - 8, ".tar.zst") == 0)
+       {
                *algorithm = PG_COMPRESSION_ZSTD;
-       else
-               return false;
+               return fname_len - 8;
+       }
 
-       return true;
+       return -1;
 }
 
 /*
index f99c747cdd3fa7fad59ee1dc66c0356cfa0455ec..adbe668a105aabbc8399295d4d3077c459126c51 100644 (file)
@@ -41,7 +41,7 @@ typedef struct pg_compress_specification
 
 extern void parse_compress_options(const char *option, char **algorithm,
                                                                   char **detail);
-extern bool parse_tar_compress_algorithm(const char *fname,
+extern int     parse_tar_compress_algorithm(const char *fname,
                                                                                 pg_compress_algorithm *algorithm);
 extern bool parse_compress_algorithm(char *name, pg_compress_algorithm *algorithm);
 extern const char *get_compress_algorithm_name(pg_compress_algorithm algorithm);