diff --git a/SOURCES/tar-1.34-Warn-file-changed-as-we-read-it-less-often.patch b/SOURCES/tar-1.34-Warn-file-changed-as-we-read-it-less-often.patch new file mode 100644 index 0000000..654d679 --- /dev/null +++ b/SOURCES/tar-1.34-Warn-file-changed-as-we-read-it-less-often.patch @@ -0,0 +1,164 @@ +From 7819e9ce26a6331f7a347c59cebfd5c6a8902ea3 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Thu, 15 Aug 2024 14:19:58 +0200 +Subject: [PATCH] =?UTF-8?q?Warn=20=E2=80=9Cfile=20changed=20as=20we=20read?= + =?UTF-8?q?=20it=E2=80=9D=20less=20often?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +* src/create.c (dump_file0): Remove an fstatat call that is +unnecessary because the file wasn’t read so we can treat the first +fstatat as atomic. Warn “file changed” when the file’s size, +mtime, user ID, group ID, or mode changes, instead of when the +file’s size or ctime changes. Also, when such a change happens, +do not change exit status if --ignore-failed-read. Finally, don’t +attempt to change atime back if it didn’t change. +--- + doc/tar.texi | 10 ++++++---- + src/create.c | 54 ++++++++++++++++++++++++++++++++++++---------------- + 2 files changed, 44 insertions(+), 20 deletions(-) + +diff --git a/doc/tar.texi b/doc/tar.texi +index b66b163..dd5a272 100644 +--- a/doc/tar.texi ++++ b/doc/tar.texi +@@ -2854,7 +2854,7 @@ Ignore exit codes of subprocesses. @xref{Writing to an External Program}. + @opsummary{ignore-failed-read} + @item --ignore-failed-read + +-Do not exit unsuccessfully merely because an unreadable file was encountered. ++Do not exit unsuccessfully merely because reading failed. + @xref{Ignore Failed Read}. + + @opsummary{ignore-zeros} +@@ -4638,7 +4638,8 @@ Disable all warning messages. + @item file-changed + @samp{%s: file changed as we read it} + @item failed-read +-Suppresses warnings about unreadable files or directories. This ++Suppresses warnings about read failures, which can occur if files ++or directories are unreadable, or if they change while being read. This + keyword applies only if used together with the @option{--ignore-failed-read} + option. @xref{Ignore Failed Read}. + @end table +@@ -5761,11 +5762,12 @@ Disable SELinux context support. + @table @option + @item --ignore-failed-read + @opindex ignore-failed-read +-Do not exit with nonzero on unreadable files or directories. ++Do not exit with nonzero if there are mild problems while reading. + @end table + + This option has effect only during creation. It instructs tar to +-treat as mild conditions any missing or unreadable files (directories). ++treat as mild conditions any missing or unreadable files (directories), ++or files that change while reading. + Such failures don't affect the program exit code, and the + corresponding diagnostic messages are marked as warnings, not errors. + These warnings can be suppressed using the +diff --git a/src/create.c b/src/create.c +index e2816fc..2b3001d 100644 +--- a/src/create.c ++++ b/src/create.c +@@ -1650,8 +1650,6 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p) + { + union block *header; + char type; +- off_t original_size; +- struct timespec original_ctime; + off_t block_ordinal = -1; + int fd = 0; + bool is_dir; +@@ -1694,10 +1692,11 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p) + return; + } + +- st->archive_file_size = original_size = st->stat.st_size; ++ struct stat st1 = st->stat; ++ st->archive_file_size = st->stat.st_size; + st->atime = get_stat_atime (&st->stat); + st->mtime = get_stat_mtime (&st->stat); +- st->ctime = original_ctime = get_stat_ctime (&st->stat); ++ st->ctime = get_stat_ctime (&st->stat); + + #ifdef S_ISHIDDEN + if (S_ISHIDDEN (st->stat.st_mode)) +@@ -1747,7 +1746,7 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p) + if (is_dir || S_ISREG (st->stat.st_mode) || S_ISCTG (st->stat.st_mode)) + { + bool ok; +- struct stat final_stat; ++ struct stat st2; + + xattrs_acls_get (parentfd, name, st, 0, !is_dir); + xattrs_selinux_get (parentfd, name, st, fd); +@@ -1815,31 +1814,54 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p) + errno = - parentfd; + ok = false; + } +- else +- ok = fstatat (parentfd, name, &final_stat, fstatat_flags) == 0; + } + else +- ok = fstat (fd, &final_stat) == 0; ++ ok = fstat (fd, &st2) == 0; + + if (! ok) + file_removed_diag (p, top_level, stat_diag); + } + +- if (ok) ++ if (ok && fd) + { +- if ((timespec_cmp (get_stat_ctime (&final_stat), original_ctime) != 0 +- /* Original ctime will change if the file is a directory and +- --remove-files is given */ +- && !(remove_files_option && is_dir)) +- || original_size < final_stat.st_size) ++ /* Heuristically check whether the file is the same in all ++ attributes that tar cares about and can easily check. ++ Although the check is not perfect since it does not ++ consult file contents, it is typically good enough. ++ Do not check atime which is saved only to replace it later. ++ Do not check ctime where changes might be benign (e.g., ++ another process creates a hard link to the file). */ ++ ++ /* If the file's user ID, group ID or mode changed, tar may ++ have output the wrong info for the file. */ ++ ok &= st1.st_uid == st2.st_uid; ++ ok &= st1.st_gid == st2.st_gid; ++ ok &= st1.st_mode == st2.st_mode; ++ ++ /* Likewise for the file's mtime, but skip this check if it ++ is a directory possibly updated by --remove-files. */ ++ if (! (is_dir && remove_files_option)) ++ ok &= ! timespec_cmp (get_stat_mtime (&st1), ++ get_stat_mtime (&st2)); ++ ++ /* Likewise for the file's size, but skip this check if it ++ is a directory as tar does not output directory sizes. ++ Although dump_regular_file caught regular file shrinkage, ++ it shouldn't hurt to check for shrinkage again now; ++ plus, the file may have grown. */ ++ if (!is_dir) ++ ok &= st1.st_size == st2.st_size; ++ ++ if (!ok) + { + WARNOPT (WARN_FILE_CHANGED, + (0, 0, _("%s: file changed as we read it"), + quotearg_colon (p))); +- set_exit_status (TAREXIT_DIFFERS); ++ if (! ignore_failed_read_option) ++ set_exit_status (TAREXIT_DIFFERS); + } + else if (atime_preserve_option == replace_atime_preserve +- && fd && (is_dir || original_size != 0) ++ && timespec_cmp (st->atime, get_stat_atime (&st2)) != 0 + && set_file_atime (fd, parentfd, name, st->atime) != 0 + && errno != EROFS ) + utime_error (p); +-- +2.45.2 + diff --git a/SPECS/tar.spec b/SPECS/tar.spec index ae60c97..23c1bdc 100644 --- a/SPECS/tar.spec +++ b/SPECS/tar.spec @@ -5,7 +5,7 @@ Summary: GNU file archiving program Name: tar Epoch: 2 Version: 1.34 -Release: 6%{?dist} +Release: 6%{?dist}.1 License: GPLv3+ URL: https://www.gnu.org/software/tar/ @@ -22,6 +22,7 @@ Patch10: tar-1.33-fix-capabilities-test.patch Patch11: tar-1.30-padding-zeros.patch Patch12: tar-1.30-disk-read-error.patch Patch13: tar-1.34-CVE-2022-48303.patch +Patch14: tar-1.34-Warn-file-changed-as-we-read-it-less-often.patch BuildRequires: make BuildRequires: gcc @@ -116,6 +117,9 @@ make check || ( %changelog +* Fri Aug 16 2024 Lukas Nykryn - 2:1.34-6.1 +- Warn “file changed as we read it” less often + * Thu Feb 09 2023 Matej Mužila - 2:1.34-6 - Fix CVE-2022-48303 - Resolves: CVE-2022-48303