The basic idea is that a process may only reduce its privileges. A process may not gain any privileges. There is one exception: a process that executes a program from a file that has a setuid or setgid flag set gains the privileges expressed by this flag.
Note how this mechanism does not allow a program to run arbitrary code with elevated privileges. The only code that can be run with elevated privileges is setuid/setgid executables.
The root user, i.e. the user with id 0, is more privileged than anything else. A process with user 0 is allowed to do anything. (Group 0 is not special.)
Most processes keep running with the same privileges. Programs that log a user in or start a daemon start as root, then drop all privileges and execute the desired program as the user (e.g. the user's login shell or session manager, or the daemon). Setuid (or setgid) programs can operate as the target user and group, but many switch between the caller's privileges and their own additional privileges depending on what they're doing, using the mechanisms I am going to describe now.
Every process has three user IDs: the real user ID (RUID), the effective user ID (EUID), and the saved user ID (SUID). The idea is that a process can temporarily gain privileges, then abandon them when it doesn't need them anymore, and gain them back when it needs them again. There's a similar mechanism for groups, with a real group ID (RGID), an effective group ID (EGID), a saved group ID (SGID) and supplementary groups. The way they work is:
- Most programs keep the same real UID and GID throughout. The main exception is login programs (and daemon launchers), which switch their RUID and RGID from root to the target user and group.
- File access, and operations that require root privileges, look at the effective UID and GID. Privileged programs often switch their effective IDs depending on whether they're executing a privileged operation.
- The saved IDs allow switching the effective IDs back and forth. A program may switch its effective ID between the saved ID and the real ID.
A program that needs to perform certain actions with root privileges normally runs with its EUID set to the RUID, but calls seteuid
to set its EUID to 0 before running the action that requires privileges and calls seteuid
again to the EUID change back to the RUID afterwards. In order to perform the call to seteuid(0)
even though the EUID at the time is not 0, the SUID must be 0.
The same mechanism can be used to gain group privileges. A typical example is a game that saves high scores of local users. The game executable is setgid games
. When the game starts, its EGID is set to games
, but it changes back to the RGID so as not to risk performing any action that the user isn't normally allowed to do. When the game is about to save a high score, it changes its EGID temporarily to games
. This way:
- Because the high score file requires privileges that ordinary users don't have, the only way to add an entry to the high score file is to play the game.
- If there's a security vulnerability in the game, the worst that it can do is grant a user permission to the
games
group, allowing them to cheat on high scores.
- If there's a bug in the game that doesn't result in the program calling the
setegid
function, e.g. a bug that only causes the game to write to an unintended file, then that bug doesn't allow cheating on high scores, because the game doesn't have the permission to write to the high score file without calling setegid
.
What I wrote above is describes a basic traditional Unix system. Some modern systems have other features that complement the traditional Unix privilege model. These features come in addition to the basic user/group effective/real system and sometimes interact with it. I won't go into any detail about these additional features, but I'll just mention three features of the Linux security model.
- The permission to perform many actions is granted via a capability rather than to user ID 0. For example, changing user IDs requires the capability
CAP_SETUID
, rather than having user ID 0. Programs running as user ID 0 receive all capabilities unless they go out of their way, and programs running with CAP_SETUID
can acquire root privileges, so in practice running as root and having CAP_SETUID
are equivalent.
- Linux has several security frameworks that can restrict what a process can do, even if that process is running as user ID 0. With some security frameworks, unlike with the traditional Unix model and capabilities, a process may gain privileges upon
execve
due to the security framework's configuration rather than due to flags in the executable file's metadata.
- Linux has user namespaces. A process running as root in a namespace only has privileges inside that namespace.
setuid(0)
, so was just wondering how it is possible there. And if it possible there why isn't it possible in other cases ? What prerequisites are needed for the method to successfully execute ? That was my question. I know my claim is false. – ng.newbie Oct 22 '17 at 17:03su
has the setuid permission bit set – thrig Oct 22 '17 at 18:10