2

I have some C++ code on a Linux machine whose purpose is to run some code as an arbitrary user.

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

void doAsUser(uid_t uid) {
    if (CAP_IS_SUPPORTED(CAP_SETUID)) {
        cout << "Do we have CAP_SETUID? " << cap_get_bound(CAP_SETUID) << endl;
    } else {
        cout << "CAP_SETUID not supported!" << endl;
    }

    uid_t ruid, euid, suid;
    getresuid(&ruid, &euid, &suid);
    cout << "UIDs: " << ruid << " " << euid << " " << suid << endl;

    // assume credentials of user
    status = seteuid(uid);
    if (status < 0) {
        cerr << "FATAL ERROR: Couldn't set uid: " <<  strerror(errno) << endl;
        exit(1);
    }

    // do stuff here...

    // re-assume credentials of program
    status = seteuid(my_uid);
    if (status < 0) {
        cerr << "FATAL ERROR: Couldn't reset uid: " <<  strerror(errno) << endl;
        exit(1);
    }
}

However, without fail, you get the following output when this function is run:

$ sudo ./program

...

Do we have CAP_SETUID? 1
UIDs: 0 0 0
FATAL ERROR: Couldn't set uid: Operation not permitted

What's going on here? I thought things running as root (you know, with UID 0 and CAP_SETUID) could assume effective UIDs of any other user.

EDIT: This question does not adequately answer my problem, because, as it states, "In order to perform the call to seteuid even though the EUID at the time is not 0, the SUID must be 0". My SUID is 0, my CAP_SETUID is 1, and I have no other security framework in place.

  • I have found a solution to this and would like to post an answer. Could you please unmark this as a duplicate? – Iconmaster Jan 22 '19 at 17:26
  • Thank you for instrumenting your routine.  Now, could you please take it a step further and modify the code to print the value of “uid” (the argument to the function), just in case it is some weird, invalid value?  And, maybe, to be paranoid, print the return values of getuid, geteuid and getresuid.  Note that your current code won’t even compile, since you are still using my_uid even though you have deleted its declaration, and you have never showed us a declaration for status (please don’t tell me that it’s a global variable). – G-Man Says 'Reinstate Monica' Jan 23 '19 at 23:07
  • Um, doesn't cap_get_bound() just check the bounding set? Don't you need to check the effective capabilities instead? – Olorin Jan 29 '19 at 07:14
  • @Iconmaster what was your solution? – lucidbrot Oct 15 '22 at 12:01

0 Answers0