Search code examples
pythonpermissionswrapperelevated-privilegessetuid

setuid/setgid wrapper for python script


I have a Python script that I wish to be able to be run as the system user guybrush with UID 200 and group guybrush with GID 200.

At the moment my Python script (located in /path/to/script.py) looks like this:

#!/usr/bin/env python2
import os

print "uid: %s" % os.getuid()
print "euid: %s" % os.getgid()
print "gid: %s" % os.geteuid()
print "egid: %s" % os.getegid()

My attempted C wrapper (scriptwrap.c) looks like this:

#include <unistd.h>
#include <sys/types.h>

int main(int argc, char *argv[]) {
    setuid(geteuid());
    setgid(getegid());
    return execv("/path/to/script.py", argv);
}

I then compile, chown, and chmod the wrapper as follows:

$ gcc scriptwrap.c -o scriptwrap
$ chown guybrush:guybrush scriptwrap
$ chmod 6755 scriptwrap

Yet when I run scriptwrap, I get the following output:

uid: 1000
euid: 1000
gid: 200
egid: 200

So for some reason only the GID is being set (my normal UID is 1000). What can I do to fix this?

Edit: If I chown the script to root:root and run it, the UID, eUID, GID, and eGID are all set to 0.

Also, this is on Ubuntu 12.04.4 LTS.


Solution

  • Well I figured this out (and learnt a bit in the process). Embarrassingly my initial problem was caused by a typo in my Python script: I was printing out the GID under the label euid, and the eUID under the label gid. Oops.

    So the eUID and eGID are actually set correctly - great. But the UID and GID still aren't set despite my use of setuid and setgid in the C wrapper.

    It turns out that this is due to the behaviour of setuid and setgid differing based on whether you are root or not: If you are root and you call setuid, it sets your real UID and your effective UID to whatever you pass it in, if you are not root it just sets the effective UID (source). So my use of setuid (and setgid) are essentially no-ops.

    However it is possible to set the real UID and GID by using the setreuid and setregid calls:

    #include <unistd.h>
    #include <sys/types.h>
    
    int main(int argc, char *argv[]) {
        setreuid(geteuid(), geteuid());
        setregid(getegid(), getegid());
        return execv("/path/to/script.py", argv);
    }
    

    Which results in the following output from the (corrected) Python script when run:

    uid: 200
    euid: 200
    gid: 200
    egid: 200