2

I have a setuid root binary, with_sudo.bin, with the following source code:

/* with_sudo.c */
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

int main() {
    printf("\n\n ruid : %d \n euid : %d \n\n", (int)getuid(), (int)geteuid());
    system("/usr/bin/sudo cat /root/key.txt");
    return 0;
}

 

akshay@bluebox ~ $ ls -l with_sudo.bin
-rwsr-sr-x 1 root root 8684 Feb  1 22:09 with_sudo.bin

Even though it is a setuid root binary, sudo password is being asked.

akshay@bluebox ~ $ ./with_sudo.bin
ruid : 1000  euid : 0 
[sudo] password for akshay:

When I run the another binary without sudo in system(), it runs with superuser privileges.

/* without_sudo.c */
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

int main() {
    printf("\n\n ruid : %d \n euid : %d \n\n", (int)getuid(), (int)geteuid());
    system("cat /root/key.txt");
    return 0;
}

 

akshay@bluebox ~ $ ls -l without_sudo.bin
-rwsr-sr-x 1 root root 8677 Feb  1 22:09 without_sudo.bin

akshay@bluebox ~ $ ./without_sudo.bin

ruid : 1000 euid : 0

:::this_is_a_secret_key:::

When the Real UID was made 0 along with the Effective UID using setreuid(geteuid(), 0);, the binary ran with superuser privileges without prompting for sudo password even though sudo was used.

/* with_sudo_ruid_elevated.c */
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

int main() {
    setreuid(0, geteuid());
    printf("\n\n ruid : %d \n euid : %d \n\n", (int)getuid(), (int)geteuid());
    system("/usr/bin/sudo cat /root/key.txt");
    return 0;
}

I have read that EUID is used to evaluate privileges of the process to perform a particular action. Then why is sudo prompting for sudo password based on the RUID even when the EUID is 0 ?

1 Answers1

4

It’s a little complicated.  The operating system kernel uses a process’s effective UID and GID to determine its privileges/authorizations; they are used for

  • allowing/disallowing ordinary filesystem operations (e.g., open, link/unlink) based on the user/group/other rules,
  • setting the ownership of newly created files,
  • determining what other processes a process can send signals to, and
  • deciding whether a process can mount and unmount filesystems, change the date, shutdown the system, etc.

and probably other things.  But, the catch is, when a program needs to make some sort of access/authorization decision, it usually needs to use the real UID and GID.  Consider: when your with_sudo.c program executes sudo, the effective UID is root (0) and the real UID is you (1000), as demonstrated by your printfBut this is exactly the same as what happens if you run sudo from an unprivileged shell.  Whenever sudo runs, the effective UID is 0 – so sudo can’t use that to decide how to behave.  It has to use the real UID to figure out who you really, so it can determine what you’re allowed to do in sudo.  Only if the real UID is 0 does sudo conclude that you are “really” root, or at least that it cannot reliably determine your real identity, so it doesn’t know what restrictions to apply to you, and it just executes the cat without asking for any further authentication from you.