Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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).

share|improve this question
    
Switch the setuid()/setgid() calls around. –  vonbrand Mar 8 at 22:25
    
@vonbrand ROTFL I thought I was in for a facepalm there -- but same result, so I'll edit the question to eliminate the red herring. –  goldilocks Mar 8 at 22:27
1  
If you use setgid(54) instead of setgid(73) (as in /etc/groups, group bar has gid 54), does it work? –  lgeorget Mar 8 at 22:35
    
@lgeorget Sure, but that defeats the purpose. The process needs its own GID for other reasons, and likewise, those files must have the permissions they have. That's why membership in groups plural is necessary -- e.g., what if you have two users that need to do this. Note you can't setuid() again after you do it...but, hmmm...I think you can with seteuid()... –  goldilocks Mar 8 at 22:52
1  
My question was to be sure there was no other hidden subtle problem somewhere. :-) –  lgeorget Mar 8 at 22:54

2 Answers 2

up vote 5 down vote accepted

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;
}  
share|improve this answer
2  
Gorgeous lgeorget, thanks much. –  goldilocks Mar 8 at 22:58
1  
That was an interesting question which deserves more upvotes because it could actually be useful to a lot of people out there. :-) –  lgeorget Mar 8 at 23:00

OK, trawled around the net a bit. I thought at first that APUE would hold all the answers, but was mistaken. And my copy (old edition) is at work, so... The Unix and Linux Administration Handbook's chapter 5 looks promising, but I haven't got it (just a copy of the first two editions, also at work).

The little resources I've found (google for "daemon writing unix") all talk about important steps, like how to dissociate from the tty, etc. But nothing about UID/GID. Strangely, not even the extensive HOWTO collection at http://tldp.org seems to have details. Only excetion is Jason Short's Let's Write a Linux Daemon - part I. Full details of how SUID/SGID and all that mess works is Chen, Wagner and Dean's SUID demystified (a paper in USENIX 2002). But be careful, Linux has an extra UID, the FSUID (see Wolter's Unix Incompatibility Notes: UID Setting Functions for a discussion).

Daemonizing a process is definitely not for the faint of heart. General security considerations are given in D. Wheeler's Secure Programming for Linux and Unix HOWTO -- Creating Secure Software. Systemd promises to simplify most of that (and thus reducing the room for mistakes that lead to security problems), see the daemon manual.

share|improve this answer
1  
The question isn't about daemonization. You've confused the SUID bit (giving a process the permissions of the owner of its executable) with setuid(), which allows the process to change it's UID arbitrarily. SUID is usually intended to allow an escalation of permissions (non-privilleged -> privilleged), whereas setuid() can only do the opposite. –  goldilocks Mar 9 at 1:37

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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