I’ll try to explain why this is I think any such attempt must fail. Buckle up
In the old times there was “root” and lusers, the privilege separation was completely binary. But some time in the 2.2 era, Linux implemented capabilities. This means that you can be root, completely unprivileged, or in one of the 1099511627774 intermediate states.
In addition, we have MAC, in particular SELinux, which means that you can be “privileged”, but actually unable to do something.
In the other direction, we have extended file attributes, which allow the admin to grant write access to various things to unprivileged or less-privileged users. Systemd uses this to give access to the system journal to users in administrative groups and to certain device nodes to users who are logged in locally.
Finally, processes can use dbus and other IPC to execute operations via a privileged daemon, which in turn can use polkit to allow or disallow operations based on arbitrarily complex policies.
Altogether, answering the question whether “this process can do that thing” is … hard. The only reliable way is to just try and handle failure appropriately.
The interesting corollary is that all programs that are supposed to “run as root” must always treat every individual operation as something that can fail (because even if the process formally has privileges, MAC or something else may prevent the operation) and must report such failure in sufficient detail. It is not OK to say “we failed” or “not enough privileges, must be root”, because that is not enough to figure out what exactly failed. In fact, the process may be root and still fail.
(In systemd, we had a bunch of programs intended to be ran as root which would flat out refuse to start with a different UID. We removed all those checks.)
Then there are cases where it’s actually fine if the process doesn’t have enough privileges. For example, the user executes a privileged command to see what it will try to do. Another case is where the program implements a “dry run” mode where it only logs what it would do. If we were to be strict about this separation, we would have to move programs from /usr/sbin
to /usr/bin
when they implement a --dry-run
option.
We just cannot say “this program requires root”.
That’s a separate issue. We have a bunch of binaries which are intentionally outside of $PATH
. /usr/libexec
has hundreds of programs, and there are even more in other locations under /usr
.