0

Look at this c program:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    printf("UID:  %d\n", getuid());
    printf("EUID: %d\n", geteuid());
    system("id");

    printf("res=%d\n", setuid(1001));

    printf("UID:  %d\n", getuid());
    printf("EUID: %d\n", geteuid());
    system("id");
    return 0;
}

My user account is "test" (id 1000). I have a second user account: "test2" (id 1001).

Here is what I've done:

gcc test.c -o ./a.out
sudo chown test2 ./a.out
sudo chmod u+s ./a.out

Now, here is what happens if I launch ./a.out:

UID:  1000
EUID: 1001
uid=1000(test) gid=1000(test) groups=1000(test),...
res=0
UID:  1000
EUID: 1001
uid=1000(test) gid=1000(test) groups=1000(test),...
          

I do not understand why I do not see uid=1001 in the second part...

I have tried this:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    printf("UID:  %d\n", getuid());
    printf("EUID: %d\n", geteuid());
    system("id");

    printf("res=%d\n", setuid(0));  // <- Here is the change

    printf("UID:  %d\n", getuid());
    printf("EUID: %d\n", geteuid());
    system("id");
    return 0;
}
          
gcc test.c -o ./a.out
sudo chown root ./a.out
sudo chmod u+s ./a.out

Here is what I get when running ./a.out:

UID:  1000
EUID: 0
uid=1000(test) gid=1000(test) groups=1000(test),...
res=0
UID:  0
EUID: 0
uid=0(root) gid=1000(test) groups=1000(test),...
           

Now, it works.

So I don't understand why setuid does not work with test2 user and works with root users...

Any idea ?

Thanks

2
  • How secure do you think your system would be if a normal user like test2 had the privilege to change to a different UID? Dec 23, 2022 at 12:34
  • I do not understand what you mean
    – Bob5421
    Dec 23, 2022 at 14:05

1 Answer 1

5
+25

There are a couple of things going on here, which cause this confusion. Setuid does work in both cases, it just doesn't work the way you think it would. First, there is the issue of real and effective user IDs. According to the setuid(2) man page

If the calling process is privileged (more precisely: if the process has the CAP_SETUID capability in its user namespace), the real UID and saved set-user-ID are also set.

This also means that is the calling process does not have the CAP_SETUID capability (which is the case of your ordinary users), then the UID will not change, only the EUID.

So we move on to the system() call. Calling system("anything") is the equivalent of calling this:

execl("/bin/sh", "sh", "-c", "anything", (char *) NULL);

So it spawns /bin/sh, providing arguments so that a new shell will execute your command. I assume you use bash as your shell, because bash works so

If the shell is started with the effective user (group) id not equal to the real user (group) id, and the -p option is not supplied, (...) the effective user id is set to the real user id.

So if your process does not have the CAP_SETUID capability, it won't change the real user ID, only the effective UID. Then, when bash is spawned, it drops the effective UID, since UID is not equals to EUID. You can confirm this by calling

system("touch /tmp/blah")

and adding

FILE *file = fopen("/tmp/blah2", "w+");
fclose(file);

to your program. You will see that the owner of /tmp/blah will be "test" (since the EUID will be dropped on shell execution), but /tmp/blah2 will belong to "test2".

3
  • A very good answer
    – Nifle
    Dec 26, 2022 at 9:37
  • Thanks but there is something I do not understand: "This also means that is the calling process does not have the CAP_SETUID capability (..), then the UID will not change, only the EUID.". For my second test, the calling process do not have CAP_SETUID. But it works...
    – Bob5421
    Dec 26, 2022 at 11:20
  • But it did have CAP_SETUID, since it was a root process. If an executable has the setuid bit set, it runs in the name of the owning user. That is why printing the EUID yielded 0, even before calling setuid(). It was effectively a root process from the beginning, and as such, it had CAP_SETUID.
    – Lacek
    Dec 26, 2022 at 15:20

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .