The setres[u|g]id(2) system calls

Here are a couple of wrapper calls—the setresuid(2) and the setresgid(2); their signatures:

#define _GNU_SOURCE         /* See feature_test_macros(7) */
#include <unistd.h>

int setresuid(uid_t ruid, uid_t euid, uid_t suid);
int setresgid(gid_t rgid, gid_t egid, gid_t sgid);

This pair of system calls is like a superset of the earlier set*id() APIs. With the setresuid(2) system call, a process can set the RUID, EUID, and saved-set-id all at once, with a single system call (the res in the system call name stands for real, effective, and saved-set-ID, respectively).

A non-privileged (meaning, non-root) process can only use this system call to set the three IDs to one of the current RUID, the current EUID, or the current saved-set UID, nothing else (the usual security principle at work). Passing -1 implies to leave the corresponding value unchanged. A privileged (root) process can use the call to set the three IDs to any values, of course. (As usual, the setresgid(2) system call is identical except that it sets group credentials).

Some real-world OSS projects indeed use this system call; good examples are the OpenSSH project (the Linux port is called OpenSSH-portable) and the well-known sudo(8) utility.

OpenSSH: from its git repository here: https://github.com/openssh/openssh-portable/ :

uidswap.c: permanently_drop_suid():

void permanently_drop_suid(uid_t uid)
[...]
debug("permanently_drop_suid: %u", (u_int)uid);
if (setresuid(uid, uid, uid) < 0)
fatal("setresuid %u: %.100s", (u_int)uid, strerror(errno));

[...]

/* Verify UID drop was successful */
if (getuid() != uid || geteuid() != uid) {
fatal("%s: euid incorrect uid:%u euid:%u (should be %u)",
__func__, (u_int)getuid(), (u_int)geteuid(), (u_int)uid);
}

It's interesting to notice the effort taken to ensure that the UID drop was successful—more on this next!

Performing an strace(1) on sudo(8) (notice we have to trace it as root, as attempting to strace a setuid program as a regular user does not work as, while tracing, the setuid bit is deliberately ignored; this output is from an Ubuntu Linux system):

$ id mail 
uid=8(mail) gid=8(mail) groups=8(mail)
$ sudo strace -e trace=setuid,setreuid,setresuid sudo -u mail id

[...]
setresuid(-1, 0, -1) = 0
setresuid(-1, -1, -1) = 0
setresuid(-1, 8, -1) = 0
setresuid(-1, 0, -1) = 0
[...]

Clearly, sudo uses the setresuid(2) system call to set permissions, credentials, really, as appropriate (in the preceding example, the process EUID is being set to that of the mail user, the RUID and saved-set-id are being left unchanged).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.157.62