Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 709 Vote(s) - 3.45 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How to drop privilege temporarily from root?

#1
I am developing a daemon running as root, but need to call an API with the user, I checked the API codes, it uses `getuid()` to get the user.

If root user drops privilege by `setuid()` , it can't be restored to root. If calling seteuid(), the API will still do something as user `uid=0`.

I think fork before accessing API and setuid in the child process should work, but even if COW , it will cost much if calling API many times. Is it possible to solve the problem except using process pool?
Reply

#2
You can store the former effective uid in the *saved UID* of the process:

uid_t real = getuid();
uid_t privileged = geteuid();
setresuid(real, real, privileged);
do_API_call(); // API's getuid() call now returns real
setresuid(real, privileged, -1); // allowed, since saved==privileged

There's a corresponding `setresgid` to use saved GIDs, too.

---
Note that this answer is specific to Linux (as per question tags). A similar call exists on HP-UX and some BSD systems, but I haven't checked that the semantics are identical.

---
Actually, on further reading `setreuid()` should be sufficient (and POSIX-conformant). `setuid()` says:

> If the effective UID of the caller is root (more precisely: if the caller has the `CAP_SETUID` capability), the real UID and saved set-user-ID are also
set.

and

> If the user is root or the program is set-user-ID-root, special care must be taken. The `setuid()` function checks the effective user ID of the caller and if it is the superuser, all process-related user ID's are
set to `uid`. After this has occurred, it is impossible for the program to regain root privileges.

but there is no such statement for `setreuid()`.
Reply

#3
Yes! Create a single process to call the API with the appropriate UID and communicate with the rest of the program through a Pipe, a UNIX domain socket or (*shared memory*)<sup>1</sup>.

I mean, fork only once and keep the privileged user running another process. Then create communication between the two if needed and as needed. Also, you might want to consider using [*dbus*](

[To see links please register here]

) since it also integrates perfectly with [systemd](

[To see links please register here]

) and on modern linux you want your daemon to interact nicely with both.

**Note**: I am by no means an expert on the subject, but this is a simple idea that seems clear to me. You don't need to create a process for every call to the API. This is a good example of the [XY problem](

[To see links please register here]

), the real problem that you want to solve, has nothing to do with avoiding to `fork()` multiple times because the idea of doing that is the wrong solution. You only need to `fork()` once, drop privileges and stay there without privileges, communicating with the parent process if/as needed.

---
<sup>1</sup><sub>Any IPC mechanism that works for you.</sub>
Reply

#4
Just call `seteuid(2)` to do the appropiate unprivileged stuff. `seteuid(2)` allows to switch between the *real*(or saved) user id (the one that launches the suid program or `root` in your case) and *the suid* user id (the one the suid program belongs to) so there should be no problem to regain privileged user id afterwards (as the saved user id is `root`, you don't have any issue to switch to it again and again).

If you change uids with `setuid(2)` you'll change **all** (effective, saved and real uids) and this is only allowed to the root user (or a program setuid root, and there's no way back then).

Look at the next example:

# File pru49015.c:

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

int main(int argc, char **argv)
{
int opt, suid = getuid(), /* this is the saved uid */
uid = 0;
while ((opt = getopt(argc, argv, "i:")) != EOF) {
switch (opt) {
case 'i': uid = atoi(optarg); break;
}
}
/* execute this program with root privileges, like setuid root, for example */
printf("real uid=%d; effective uid=%d\n", getuid(), geteuid());
seteuid(uid); /* change to the non-privileged id configured */
printf("real uid=%d; effective uid=%d\n", getuid(), geteuid());
seteuid(suid); /* return back to saved uid */
printf("real uid=%d; effective uid=%d\n", getuid(), geteuid());
}

You will get an output like this:

$ pru49015 -i 37
real uid=502; effective uid=0
real uid=502; effective uid=37
real uid=502; effective uid=502

when used as a setuid-root program

If you use it as root, you'll get the following output:

$ sudo pru$$ -i 37
real uid=0; effective uid=0
real uid=0; effective uid=37
real uid=0; effective uid=0

The mechanism is that you are allowed on a setuid-<id> program to switch between the user you are (let's call it the *saved user id*) and the user the program runs setuid to (the called *effective user id* or *suid* user) as many times as you want.
Reply

#5
From [here][1]:

> Normally when a process is executed, the effective, real, and saved user and group IDs are all set to the real user and group ID of the process's parent, respectively. However, when the setuid bit is set on an executable, the effective and saved user IDs are set to the user ID that owns the file.


[1]:

[To see links please register here]

Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through