From 4e742fc8674064a9fa00d4483d06aca48d5b0463 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Sat, 26 Jul 2025 21:41:23 -0700
Subject: [PATCH] --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.

CVE: CVE-2026-5704
Upstream-Status: Backport [https://git.savannah.gnu.org/cgit/tar.git/commit/?id=4e742fc8674064a9fa00d4483d06aca48d5b0463]

Backport Changes:
- Omit the NEWS update.
- Adapt tests/Makefile.am and tests/testsuite.at context to the tar-1.35
  test list carried by OE-Core.

(cherry picked from commit 4e742fc8674064a9fa00d4483d06aca48d5b0463)
Signed-off-by: Himanshu Jadon <hjadon@cisco.com>
---
diff --git a/src/extract.c b/src/extract.c
index 3bf0d77..4ed19b6 100644
--- a/src/extract.c
+++ b/src/extract.c
@@ -1102,31 +1102,6 @@ extract_dir (char *file_name, MAYBE_UNUSED char typeflag)
 			  repair_delayed_set_stat (file_name, &st);
 			  return true;
 			}
-		      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;
 		    }
 		}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index baeb55b..a75abdb 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -133,6 +133,7 @@ TESTSUITE_AT = \
  extrac23.at\
  extrac24.at\
  extrac25.at\
+ extrac30.at\
  extrac32.at\
  filerem01.at\
  filerem02.at\
diff --git a/tests/extrac23.at b/tests/extrac23.at
index cb63ebb..efc9a32 100644
--- 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 <mail@michael-kaufmann.ch>
 # References: <20200207112934.Horde.anXzYhAj2CHiwUrw5CuT0G-@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
diff --git a/tests/extrac30.at b/tests/extrac30.at
new file mode 100644
index 0000000..8c879c9
--- /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
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 5875700..331a6e3 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -352,0 +353 @@
+m4_include([extrac30.at])
