فهرست منبع

tar: fix 1.23 Solaris regression related to PRIV_SYS_LINKDIR

The idea was suggested by Petr Sumbera in the thread starting here:
http://lists.gnu.org/archive/html/bug-tar/2010-08/msg00000.html
* src/extract.c (set_mode): Save the errno of the chmod that
failed, for the benefit of chmod_error_details.  Do not bother
retrying chmod unless the mode suggests setuid is the issue.
(extract_archive): Remove redundant call to priv_set_remove_linkdir.
* src/system.c: Include priv-set.h.
(sys_spawn_shell, sys_child_open_for_compress):
(sys_child_open_for_uncompress, sys_exec_command):
(sys_exec_info_script, sys_exec_checkpoint_script):
Invoke priv_set_restore_linkdir before execv or execlp, so that
the subprocess has the same privileges that tar originally did.
Paul Eggert 14 سال پیش
والد
کامیت
3b219f943e
2فایلهای تغییر یافته به همراه23 افزوده شده و 11 حذف شده
  1. 13 10
      src/extract.c
  2. 10 1
      src/system.c

+ 13 - 10
src/extract.c

@@ -144,7 +144,7 @@ set_mode (char const *file_name,
 	  char typeflag)
 {
   mode_t mode;
-  bool failed;
+  int chmod_errno;
 
   if (0 < same_permissions_option
       && permstatus != INTERDIR_PERMSTATUS)
@@ -187,18 +187,24 @@ set_mode (char const *file_name,
       mode = cur_info->st_mode ^ invert_permissions;
     }
 
-  failed = chmod (file_name, mode) != 0;
-  if (failed && errno == EPERM)
+  chmod_errno = chmod (file_name, mode) == 0 ? 0 : errno;
+  if (chmod_errno == EPERM && (mode & S_ISUID) != 0)
     {
-      /* On Solaris, chmod may fail if we don't have PRIV_ALL.  */
+      /* On Solaris, chmod may fail if we don't have PRIV_ALL, because
+	 setuid-root files would otherwise be a backdoor.  See
+	 http://opensolaris.org/jive/thread.jspa?threadID=95826
+	 (2009-09-03).  */
       if (priv_set_restore_linkdir () == 0)
 	{
-	  failed = chmod (file_name, mode) != 0;
+	  chmod_errno = chmod (file_name, mode) == 0 ? 0 : errno;
 	  priv_set_remove_linkdir ();
 	}
     }
-  if (failed)
-    chmod_error_details (file_name, mode);
+  if (chmod_errno)
+    {
+      errno = chmod_errno;
+      chmod_error_details (file_name, mode);
+    }
 }
 
 /* Check time after successfully setting FILE_NAME's time stamp to T.  */
@@ -1271,9 +1277,6 @@ extract_archive (void)
 
   fatal_exit_hook = extract_finish;
 
-  /* Try to disable the ability to unlink a directory.  */
-  priv_set_remove_linkdir ();
-
   set_next_block_after (current_header);
 
   if (!current_stat_info.file_name[0]

+ 10 - 1
src/system.c

@@ -1,7 +1,7 @@
 /* System-dependent calls for tar.
 
    Copyright (C) 2003, 2004, 2005, 2006, 2007,
-   2008 Free Software Foundation, Inc.
+   2008, 2010 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by the
@@ -20,6 +20,7 @@
 #include <system.h>
 
 #include "common.h"
+#include <priv-set.h>
 #include <rmt.h>
 #include <signal.h>
 
@@ -192,6 +193,7 @@ sys_spawn_shell (void)
   child = xfork ();
   if (child == 0)
     {
+      priv_set_restore_linkdir ();
       execlp (shell, "-sh", "-i", (char *) 0);
       exec_fatal (shell);
     }
@@ -362,6 +364,7 @@ sys_child_open_for_compress (void)
 	    }
 	  xdup2 (archive, STDOUT_FILENO);
 	}
+      priv_set_restore_linkdir ();
       execlp (use_compress_program_option, use_compress_program_option, NULL);
       exec_fatal (use_compress_program_option);
     }
@@ -379,6 +382,7 @@ sys_child_open_for_compress (void)
 
       xdup2 (child_pipe[PWRITE], STDOUT_FILENO);
       xclose (child_pipe[PREAD]);
+      priv_set_restore_linkdir ();
       execlp (use_compress_program_option, use_compress_program_option,
 	      (char *) 0);
       exec_fatal (use_compress_program_option);
@@ -496,6 +500,7 @@ sys_child_open_for_uncompress (void)
       if (archive < 0)
 	open_fatal (archive_name_array[0]);
       xdup2 (archive, STDIN_FILENO);
+      priv_set_restore_linkdir ();
       execlp (use_compress_program_option, use_compress_program_option,
 	      "-d", (char *) 0);
       exec_fatal (use_compress_program_option);
@@ -514,6 +519,7 @@ sys_child_open_for_uncompress (void)
 
       xdup2 (child_pipe[PREAD], STDIN_FILENO);
       xclose (child_pipe[PWRITE]);
+      priv_set_restore_linkdir ();
       execlp (use_compress_program_option, use_compress_program_option,
 	      "-d", (char *) 0);
       exec_fatal (use_compress_program_option);
@@ -702,6 +708,7 @@ sys_exec_command (char *file_name, int typechar, struct tar_stat_info *st)
   argv[2] = to_command_option;
   argv[3] = NULL;
 
+  priv_set_restore_linkdir ();
   execv ("/bin/sh", argv);
 
   exec_fatal (file_name);
@@ -816,6 +823,7 @@ sys_exec_info_script (const char **archive_name, int volume_number)
   argv[2] = (char *) info_script_option;
   argv[3] = NULL;
 
+  priv_set_restore_linkdir ();
   execv (argv[0], argv);
 
   exec_fatal (info_script_option);
@@ -863,6 +871,7 @@ sys_exec_checkpoint_script (const char *script_name,
   argv[2] = (char *) script_name;
   argv[3] = NULL;
 
+  priv_set_restore_linkdir ();
   execv (argv[0], argv);
 
   exec_fatal (script_name);