tud-zih-energy / lo2s

Linux OTF2 Sampling - A Lightweight Node-Level Performance Monitoring Tool
https://tu-dresden.de/zih/forschung/projekte/lo2s?set_language=en
GNU General Public License v3.0
46 stars 13 forks source link

setuid() support for process mode #301

Closed cvonelm closed 4 months ago

cvonelm commented 1 year ago

Currently, the program under measurement runs with the same privileges as lo2s itself. This is problematic when the measurement feature you want to use (upcoming POSIX I/O support for example) is only available to root and you can't or don't want to run the program under measurement as root.

teto519f commented 4 months ago

I've looked into this a bit and as far as I can see, there isn't a perfect way to implement this.

The actual dropping of privileges is more or less simple, see https://www.oreilly.com/library/view/secure-programming-cookbook/0596003943/ch01s03.html

But simply adding a flag, which has to be added when calling on lo2s with higher privileges, isn't pretty, since it could be forgotten or deliberately omitted.

Everything would work just fine if we assume the user gained their privileges through sudo. Sudo changes effective, real and saved uid to 0, which we could check for and reset them to the actual users uid before then calling on exec(). The actual user id is saved in the environment var SUDO_UID and the actual group id in SUDO_GID (see https://www.geeksforgeeks.org/real-effective-and-saved-userid-in-linux/ and https://man7.org/linux/man-pages/man8/sudo.8.html).

But what if sudo wasn't used? I haven't found a way to access the callers id in that case, since all variants of getuid() or getgid() would access the already changed ids (see https://man7.org/linux/man-pages/man2/getuid.2.html or corresponding man pages).

s9105947 commented 4 months ago

thx for the writeup.

We have checked back with some more colleagues, which recommended strongly against using the setuid flag on the lo2s binary itelf, and recommended using sudo. The rationale is that setuid opens vectors through e.g. environment variables. sudo cleans up the environment and prevents this particular issue. I haven't found a concise writeup on suid binaries vs sudo from brief googling, so maybe this is overly cautious. Note that the "proper way" to do suid is to have a component that does only do the stuff that requires privileges, and another component that does all other.

cvonelm commented 4 months ago

I think I have worded this ambiguously.

What I want is root -> start lo2s -> fork -> setuid() to normal user -> start program under measurement as normal user. (Kind of how webservers acquire low port numbers and then drop to a less privileged user for the actual serving)

I agree that using the setuid-bit is a security disaster waiting to happen and something that we will not really be able to convince people to just deploy on their systems.

Something that i've tried some time ago is

$ sudo lo2s -- sudo -u normal_user ./application

but I recall that this does not work for some subtle reason (Most likely that sudo resists the ptrace() from lo2s, because ptrace() could be used to control the sudo, circumventing the security checks baked into it). But simple testcases I've tried just now seem to work just fine.

s9105947 commented 4 months ago

Just to write it down, we aim to implement:

$ sudo lo2s -- id
uid=1000(user) gid=100(users) groups=100(users)

This might not work due to sudo disliking lo2s, in which case we would reconsider.

teto519f commented 4 months ago

So, current goal is:

cvonelm commented 4 months ago

Implemented in 8e13667