I was under the impression that ‘sudo’ was baked into the entire system. Like ‘cd’ or ‘ps’. How exactly can you just swap out sudo? Does that involve swapping out chmod as well?
I was under the impression that ‘sudo’ was baked into the entire system. Like ‘cd’ or ‘ps’. How exactly can you just swap out sudo? Does that involve swapping out chmod as well?
1. Parses the sudoers file to check if the current user can run the command provided.
2. If so, authenticates the user using PAM.
3. If both those pass, sets the user id to root and runs the program.
There is nothing special about it. All steps can be done by any program. In fact sudo is usually not even an installed by default package in many systems.
The only seeming magic bit is part 3, where the program sets it's user id to root. Obviously if any program could do this... That'd be unsafe.
However, unix systems allow any executable file to have their flags changed to include the setuid bit which causes the file to execute with privileges of the files owner. You'll notice that the sudo binary has this bit set and it's owned by root, which explains now the entire process.
- Sudo can use PAM, or any other means, depending on NSS (local, ldap, through PAM, etc)
- Sudo can use a sudoers file, directory, or even LDAP fields to resolve accesses.
- Sudo can temporarily cache and forward authentication to avoid constantly retyping passwords
- Sudo can elevate you depending on your group, user, or even a glob of the command you want to type
- Sudo can log and report the executed commands
- Sudo can import none, part or all of your environment to run its command
- Etc
Sudo is very complex
"Good distro maintainers" (e.g. Arch Linux) try to minimize the attack surface by modifying their packages to use the capabilities flags instead (e.g. the net cap flag for ping binary).
"Bad distro maintainers" blame the end user for their own responsibility for letting this happen. They could have just uninstalled the program, right?
Well, I disagree. SystemD's new approach is that they try to reuse the seccomp sandboxes they've introduced for a while now, where root rights-given processes can even be executed in a chroot, with a fake /etc/passwd file, with fake users, with fake /dev ices etc.
As SystemD as the process #1 always has to be executed as root, I think it's a good thing that they try to offer a sandboxed alternative. Polkit is just so damn ugly with all their hacky subscriptions and policy files. If you disagree with me, I recommend you to learn more about privilege escalation exploits on POSIX systems, and how PAM, Polkit and pretty much any auth framework always said it's the users fault.
LD_PRELOAD auth bypasses are now more than 18 years old, and the CVE still works on enterprise-grade linux distributions. It literally was the reason muslc was created as an alternative to glibc. And that's older than a decade now.
Check out https://gtfobins.github.io (or the Windows NT equivalent LOLbins) if you wanna know how many binaries there are as an attack surface.
I would guess you are arguing in a reduction in complexity, which is semi-ironic as run0 is including polkit (and thus: an entire JS interpreter) among other things; while at the same time doas/sudo-rs exist as simpler implementations.
AFAIK, lots of the bloat of sudo is preventing a lot of the attacks you mention though, but I seriously doubt any privilege escalation system doesn't have any weak parts that need heavy scrutiny.
As long as this keeps happening due to the concept failure of how shared libraries are used for both active development and runtime execution, there won't be an easy fix available.
The stubborness of C++ developers not seeing that there is two kinds of different users, devs and endusers, is what also annoys me a lot. I understand their intent to make development and debugging easy.
But honestly, that should not be the job of the developer of a library and rather be part of the development toolchain. If the toolchain cannot fulfill this need, then the concept of binary distribution itself (aka FFI/C ABI/ELF) is wrong and needs to change.
The "never change C" mentality is what got us here, where hundreds of developers rewrite everything in Rust/Go/Zig, hoping that there is an end in sight...only to realize that at some point they have to build a different OS from the ground up to actually be able to really fix it.