Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package tar for openSUSE:Factory checked in 
at 2026-06-25 10:50:58
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/tar (Old)
 and      /work/SRC/openSUSE:Factory/.tar.new.2088 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "tar"

Thu Jun 25 10:50:58 2026 rev:90 rq:1361195 version:1.35

Changes:
--------
--- /work/SRC/openSUSE:Factory/tar/tar.changes  2026-05-10 16:47:50.383589372 
+0200
+++ /work/SRC/openSUSE:Factory/.tar.new.2088/tar.changes        2026-06-25 
10:54:55.104635532 +0200
@@ -1,0 +2,21 @@
+Mon Jun 22 16:07:49 UTC 2026 - Antonio Teixeira <[email protected]>
+
+- Fix CVE-2026-5704.patch causing errors when extracting certain archives
+  generated by rpm2archive which contain hard links
+- Refresh fix-dereference.patch
+
+-------------------------------------------------------------------
+Tue Jun 16 21:51:33 UTC 2026 - Antonio Teixeira <[email protected]>
+
+- Fix tar changing dir permissions temporarily even when using 
--no-overwrite-dir
+  * no-overwrite-dir-fix.patch
+- Fix CVE-2026-5704, crafted archives can be used to to hide file injection
+  (bsc#1261900)
+  * CVE-2026-5704.patch
+- Fix --dereference/-h not working properly after CVE-2025-45582 fix 
(bsc#1265450)
+  * fix-dereference.patch
+- Fix extraction failure for paths like "a/./b" caused by the gnulib openat2
+  implementation (bsc#1267189)
+  * openat2-fix-dotlike-failure.patch
+
+-------------------------------------------------------------------

New:
----
  CVE-2026-5704.patch
  fix-dereference.patch
  no-overwrite-dir-fix.patch
  openat2-fix-dotlike-failure.patch

----------(New B)----------
  New:
- Fix CVE-2026-5704.patch causing errors when extracting certain archives
  generated by rpm2archive which contain hard links
  New:  generated by rpm2archive which contain hard links
- Refresh fix-dereference.patch
  New:- Fix tar changing dir permissions temporarily even when using 
--no-overwrite-dir
  * no-overwrite-dir-fix.patch
- Fix CVE-2026-5704, crafted archives can be used to to hide file injection
  New:  implementation (bsc#1267189)
  * openat2-fix-dotlike-failure.patch
----------(New E)----------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ tar.spec ++++++
--- /var/tmp/diff_new_pack.pA5qee/_old  2026-06-25 10:54:56.000666533 +0200
+++ /var/tmp/diff_new_pack.pA5qee/_new  2026-06-25 10:54:56.000666533 +0200
@@ -54,6 +54,18 @@
 Patch17:        add_forgotten-tests.patch
 Patch18:        tar-fix-deletion-from-archive.patch
 Patch19:        CVE-2025-45582.patch
+# PATCH-FIX-UPSTREAM [email protected]
+# Fix tar changing dir permissions temporarily even when using 
--no-overwrite-dir
+Patch20:        no-overwrite-dir-fix.patch
+# PATCH-FIX-UPSTREAM [email protected] bsc#1261900
+# CVE-2026-5704 - crafted archives can be used to to hide file injection
+Patch21:        CVE-2026-5704.patch
+# PATCH-FIX-UPSTREAM [email protected] bsc#1265450
+# Fix --dereference/-h not working properly after CVE-2025-45582 fix
+Patch22:        fix-dereference.patch
+# PATCH-FIX-UPSTREAM [email protected] bsc#1267189
+# Fix extraction failure for paths like "a/./b" caused by the gnulib openat2 
implementation
+Patch23:        openat2-fix-dotlike-failure.patch
 BuildRequires:  automake >= 1.15
 BuildRequires:  libacl-devel
 BuildRequires:  libselinux-devel

++++++ CVE-2026-5704.patch ++++++
>From b8d8a61b25588caca4efaf9bdd2e3f1a49da77e3 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email protected]>
Date: Sun, 22 Mar 2026 12:19:40 -0700
Subject: [PATCH] Fix more -t/-x discrepancies
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Problem reported by Guillermo de Angel in:
https://lists.gnu.org/r/bug-tar/2026-03/msg00007.html
* THANKS: Add him, and sort.
* src/extract.c (extract_dir, extract_file):
* src/incremen.c (purge_directory):
Do not call skip_member, as the caller now does that, and does it
more reliably.
* src/extract.c (extract_file):
Mark file as skipped when we’ve read it.
(extract_archive): Always call skip_member after extracting,
as it suppresses the skip as needed.
* src/incremen.c (try_purge_directory): Remove; no longer
needed.  Move internals to purge_directory.
* src/list.c (read_header): Do not treat LNKTYPE header as having
size zero, as it can be nonzero (e.g., ‘pax -o linkdata’).
Set info->skipped field according to how the header was read.
(member_is_dir): Remove; no longer needed.
(skim_member): Skip directory data too, unless it’s already been
skipped (i.e., read).
* tests/extrac32.at: New file.
* tests/Makefile.am (TESTSUITE_AT):
* tests/testsuite.at:
Add it.
* tests/skipdir.at (skip directory members):
Fix test to match the correct behavior.
This fixes a bug introduced in commit
b009124ffde415515081db844d7a104e1d1c6c58
dated 2025-05-12 17:17:21 +0300.
---
 THANKS             | 30 +++++++++++++++--------------
 src/extract.c      | 23 ++++++----------------
 src/incremen.c     | 22 +++++++--------------
 src/list.c         | 48 +++++++++++++++-------------------------------
 tests/Makefile.am  |  1 +
 tests/extrac32.at  | 47 +++++++++++++++++++++++++++++++++++++++++++++
 tests/skipdir.at   |  6 +-----
 tests/testsuite.at |  1 +
 8 files changed, 94 insertions(+), 84 deletions(-)
 create mode 100644 tests/extrac32.at

Index: b/THANKS
===================================================================
--- a/THANKS
+++ b/THANKS
@@ -198,6 +198,7 @@ Greg Hudson         [email protected]
 Greg Maples            [email protected]
 Greg McGary            [email protected]
 Greg Schafer           [email protected]
+Guillermo de Angel     [email protected]
 Göran Uddeborg         [email protected]
 Gürkan Karaman         [email protected]
 Hans Guerth            [email protected]
Index: b/src/extract.c
===================================================================
--- a/src/extract.c
+++ b/src/extract.c
@@ -1081,8 +1081,6 @@ extract_dir (char *file_name, int typefl
   if (incremental_option)
     /* Read the entry and delete files that aren't listed in the archive.  */
     purge_directory (file_name);
-  else if (typeflag == GNUTYPE_DUMPDIR)
-    skip_member ();
 
   mode = safe_dir_mode (&current_stat_info.stat);
 
@@ -1262,10 +1260,7 @@ extract_file (char *file_name, int typef
     {
       fd = sys_exec_command (file_name, 'f', &current_stat_info);
       if (fd < 0)
-       {
-         skip_member ();
-         return 0;
-       }
+       return 0;
     }
   else
     {
@@ -1285,7 +1280,6 @@ extract_file (char *file_name, int typef
          int recover = maybe_recoverable (file_name, true, &interdir_made);
          if (recover != RECOVER_OK)
            {
-             skip_member ();
              if (recover == RECOVER_SKIP)
                return 0;
              open_error (file_name);
@@ -1333,6 +1327,7 @@ extract_file (char *file_name, int typef
       }
 
   skim_file (size, false);
+  current_stat_info.skipped = true;
 
   mv_end ();
 
@@ -1865,15 +1860,9 @@ extract_archive (void)
   typeflag = sparse_member_p (&current_stat_info) ?
                   GNUTYPE_SPARSE : current_header->header.typeflag;
 
-  if (prepare_to_extract (current_stat_info.file_name, typeflag, &fun))
-    {
-      if (fun (current_stat_info.file_name, typeflag) == 0)
-       return;
-    }
-  else
-    skip_member ();
-
-  if (backup_option)
+  bool ok = prepare_to_extract (current_stat_info.file_name, typeflag, &fun) 
&& ( fun (current_stat_info.file_name, typeflag) == 0);
+  skip_member ();
+  if (!ok && backup_option)
     undo_last_backup ();
 }
 
Index: b/src/incremen.c
===================================================================
--- a/src/incremen.c
+++ b/src/incremen.c
@@ -1625,8 +1625,8 @@ dumpdir_ok (char *dumpdir)
 
 /* Examine the directories under directory_name and delete any
    files that were not there at the time of the back-up. */
-static bool
-try_purge_directory (char const *directory_name)
+void
+purge_directory (char const *directory_name)
 {
   char *current_dir;
   char *cur, *arc, *p;
@@ -1634,18 +1634,18 @@ try_purge_directory (char const *directo
   struct dumpdir *dump;
 
   if (!is_dumpdir (&current_stat_info))
-    return false;
+    return;
 
   current_dir = tar_savedir (directory_name, 0);
 
   if (!current_dir)
     /* The directory doesn't exist now.  It'll be created.  In any
        case, we don't have to delete any files out of it.  */
-    return false;
+    return;
 
   /* Verify if dump directory is sane */
   if (!dumpdir_ok (current_stat_info.dumpdir))
-    return false;
+    return;
 
   /* Process renames */
   for (arc = current_stat_info.dumpdir; *arc; arc += strlen (arc) + 1)
@@ -1666,7 +1666,7 @@ try_purge_directory (char const *directo
                      quote (temp_stub)));
              free (temp_stub);
              free (current_dir);
-             return false;
+             return;
            }
        }
       else if (*arc == 'R')
@@ -1700,7 +1700,7 @@ try_purge_directory (char const *directo
              free (current_dir);
              /* FIXME: Make sure purge_directory(dst) will return
                 immediately */
-             return false;
+             return;
            }
        }
     }
@@ -1758,14 +1758,6 @@ try_purge_directory (char const *directo
   dumpdir_free (dump);
 
   free (current_dir);
-  return true;
-}
-
-void
-purge_directory (char const *directory_name)
-{
-  if (!try_purge_directory (directory_name))
-    skip_member ();
 }
 
 void
Index: b/src/list.c
===================================================================
--- a/src/list.c
+++ b/src/list.c
@@ -448,20 +448,15 @@ read_header (union block **return_block,
       if ((status = tar_checksum (header, false)) != HEADER_SUCCESS)
        break;
 
-      /* Good block.  Decode file size and return.  */
-
-      if (header->header.typeflag == LNKTYPE)
-       info->stat.st_size = 0; /* links 0 size on tape */
-      else
+      info->stat.st_size = OFF_FROM_HEADER (header->header.size);
+      if (info->stat.st_size < 0)
        {
-         info->stat.st_size = OFF_FROM_HEADER (header->header.size);
-         if (info->stat.st_size < 0)
-           {
-             status = HEADER_FAILURE;
-             break;
-           }
+         status = HEADER_FAILURE;
+         break;
        }
 
+      info->skipped = false;
+
       if (header->header.typeflag == GNUTYPE_LONGNAME
          || header->header.typeflag == GNUTYPE_LONGLINK
          || header->header.typeflag == XHDTYPE
@@ -524,11 +519,15 @@ read_header (union block **return_block,
                }
 
              *bp = '\0';
+             info->skipped = true;
            }
          else if (header->header.typeflag == XHDTYPE
                   || header->header.typeflag == SOLARIS_XHDTYPE)
-           xheader_read (&info->xhdr, header,
-                         OFF_FROM_HEADER (header->header.size));
+           {
+             xheader_read (&info->xhdr, header,
+                           OFF_FROM_HEADER (header->header.size));
+             info->skipped = true;
+           }
          else if (header->header.typeflag == XGLTYPE)
            {
              struct xheader xhdr;
@@ -542,6 +541,7 @@ read_header (union block **return_block,
                            OFF_FROM_HEADER (header->header.size));
              xheader_decode_global (&xhdr);
              xheader_destroy (&xhdr);
+             info->skipped = true;
              if (mode == read_header_x_global)
                {
                  status = HEADER_SUCCESS_EXTENDED;
@@ -1471,10 +1471,11 @@ skim_member (bool must_copy)
 
       if (current_stat_info.is_sparse)
        sparse_skim_file (&current_stat_info, must_copy);
-      else if (save_typeflag != DIRTYPE)
+      else
        skim_file (current_stat_info.stat.st_size, must_copy);
 
       mv_end ();
+      current_stat_info.skipped = true;
     }
 }
 
Index: b/tests/Makefile.am
===================================================================
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -127,6 +127,7 @@ TESTSUITE_AT = \
  extrac25.at\
  extrac30.at\
  extrac31.at\
+ extrac32.at\
  filerem01.at\
  filerem02.at\
  dirrem01.at\
Index: b/tests/extrac32.at
===================================================================
--- /dev/null
+++ b/tests/extrac32.at
@@ -0,0 +1,47 @@
+# Check for file injection bug with symlinks. -*- Autotest -*-
+
+# Copyright 2026 Free Software Foundation, Inc.
+
+# This file is part of GNU tar.
+
+# GNU tar is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# GNU tar is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Thanks to Guillermo de Angel for the bug report and test cases; see:
+# https://lists.gnu.org/r/bug-tar/2026-03/msg00007.html
+
+AT_SETUP([skip file injection])
+AT_KEYWORDS([injection])
+AT_DATA([archive.in],
+[/Td6WFoAAATm1rRGBMDbAYAcIQEcAAAAAAAAACYr+9LgDf8A010AMZhKvfVdtHe4Rxjj7M03ek97
+UgeKfJ0ORqYg0XDFntWxdTH4PYrTOo9CoqBrnTM2NcwFBrRVr7aFwdd56vddyAw2QGDjxgNexDU3
+ImTi/+z8ZOLMi/+AybdEpd5aA/M9Maa+8tQ84bySzSAwrmxMWJJ6W9IKvsqfiRa3TrD51v44PZU/
+KLVKpocS56n/O3g+b+hiZwaysR0eLO+tiU8FB/e3PEq3vTtDFVi/YfZMieBWSzomSX9eF13K1yPY
+UuWgp7VokXqduL0YGNVV40MTPG9oAAAApD6mpajengIAAfcBgBwAAOM4xw6xxGf7AgAAAAAEWVo=
+])
+AT_CHECK([base64 --help >/dev/null 2>&1 || AT_SKIP_TEST
+xz --help >/dev/null 2>&1 || AT_SKIP_TEST
+base64 -d < archive.in | xz -c -d > archive.tar
+])
+cp archive.tar /tmp
+AT_CHECK([tar tf archive.tar],
+[0],
+[carrier_entry
+marker.txt
+])
+AT_CHECK([tar xvf archive.tar],
+[0],
+[carrier_entry
+marker.txt
+])
+AT_CLEANUP
Index: b/tests/testsuite.at
===================================================================
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -353,6 +353,7 @@ m4_include([extrac24.at])
 m4_include([extrac25.at])
 m4_include([extrac30.at])
 m4_include([extrac31.at])
+m4_include([extrac32.at])
 
 m4_include([backup01.at])
 
commit 67981bbb1587803bb1e029393d2228492cef8c4f
Author: Paul Eggert <[email protected]>
Date:   Sat Jun 20 00:28:17 2026 -0700

    tar: ignore nonzero sizes in hard links etc
    
    Problem reported by Antonio Teixeira.
    * src/list.c (read_header): When POSIX says a size field must
    be zero or does not represent a data count, treat it as zero.
    * tests/extrac32.at: Update to match new behavior.
    We now treat hard link sizes as zero even when the size fields are
    nonzero, and this means the “injected” file is treated as valid
    regardless of whether we list or extract.
    * tests/extrac34.at: New test.
    * tests/Makefile.am (TESTSUITE_AT), tests/testsuite.at: Add it.

diff --git a/src/list.c b/src/list.c
index 5ab6de42..1c992cf4 100644
--- a/src/list.c
+++ b/src/list.c
@@ -535,6 +535,22 @@ read_header (union block **return_block, struct 
tar_stat_info *info,
          struct posix_header const *h = &header->header;
          char namebuf[sizeof h->prefix + 1 + NAME_FIELD_SIZE + 1];
 
+         switch (h->typeflag)
+           {
+           /* For these file types, although POSIX does not specify the
+              meaning of the size, it does say there should be no data,
+              so treat the size as zero.  */
+           case BLKTYPE: case CHRTYPE: case FIFOTYPE:
+
+           /* For these file types, POSIX requires that the size be zero.
+              Be generous and accept any size as zero, as some
+              nonconforming programs generate nonzero size fields along
+              with no data.  */
+           case LNKTYPE: case SYMTYPE:
+
+             info->stat.st_size = 0;
+           }
+
          free (recent_long_name);
 
          if (next_long_name)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 103c6de7..4f666b09 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -143,6 +143,7 @@ TESTSUITE_AT = \
  extrac30.at\
  extrac31.at\
  extrac32.at\
+ extrac34.at\
  filerem01.at\
  filerem02.at\
  dirrem01.at\
diff --git a/tests/extrac32.at b/tests/extrac32.at
index d3505fdb..af40916d 100644
--- a/tests/extrac32.at
+++ b/tests/extrac32.at
@@ -36,11 +36,13 @@ base64 -d < archive.in | xz -c -d > archive.tar
 AT_CHECK([tar tf archive.tar],
 [0],
 [carrier_entry
+injected.txt
 marker.txt
 ])
 AT_CHECK([tar xvf archive.tar],
 [0],
 [carrier_entry
+injected.txt
 marker.txt
 ])
 AT_CLEANUP
diff --git a/tests/extrac34.at b/tests/extrac34.at
new file mode 100644
index 00000000..1cedb463
--- /dev/null
+++ b/tests/extrac34.at
@@ -0,0 +1,40 @@
+# Check hard link with nonzero size field in tarball. -*- Autotest -*-
+
+# Copyright 2026 Free Software Foundation, Inc.
+
+# This file is part of GNU tar.
+
+# GNU tar is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# GNU tar is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Check extracting from a nonconforming tarball that has
+# a hard link with nonzero size.
+
+AT_SETUP([hard link with a nonzero size field])
+AT_KEYWORDS([extract extrac34 hard link])
+AT_DATA([archive.in],
+[/Td6WFoAAATm1rRGBMBwgFAhARwAAAAAAAAAAAbKrCjgJ/8AaF0AMIAzUBhoiawFdYeRen4lxlj0
+QWRLpUM+28ArRsXVY5bGv4H5kijsqiJ4Z9YIVhZd01+IppF+AkltS60aB8fuUW35Tp/3XzUx9Mq2
+4ypJFzvcgHXsSIvc9L+mmTDuHzhvJQ/oe7ya8QAASbOfD7CgZcIAAYwBgFAAAEWxohaxxGf7AgAA
+AAAEWVo=
+])
+AT_CHECK([base64 --help >/dev/null 2>&1 || AT_SKIP_TEST
+xz --help >/dev/null 2>&1 || AT_SKIP_TEST
+base64 -d < archive.in | xz -c -d > archive.tar
+])
+AT_CHECK([mkdir dir
+])
+AT_CHECK([tar -C dir -xf archive.tar || exit 1
+cmp dir/a dir/b
+])
+AT_CLEANUP
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 70d36a5a..ab30c2ab 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -360,6 +360,7 @@ m4_include([extrac30.at])
 m4_include([extrac30.at])
 m4_include([extrac31.at])
 m4_include([extrac32.at])
+m4_include([extrac34.at])
 
 m4_include([backup01.at])
 

++++++ fix-dereference.patch ++++++
commit 145a671e8ad0f2443e253ea4cc95b676ed7a2847
Author: Sergey Poznyakoff <[email protected]>
Date:   Thu Jun 11 16:33:15 2026 +0300

    Fix extracting over symlinks with --dereference
    
    Extraction over symlink to a directory was broken in 75b03fdff4.
    See https://savannah.gnu.org/bugs/index.php?68368
    
    * src/tar.c (decode_options): Don't enable RESOLVE_BENEATH mode
    if --dereference is given.
    * tests/extrac33.at: New test.
    * tests/Makefile.am: Add new test.
    * tests/testsuite.at: Likewise.
    * tests/extrac13.at: Add a keyword.
    * tests/extrac31.at: Remove --absolute-names keyword: that option
    is never used in the testcase. Add CVE-2025-45582 keyword instead.

Index: b/src/tar.c
===================================================================
--- a/src/tar.c
+++ b/src/tar.c
@@ -2633,7 +2633,7 @@ decode_options (int argc, char **argv)
 #endif
     open_searchdir_how.flags = (search_flags | nofollow_flag
                                | O_BINARY | O_CLOEXEC | O_DIRECTORY);
-    if (!absolute_names_option
+    if (!absolute_names_option && !dereference_option
        && (subcommand_option == EXTRACT_SUBCOMMAND
            || subcommand_option == DIFF_SUBCOMMAND))
       open_searchdir_how.resolve = RESOLVE_BENEATH;
Index: b/tests/Makefile.am
===================================================================
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -128,6 +128,7 @@ TESTSUITE_AT = \
  extrac30.at\
  extrac31.at\
  extrac32.at\
+ extrac33.at\
  extrac34.at\
  filerem01.at\
  filerem02.at\
Index: b/tests/extrac13.at
===================================================================
--- a/tests/extrac13.at
+++ b/tests/extrac13.at
@@ -24,7 +24,7 @@
 # unless --dereference is specified.
 
 AT_SETUP([extract over symlinks])
-AT_KEYWORDS([extract extrac13 chdir])
+AT_KEYWORDS([extract extrac13 chdir --dereference])
 
 AT_TAR_CHECK([
 mkdir src dst1 dst2 dst3
Index: b/tests/extrac31.at
===================================================================
--- a/tests/extrac31.at
+++ b/tests/extrac31.at
@@ -17,8 +17,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 AT_SETUP([extracting untrusted incremental])
-AT_KEYWORDS([extract extrac31 --absolute-names])
-
+AT_KEYWORDS([extract extrac31 CVE-2025-45582])
 
 AT_TAR_CHECK([
 
Index: b/tests/extrac33.at
===================================================================
--- /dev/null
+++ b/tests/extrac33.at
@@ -0,0 +1,53 @@
+# Test suite for GNU tar.                             -*- Autotest -*-
+# Copyright 2026 Free Software Foundation, Inc.
+#
+# This file is part of GNU tar.
+#
+# GNU tar is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GNU tar is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Description: Fixing CVE-2025-45582 (commit 75b03fdff4) broke some
+# legitimate cases of extracting over symlinks with the --dereference
+# option. Check if that is fixed.
+#
+# References: https://savannah.gnu.org/bugs/index.php?68368
+
+AT_SETUP([extract over symlink to dir with --dereference])
+AT_KEYWORDS([extract extrac33 CVE-2025-45582 --dereference])
+AT_DATA([archive.in],
+[/Td6WFoAAATm1rRGAgAhARYAAAB0L+Wj4Cf/AJxdABcLvBx9AZXAHUpGnBzE/y67neFgHitlwSWw
+/oOsdf1GACIE/0RnS0Lp6Mj1RyfaFcxOxcWz61KEu+VeJMMAUhYEcMyGrz191zPA4rOoVcIqYEm0
+B9Jiq66xT/4F6gUOeitk5fqE+uMdHKK7QTaty/dnoxtba+McJh/dXP2TUStl0xetvrnvCE1/2tKZ
+grqe/9/HpysFqZnu5sskAABO7ZNxp1eWNgABuAGAUAAA/vRJibHEZ/sCAAAAAARZWg==
+])
+AT_CHECK([base64 --help >/dev/null 2>&1 || AT_SKIP_TEST
+xz --help >/dev/null 2>&1 || AT_SKIP_TEST
+base64 -d < archive.in | xz -c -d > archive.tar
+])
+AT_CHECK([mkdir dir dir2 hdir
+cd dir
+ln -sf ../dir2 .
+cd ../hdir
+ln -sf ../dir2 .
+])
+AT_CHECK([tar -C dir -xf archive.tar || exit 1
+test -d dir/dir2
+])
+AT_CHECK([tar -C hdir -hxf archive.tar || exit 1
+test -h hdir/dir2 || exit 2
+ls dir2
+],
+[0],
+[file2
+])
+AT_CLEANUP
Index: b/tests/testsuite.at
===================================================================
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -354,6 +354,7 @@ m4_include([extrac25.at])
 m4_include([extrac30.at])
 m4_include([extrac31.at])
 m4_include([extrac32.at])
+m4_include([extrac33.at])
 m4_include([extrac34.at])

 m4_include([backup01.at])
 

++++++ no-overwrite-dir-fix.patch ++++++
commit 4e742fc8674064a9fa00d4483d06aca48d5b0463
Author: Paul Eggert <[email protected]>
Date:   Sat Jul 26 21:41:23 2025 -0700

    --no-overwrite-dir no overwrite even temporarily
    
    Problem and fix reported by Pavel Cahyna in
    https://lists.gnu.org/r/bug-tar/2025-01/msg00000.html
    * src/extract.c (extract_dir): With --no-overwrite-dir,
    skip the chmod if the directory already exists.
    * tests/extrac23.at (--no-overwrite-dir on empty directory):
    Move the part of the test that looks at a nonempty directory ...
    * tests/extrac30.at: ... to this new file, because the test now
    must be run as non-root.  Adjust the test to match the new behavior.
    * tests/Makefile.am (TESTSUITE_AT), tests/testsuite.at: Add it.

Index: b/src/extract.c
===================================================================
--- a/src/extract.c
+++ b/src/extract.c
@@ -1126,31 +1126,6 @@ extract_dir (char *file_name, int typefl
                          repair_delayed_set_stat (file_name, &st);
                          return 0;
                            }
-             else if (old_files_option == NO_OVERWRITE_DIR_OLD_FILES)
-                           {
-                         /* Temporarily change the directory mode to a safe
-                            value, to be able to create files in it, should
-                            the need be.
-                         */
-                         mode = safe_dir_mode (&st);
-                         status = fd_chmod (-1, file_name, mode,
-                                            AT_SYMLINK_NOFOLLOW, DIRTYPE);
-                         if (status == 0)
-                           {
-                             /* Store the actual directory mode, to be restored
-                                later.
-                             */
-                             current_stat_info.stat = st;
-                             current_mode = mode & ~ current_umask;
-                             current_mode_mask = MODE_RWX;
-                             atflag = AT_SYMLINK_NOFOLLOW;
-                             break;
-                           }
-                         else
-                           {
-                             chmod_error_details (file_name, mode);
-                           }
-                       }
                      break;
                    }
                }
Index: b/tests/Makefile.am
===================================================================
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -125,6 +125,7 @@ TESTSUITE_AT = \
  extrac23.at\
  extrac24.at\
  extrac25.at\
+ extrac30.at\
  extrac31.at\
  filerem01.at\
  filerem02.at\
Index: b/tests/extrac23.at
===================================================================
--- a/tests/extrac23.at
+++ b/tests/extrac23.at
@@ -15,15 +15,12 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
-AT_SETUP([--no-overwrite-dir])
+AT_SETUP([--no-overwrite-dir on empty directory])
 AT_KEYWORDS([extract extrac23 no-overwrite-dir])
 
 # Description: Implementation of the --no-overwrite-dir option was flawed in
 # tar versions up to 1.32.90.  This option is intended to preserve metadata
 # of existing directories.  In fact it worked only for non-empty directories.
-# Moreover, if the actual directory was owned by the user tar runs as and the
-# S_IWUSR bit was not set in its actual permissions, tar failed to create files
-# in it.
 #
 # Reported by: Michael Kaufmann <[email protected]>
 # References: 
<20200207112934.horde.anxzyhaj2chiwurw5cut...@webmail.michael-kaufmann.ch>,
@@ -38,21 +35,10 @@ chmod 777 dir
 tar -xf a.tar --no-overwrite-dir
 genfile --stat=mode.777 dir
 
-# Test if temporary permissions are set correctly to allow the owner
-# to write to the directory.
-genfile --file dir/file
-tar cf a.tar dir
-rm dir/file
-chmod 400 dir
-tar -xf a.tar --no-overwrite-dir
-genfile --stat=mode.777 dir
-chmod 700 dir
 find dir
 ],
 [0],
 [777
-400
 dir
-dir/file
 ])
 AT_CLEANUP
Index: b/tests/extrac30.at
===================================================================
--- /dev/null
+++ b/tests/extrac30.at
@@ -0,0 +1,47 @@
+# Test suite for GNU tar.                             -*- Autotest -*-
+# Copyright 2020-2025 Free Software Foundation, Inc.
+#
+# This file is part of GNU tar.
+#
+# GNU tar is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GNU tar is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+AT_SETUP([--no-overwrite-dir on unwritable directory])
+AT_KEYWORDS([extract extrac30 no-overwrite-dir])
+
+# Make sure that tar does not change permissions on directories if
+# --no-overwrite-dir tells it not to, not even temporarily.
+
+AT_TAR_CHECK([
+AT_UNPRIVILEGED_PREREQ
+
+# Test that the user cannot write to a unwritable directory
+# if --no-overwrite-dir is used.
+mkdir dir
+chmod 755 dir
+genfile --file dir/file
+tar cf a.tar dir
+rm dir/file
+chmod 555 dir
+tar -xf a.tar --no-overwrite-dir
+genfile --stat=mode.777 dir
+chmod 755 dir
+find dir
+],
+[0],
+[555
+dir
+],
+[tar: dir/file: Cannot open: Permission denied
+tar: Exiting with failure status due to previous errors
+])
+AT_CLEANUP
Index: b/tests/testsuite.at
===================================================================
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -351,6 +351,7 @@ m4_include([extrac22.at])
 m4_include([extrac23.at])
 m4_include([extrac24.at])
 m4_include([extrac25.at])
+m4_include([extrac30.at])
 m4_include([extrac31.at])
 
 m4_include([backup01.at])

++++++ openat2-fix-dotlike-failure.patch ++++++
>From 50d7bb88f547aff37e6279bdc84a7602e1dd3533 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email protected]>
Date: Wed, 17 Jun 2026 00:19:35 -0700
Subject: openat2: fix bug with trailing "/./"

Problem reported by Kinan Al-Falakh in:
https://lists.gnu.org/r/bug-gnulib/2026-06/msg00070.html
* lib/openat2.c (do_openat2): When opening a dotlike component at
file name end, also set the G and H indexes appropriately for ".".
This matters if the file name ends in something like "/./" so the
last component "." is not at file name end.
* tests/test-openat2.c (do_test_resolve): Test for the bug.
---
 ChangeLog            | 11 +++++++++++
 lib/openat2.c        |  3 ++-
 tests/test-openat2.c | 11 +++++++++++
 3 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/gnu/openat2.c b/gnu/openat2.c
index 2be62c921c..8c722427f7 100644
--- a/gnu/openat2.c
+++ b/gnu/openat2.c
@@ -320,8 +320,9 @@ do_openat2 (int *fd, char const *filename,
             {
               /* This is empty or the last component, and acts like ".".
                  Use "." regardless of whether it was "" or "." or "..".  */
-              f = sizeof ".";
+              f = g = sizeof ".";
               e[-f] = '.';
+              h = 1;
             }
 
           /* Open the current component, as either an internal directory or
-- 
cgit v1.2.3

Reply via email to