1

I have a process P which is spawned by a process owned by root. After P is created setguid() and setuid() are called and it runs as user U.

The process P attempts to create a file f on a folder F (in the root file system) which is owned by root and has the following privileges:

drwxrwx---    2 root     root

The function call look likes this:

open(path , O_CREAT | O_RDWR , 0660);

If I run the command ps -e -o cmd,uid,euid,ruid,suid,gid,egid,rgid,sgid the result is the following:

/my/process    500   500   500   500   500   500   500   500

This confirm that the process P is not running as root however strange enough even if the process runs as user U the file f is create under the folder F which should be only writable by root and its group members:

-rw-rw---- 1 U U

So the file is owned by U.

If I try doing the same from the bash I get a "Permission Denied" as expected:

$ touch /F/f
touch: cannot touch `/F/f': Permission denied

If I set the folder F permissions to:

drwx------    2 root     root

then the open() call fails with "Permission Denied" as expected.

Why can P create the file in that folder when writing permission has been granted to the root group?

The ps command shows that all uid and gid are set to the related user ids so how can it possible?

These are the group memberships of root and U:

$groups root
root : root

$groups U
U : U G

So U has G as secondary group

$lid -g root
 root(uid=0)
 sync(uid=5)
 shutdown(uid=6)
 halt(uid=7)
 operator(uid=11)

$lid -g U
 U(uid=500)

$lid -g G
 U(uid=500)

This show that only U is a member of G

1

Like @jdwolf mentions in the comments, the issue might be supplementary groups. setgid() doesn't remove them.

A simple test, ./drop here is a program that calls setregid() and setreuid() to change the GID and UID to nobody, and then runs id:

# id
uid=0(root) gid=0(root) groups=0(root)
# ./drop
uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup),0(root)

There's still the zero group. Adding setgroups(0, NULL) (before the setuid()) removes that group:

# ./drop2
uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)

Of course, that doesn't add any of the other target user's groups.

  • @Bemipefe, the order of setgid() and setgroups() doesn't actually matter. You just need to leave the setuid() last since changing groups arbitrarily needs privileges. – ilkkachu Nov 17 '17 at 10:15
  • Ok but since setgit() must always preceed setuid() I would place setgroups() before both function calls. I doesn't matter programmatically but it does matter from the code readability and maintenance point of view. – Bemipefe Nov 17 '17 at 12:52

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.