From: Sergey Poznyakoff Date: Tue, 21 Jul 2026 19:49:04 +0000 (+0300) Subject: Check if the dumpdir read from the archive is well-formed before using it. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=HEAD;p=thirdparty%2Ftar.git Check if the dumpdir read from the archive is well-formed before using it. * src/common.h (dumpdir_ok): New proto. * src/incremen.c (dumpdir_ok): Take size as the second argument. Verify if the last byte is 0 and the dumpdir contains 0 or more nul-terminated strings. (get_gnu_dumpdir): Check if the obtained dumpdir is ok. Clear the is_dumpdir flag if it is not. * src/xheader.c (dumpdir_decoder) Verify if the obtained dumpdir is ok. --- diff --git a/src/common.h b/src/common.h index e835d888..e1332a51 100644 --- a/src/common.h +++ b/src/common.h @@ -589,6 +589,7 @@ void purge_directory (char const *directory_name); void list_dumpdir (char *buffer, idx_t size); void update_parent_directory (struct tar_stat_info *st); +bool dumpdir_ok (char const *dumpdir, idx_t size); idx_t dumpdir_size (const char *p); bool is_dumpdir (struct tar_stat_info *stat_info); void clear_directory_table (void); diff --git a/src/incremen.c b/src/incremen.c index 53c6b3f3..d946b0d2 100644 --- a/src/incremen.c +++ b/src/incremen.c @@ -123,6 +123,7 @@ dir_set_flag (struct directory *d, int f) { d->flags |= f; } + static void dir_clear_flag (struct directory *d, int f) { @@ -1525,6 +1526,12 @@ get_gnu_dumpdir (struct tar_stat_info *stat_info) mv_end (); + if (!dumpdir_ok (archive_dir, stat_info->stat.st_size)) + { + stat_info->is_dumpdir = false; + free (archive_dir); + archive_dir = NULL; + } stat_info->dumpdir = archive_dir; stat_info->skipped = true; /* For skip_member() and friends to work correctly */ @@ -1541,13 +1548,20 @@ is_dumpdir (struct tar_stat_info *stat_info) return stat_info->is_dumpdir; } -static bool -dumpdir_ok (char *dumpdir) +bool +dumpdir_ok (char const *dumpdir, idx_t size) { - char *p; + char const *p; bool has_tempdir = false; char expect = '\0'; + if (!(size > 0 && + dumpdir[size-1] == 0 && (size == 1 || dumpdir[size-2] == 0))) + { + paxerror (0, _("Malformed dumpdir: missing terminator")); + return false; + } + for (p = dumpdir; *p; p += strlen (p) + 1) { if (expect && *p != expect) @@ -1640,10 +1654,6 @@ purge_directory (char const *directory_name) case, we don't have to delete any files out of it. */ return; - /* Verify if dump directory is sane */ - if (!dumpdir_ok (current_stat_info.dumpdir)) - return; - /* Process renames */ for (arc = current_stat_info.dumpdir; *arc; arc += strlen (arc) + 1) { diff --git a/src/xheader.c b/src/xheader.c index 05f905ed..09d43995 100644 --- a/src/xheader.c +++ b/src/xheader.c @@ -1483,8 +1483,13 @@ dumpdir_decoder (struct tar_stat_info *st, char const *arg, idx_t size) { - st->dumpdir = ximalloc (size); - memcpy (st->dumpdir, arg, size); + if (dumpdir_ok (arg, size)) + { + st->dumpdir = ximalloc (size); + memcpy (st->dumpdir, arg, size); + } + else + paxerror (0, _("Malformed dumpdir: missing terminator")); } static void