From: Paul Eggert Date: Tue, 24 Aug 2010 07:07:32 +0000 (-0700) Subject: tar: fix 1.23 Solaris regression related to PRIV_SYS_LINKDIR X-Git-Url: https://git.brokenzipper.com/gitweb?a=commitdiff_plain;h=3b219f943e6b0b14c8f30176951b9339ae3ebaf4;p=chaz%2Ftar 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. --- diff --git a/src/extract.c b/src/extract.c index 0ad5545..653e2a0 100644 --- a/src/extract.c +++ b/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] diff --git a/src/system.c b/src/system.c index f8c3ec1..a11afd7 100644 --- a/src/system.c +++ b/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 #include "common.h" +#include #include #include @@ -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);