We have RH based Linux images; on which I have to "apply" some "special archive" in order to upgrade them to the latest development version of our product.

The person creating the archive figured that within our base image, some permissions are wrong; so we were told to run

sudo chgrp -R nobody /whatever

We did that; and later on, when our application is running, obscure problems came up.

What I found later on: the call to chgrp will clear the setuid bit information on our binaries within /whatever.

And the actual problem is: some of our binaries must have that setuid bit set in order to function properly.

Long story short: is there a way to run that "chgrp" command without killing my setuid bits?

I just ran the following on my local Ubuntu; leading to the same result:

mkdir sticky
cd sticky/
touch blub
chmod 4755 blub 
ls -al blub 

--> shows me file name with red background --> so, yep, setuid

chgrp -R myuser .
ls -al blub 

--> shows me file name without red background --> setuid is gone

  • 1
    The 4XXX bit is called setuid bit (s), not sticky. Sticky is the t bit and its purpose is a little different: en.wikipedia.org/wiki/Sticky_bit – zuazo Sep 30 '16 at 11:23
  • 2
    (1) You're setting the setuid bit, not the sticky bit. (2) Not clearing the setuid bit when you do chgrp or chown would be a security problem. – Satō Katsura Sep 30 '16 at 11:24
  • 1
    This behavior changes between distributions. But as explained here, the change of the setuid bit depends on the underlying syscall behavior. – zuazo Sep 30 '16 at 11:29
  • Thanks everybody. You are correct, this is about the setuid bit! Thanks for your help. And I also accept that this is "works as designed". Now I just need to find the most sane way to do what needs to be done without killing those bits. I consider to use gefacl to create a text dump, rework the text config and then apply that one. That should give me full control over what will happen. – GhostCat says Reinstate Monica Sep 30 '16 at 12:00

If you want to implement your chgrp -R nobody /whatever while retaining the setuid bit you can use these two find commands

find /whatever ! -type l -perm -04000 -exec chgrp nobody {} + \
                                      -exec chmod u+s {} +
find /whatever ! -type l ! -perm -04000 -exec chgrp nobody {} +

The find ... -perm 04000 option picks up files with the setuid bit set. The first command then applies the chgrp and then a chmod to reinstate the setuid bit that has been knocked off. The second one applies chgrp to all files that do not have a setuid bit.

In any case, you don't want to call chgrp or chmod on symlinks as that would affect their targets instead, hence the ! -type l.

  • Note that chgrp also clears the setgid bit (and capabilities on Linux) which might also need to be restored. – Stéphane Chazelas Sep 30 '16 at 12:48
  • @StéphaneChazelas you're right, but as no-one's mentioned setgid I didn't worry about providing a solution for it. The solution is trivially extensible, though, with a third find – roaima Sep 30 '16 at 12:59
  • Well it can't be a 3rd find, you'd have to cover the cases u+g, u alone, g alone. In any case, you should be able to do it in one find invocation. I don't like the long lines in SE when you have to scroll the text. My adding of the ! -type l made it go over the edge – Stéphane Chazelas Sep 30 '16 at 13:23
  • Well, the one find approach with -exec + may be hard to do reliably if that ends up breaking up the chmod/chgrps into several invocations. – Stéphane Chazelas Sep 30 '16 at 13:30
  • 1
    Actually, I think find . ! -type l -exec chgrp nobody {} + \( -perms -6000 -exec chmod gu+s {} + -o -perms -4000 -exec chmod u+s {} + -o -perms -2000 -exec chmod g+s {} + \) should be OK. Because the chgrp matches for more files, for every file it should be done before the chmods. – Stéphane Chazelas Sep 30 '16 at 13:51

Clearing SUID and SGID bits on chgrp (or chown) is perfectly reasonable. It is a safety measure in order to prevent security problems. For SGID (on executables, I presume) means run this program with effective group of the group owner.

If you change the group owner, then in terms of security and access control this is something entirely different, i.e. instead of running with effective group uvw the program now runs with effective group xyz.

Thus you have to restore the SUID or SGID bit explicitly on ownership change.

Addendum: On the claim that chgrp (or chown) should only clear SGID (or SUID, resp.)

By chowning or chgrping you change the security setting for an executable, and this is sufficient reason to clear any privilege elevating attributes. The power of Unix comes from conceptual simplicity, and Unix security is already quite tricky. To this end removing SUID and SGID on any ownership change is simply a safety net - after all, in the history of Unix/Linux there were quite some vulnerabilities due to misguided SUID or SGID settings.

So there is no deeper reason why Unix behaves this way, it is just a conservative design decision.

  • 1
    This perfectly explains why changing owner clears the SUID bit, and changing group clears the SGID bit. But the question is about the SUID bit during a group change operation that doesn't affect the user under which SUID runs. So there has to be a different explanation. – Ben Voigt Sep 30 '16 at 16:06
  • 1
    @BenVoigt: it explains it pretty good. Both chown and chgrp call the chown() syscall, which clears suid and sgid on regular files no matter what. – Joshua Sep 30 '16 at 16:19
  • 1
    @Joshua: That's a description. The explanation is "to avoid the case that instead of running with effective group uvw the program would now run with effective group xyz", but that doesn't apply to the case under discussion. – Ben Voigt Sep 30 '16 at 16:40
  • It does. By chowning or chgrping you change the security setting, and this is sufficient reason to clear privilege elevating attributes. Chances are high that this otherwise strikes the unwary. – countermode Oct 1 '16 at 0:06

The clearing of the setuid, setgid bit (at least on Linux) on non-directories is done by the kernel upon the chown() system call done by chgrp, not by chgrp itself. So the only way is to restore it afterwards.

It also clears the security capabilities.

So, on GNU Linux:

chown_preserve_sec() (
  newowner=${1?}; shift
  for file do
    perms=$(stat -Lc %a -- "$file") || continue
    cap=$(getfattr -m '^security\.capability$' --dump -- "$file") || continue
    chown -- "$newowner" "$file" || continue
    [ -z "$cap" ] || printf '%s\n' "$cap" | setfattr --restore=-
    chmod -- "$perms" "$file"

And run (as root):

chown_preseve_sec :newgroup file1 file2...

to change the group while attempting to preserve the permissions.

Recursively, you could do:

# save permissions (and ACLs). Remove the "# owner" and "# group" lines
# to prevent them being restored!
perms=$(getfacl -RPn . | grep -vE '^# (owner|group): ')
# save capabilities
cap=$(getfattr -Rhm '^security\.capability$' --dump .)

chgrp -RP nobody .

# restore permissions, ACLs and capabilities
printf '%s\n' "$perms" | setfacl --restore=-
[ -z  "$cap" ] || printf '%s\n' "$cap" | setfattr -h --restore=-

(that's all assuming nothing is otherwise messing up with the files at the same time).


As usual in admin'ing there are many ways to go.

The solution I put in place goes like this:

cd /home/me
getfacl -R /whatever > whatever-permissions.org 2> /dev/null

# A) change lines starting with      # group: root
# to                                 # group: whatineed
sed 's/^# group: root/# group: whatineed/g' whatever-permissions.org > whatever-permissions.new

# B) change lines with               group::x.y
# to                                 group::xwy
# (where x, y mean: whatever was there before)
sed 's/^group::\(.\).\(.\)/group::\1w\2/g' whatever-permissions.new > whatever-permissions.new

cd /
setfacl --restore /home/me/whatever-permissions.new

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.