Group memberships and setuid/setgid processes

grouppermissionssetgidsetuid

Processes which de-escalate privileges via setuid() and setgid() do not seem to inherit the group memberships of the uid/gid they set.

I have a server process that must be executed as root in order to open a privileged port; after that it de-escalates to a specific non-privilleged uid/gid,1 — e.g., that of user foo (UID 73). User foo is a member of group bar:

> cat /etc/group | grep bar
bar:x:54:foo

Hence if I login as foo, I can read a file /test.txt with these characteristics:

> ls -l /test.txt
-rw-r----- 1 root bar 10 Mar  8 16:22 /test.txt

However, the following C program (compile std=gnu99), when run root:

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int main (void) {
    setgid(73);
    setuid(73);
    int fd = open("/test.txt", O_RDONLY);
    fprintf(stderr,"%d\n", fd);
    return 0;
}   

Always reports Permission denied. I imagine this has to do with it being a non-login process, but it kind of hamstrings the way permissions are supposed to work.


1. Which is often SOP for servers, and I think there must be a way around this as I found a report of someone doing it with apache — apache has been added to the audio group and can apparently then use the sound system. Of course, this likely happens in a fork and not the original process, but in fact the case is the same in my context (it's a child process forked subsequent to the setuid call).

Best Answer

The problem is that setuid and setgid are not sufficient to give your process all the credentials it needs. The authorizations of a process depend on

  • its UID
  • its GID
  • its supplementary groups
  • its capabilities.

See man 7 credentials to get a more detailed overview. So, in your case, the problem is that you correctly set the UID and GID, but you don't set the supplementary groups of the process. And group bar has GID 54, no 73 so it is not recognized as a group your process is in.

You should do

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <grp.h>

int main (void) {
    gid_t supplementary_groups[] = {54};

    setgroups(1, supplementary_groups);
    setgid(73);
    setuid(73);
    int fd = open("/test.txt", O_RDONLY);
    fprintf(stderr,"%d\n", fd);
    return 0;
}  
Related Question