The following program demonstrates what appears
to be a bug in the implementation of setreuid().
(I haven’t a clue whether the bug is in the library
or the OS.) To test:
make testuid
su -c “chown root testuid; chmod u+s testuid”
…/testuid
I get the following output under 6.2.0:
(UID,EUID)=(101,0) => setreuid(0,101) OK
(UID,EUID)=(0,101) => setreuid(0,0) ERROR: Operation not permitted
Workaround…
(UID,EUID)=(0,101) => setreuid(101,0) OK
(UID,EUID)=(101,0) => setreuid(0,0) OK
According to the man page, if the real UID is 0,
setreuid should be able to set the effective UID
to 0 as well. I came up with the workaround of
swapping real/effective before setreuid(0,0).
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
void testreuid( uid_t uid, uid_t euid ) {
printf("(UID,EUID)=(%d,%d) => setreuid(%d,%d)",
getuid(), geteuid(), uid, euid );
if ( setreuid( uid, euid ) == -1 ) {
printf( " ERROR: %s\n", strerror(errno) );
} else {
printf( " OK\n" );
}
}
int main( int argc, char **argv ) {
testreuid(geteuid(), getuid());
testreuid(0, 0);
printf(“Workaround…\n”);
testreuid(geteuid(), getuid());
testreuid(0, 0);
return 0;
}