Hello, chown has a flag that prevents symlink following. chown/chmod is sometimes used in %post/%pre sections of rpm packages to fix up permissions. When this is done in user owned directories (somewhere along the path) this is a security problem. chown allows users to handle this via the -h flag which instructs it not to follow a symlink.
The attached patch adds this flag for chmod. I read https://git.savannah.gnu.org/cgit/coreutils.git/plain/README-hacking but chmod doesn't have an email listed, so I set the patch here. Please CC me in replies, I'm not subscribed to the list. Thanks, Johannes -- GPG Key EE16 6BCE AD56 E034 BFB3 3ADD 7BF7 29D5 E7C8 1FA0 Subkey fingerprint: 250F 43F5 F7CE 6F1E 9C59 4F95 BC27 DD9D 2CC4 FD66 SUSE Software Solutions Germany GmbH, Frankenstraße 146, 90461 Nürnberg, Germany Geschäftsführer: Ivo Totev, Andrew McDonald, Werner Knoblich (HRB 36809, AG Nürnberg)
Index: coreutils-9.4/src/chmod.c
===================================================================
--- coreutils-9.4.orig/src/chmod.c
+++ coreutils-9.4/src/chmod.c
@@ -74,6 +74,9 @@ static mode_t umask_value;
/* If true, change the modes of directories recursively. */
static bool recurse;
+/* If true, don't follow symlinks */
+static bool nofollow_symlinks;
+
/* If true, force silence (suppress most of error messages). */
static bool force_silent;
@@ -100,6 +103,7 @@ enum
static struct option const long_options[] =
{
+ {"no-dereference", no_argument, nullptr, 'h'},
{"changes", no_argument, nullptr, 'c'},
{"recursive", no_argument, nullptr, 'R'},
{"no-preserve-root", no_argument, nullptr, NO_PRESERVE_ROOT},
@@ -207,6 +211,7 @@ process_file (FTS *fts, FTSENT *ent)
const struct stat *file_stats = ent->fts_statp;
struct change_status ch = { 0, };
ch.status = CH_NO_STAT;
+ int retval = -1;
switch (ent->fts_info)
{
@@ -277,7 +282,12 @@ process_file (FTS *fts, FTSENT *ent)
ch.old_mode = file_stats->st_mode;
ch.new_mode = mode_adjust (ch.old_mode, S_ISDIR (ch.old_mode) != 0,
umask_value, change, nullptr);
- if (chmodat (fts->fts_cwd_fd, file, ch.new_mode) == 0)
+ if (nofollow_symlinks) {
+ retval = fchmodat (fts->fts_cwd_fd, file, ch.new_mode, AT_SYMLINK_NOFOLLOW);
+ } else {
+ retval = chmodat (fts->fts_cwd_fd, file, ch.new_mode);
+ }
+ if (retval == 0)
ch.status = CH_SUCCEEDED;
else
{
@@ -399,6 +409,10 @@ With --reference, change the mode of eac
fputs (_("\
-R, --recursive change files and directories recursively\n\
"), stdout);
+ fputs (_("\
+ -h, --no-dereference affect symbolic links instead of any referenced file\n\
+"), stdout);
+
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
@@ -435,7 +449,7 @@ main (int argc, char **argv)
recurse = force_silent = diagnose_surprises = false;
while ((c = getopt_long (argc, argv,
- ("Rcfvr::w::x::X::s::t::u::g::o::a::,::+::=::"
+ ("hRcfvr::w::x::X::s::t::u::g::o::a::,::+::=::"
"0::1::2::3::4::5::6::7::"),
long_options, nullptr))
!= -1)
@@ -491,6 +505,9 @@ main (int argc, char **argv)
case REFERENCE_FILE_OPTION:
reference_file = optarg;
break;
+ case 'h':
+ nofollow_symlinks = true;
+ break;
case 'R':
recurse = true;
break;
signature.asc
Description: Digital signature
