4

I'm not understanding setgid on executables on my platform (ubuntu). g-x,g+s is not giving the process effective group permissions of the program's owner.

$ gcc perms.c -o perms; ls -l ; ./perms
-rwxr-xr-x 1 ubuntu ubuntu 9302 Feb 24 01:00 perms*
-rw-r--r-- 1 ubuntu ubuntu 1437 Feb 21 08:41 perms.c
ruid: ubuntu:1000 group:1000
euid: ubuntu:1000 group:1000

$ sudo useradd alice; groups alice $USER
alice : alice
ubuntu : ubuntu sudo rvm

$ chmod g+s ./perms; ls -l ./perms ; sudo -u alice ./perms
rwxr-sr-x 1 ubuntu ubuntu 9302 Feb 24 01:00 perms*
ruid: alice:1001 group:1002
euid: alice:1001 group:**1000**

This is all expected, the problem is:

$ chmod g-x ./perms; ls -l ./perms ; sudo -u alice ./perms
-rwxr-Sr-x 1 ubuntu ubuntu 9302 Feb 24 01:00 perms*
ruid: alice:1001 group:1002
euid: alice:1001 group:**1002**

My understanding is that g+s gives the process the effective group id of the program's owner, but it's not. Obviously, this is because of the g-x since that was the only change.

Edit1: removed the section on how g-x,g+s works on directories, because people were thinking I was asking about S on directories. I'm not.

Edit2: since I'm getting condesention from one answer. This is also different than from what happens with u-x,u+s:

$ rm -rf perms temp/; gcc perms.c -o perms
$ chmod ug-x,ug+s ./perms; ls -l ./perms; sudo -u alice ./perms
-rwSr-Sr-x 1 ubuntu ubuntu 9302 Feb 24 21:22 ./perms*
ruid: alice:1001 group:1002
euid: ubuntu:1000 group:1002

Here u-x,u+s is respected, but g-x,g+s is not.

My question: why is capital S sgid ignored for executables?
g-x,g+s is respected on directories.
u-x,u+s is respected on executables.
But g-x,g+s is not respected on executables.
WHY?

ANSWER: my research seems to have dead-ended at "because System V arbitrarily decided it means something else."

2 Answers2

3

Alright, not much help from the one response that told me to RTFM. After digging for a few hours, I found these lines in the current linux kernel.

https://github.com/torvalds/linux/blob/e816c201aed5232171f8eb80b5d46ae6516683b9/fs/exec.c

/* Be careful if suid/sgid is set */
inode_lock(inode);

/* reload atomically mode/uid/gid now that lock held */
mode = inode->i_mode;
uid = inode->i_uid;
gid = inode->i_gid;
inode_unlock(inode);

/* We ignore suid/sgid if there are no mappings for them in the ns */
if (!kuid_has_mapping(bprm->cred->user_ns, uid) ||
     !kgid_has_mapping(bprm->cred->user_ns, gid))
    return;

if (mode & S_ISUID) {
    bprm->per_clear |= PER_CLEAR_ON_SETID;
    bprm->cred->euid = uid;
}

if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
    bprm->per_clear |= PER_CLEAR_ON_SETID;
    bprm->cred->egid = gid;
}

So clearly, this is intentional.

This dates back to the original upload to github in May 2005:

https://github.com/torvalds/linux/blob/3677209239ed71d2654e73eecfab1dbec2af11a9/fs/exec.c

bprm->e_uid = current->euid;
bprm->e_gid = current->egid;

if(!(bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)) {
    /* Set-uid? */
    if (mode & S_ISUID) {
        current->personality &= ~PER_CLEAR_ON_SETID;
        bprm->e_uid = inode->i_uid;
    }

    /* Set-gid? */
    /*
     * If setgid is set but no group execute bit then this
     * is a candidate for mandatory locking, not a setgid
     * executable.
     */
    if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
        current->personality &= ~PER_CLEAR_ON_SETID;
        bprm->e_gid = inode->i_gid;
    }
}

Googling for the comment leads to:

https://www.kernel.org/doc/Documentation/filesystems/mandatory-locking.txt

  1. Marking a file for mandatory locking
    A file is marked as a candidate for mandatory locking by setting the group-id bit in its file mode but removing the group-execute bit. This is an otherwise meaningless combination, and was chosen by the System V implementors so as not to break existing user programs.
    Note that the group-id bit is usually automatically cleared by the kernel when a setgid file is written to. This is a security measure. The kernel has been modified to recognize the special case of a mandatory lock candidate and to refrain from clearing this bit. Similarly the kernel has been modified not to run mandatory lock candidates with setgid privileges.

So the answer seems to be "because it was chosen to mean something else."

0

As you have edited your question to include this:

My question: why is capital S sgid ignored for executables?

It's not being ignored. S in your case means that the file isn't executable by the group and so it's benign. If you want the executable file to run with the permissions of the group then it needs to be executable by the group. You took that away with g-x which is why you are getting S. It will run with permissions of whomever executes it and not with permissions of the group.

Nasir Riley
  • 10,665
  • 2
  • 18
  • 27
  • That wasnt my question. +s *is* working for directories. The file created belong's to the directory owner's group, not the process' group. That is the correct behavior. It is not working for the executable that is outside of the directory. the process *should* be running with the effective permissions of the program owner's group, but it is not –  Feb 24 '18 at 19:22
  • I'll update my answer but it's already been given by Praveen Khumar. `+s` means nothing for directories because directories aren't executable so you statement that it's working for directories is false. – Nasir Riley Feb 24 '18 at 19:54
  • No, +s on a directory does mean something for directories. It means that files created in that directory belong the the directory's group owner, not to the process's group. And again, I AM NOT ASKING ABOUT DIRECTORIES, I am asking about S (capital S) on the program file and how the process is not getting the program's owner's group permissions. And yes, I edited my question, because you ignored what I actually asked and instead you answered what you thought I asked. –  Feb 24 '18 at 20:08
  • Your eddied answer seems to go against POSIX. Can you link me to an authoritative source stating that this is the correct behaviour? –  Feb 24 '18 at 20:09
  • No, `s` does not mean that files created in the directory belong to the directory groups owner. In your case, `setgid` means that the file is executed with the permissions of the group. It does not affect the ownership of the file in any way, shape, or form. I did not ignore what you said. It's that you weren't being clear. As has been said several times, `S`, in your case, means that the file isn't executable by the group and hence it's benign. You don't seem to have much understanding of jpw `setgid` and `setuid` actually function. – Nasir Riley Feb 24 '18 at 20:28
  • `No, s does not mean that files created in the directory belong to the directory groups owner.` Really? So `chmod g+S temp/` (as was in my original question) does not mean that new files in that directory are owned by the directory's group owner? Sorry, but a simple test (as was included in the original) contradict that. –  Feb 24 '18 at 21:00
  • `In your case, setgid means that the file is executed with the permissions of the group.` ... `As has been said several times, S, in your case, means that the file isn't executable by the group and hence it's benign`. Yes, the question is WHY. WHY is it benign for a program? Especially since it is not for a directory. And telling me to google is not a satisfactory answer. I wouldnt be posting here if it had a simple answer that could be googled. –  Feb 24 '18 at 21:02
  • For the fourth time, you removed the executable permission before you applied `setgid`. That made it benign. If it's not executable then you get `S`. – Nasir Riley Feb 24 '18 at 22:06
  • What are you talking about? Where did you show that files created in the directory by someone else come under ownership of the owner of the directory? You showed that you executed the files. The directories that you showed aren't even writable by anyone other than the owner so that's not even possible. – Nasir Riley Feb 24 '18 at 22:37