What it means to become another user on Unix

March 26, 2012

Ignoring things like SELinux for the moment, the basic security state of Unix system calls has always been that root is allowed to become any other UID at will, but no one else is allowed to change their UID or other security attributes (setuid programs then provide an escape hatch from this). But what does it mean to become another user on Unix, beyond just setting your UID? In fact there are a whole series of things that it can mean, some of which you do not necessarily want.

Let's make a list:

  • switching to the user's UID. This is the basic prerequisite of what it means to become another user on Unix, and is done by setuid().
  • switching your groups to the user's groups, which is done with a combination of initgroups() and setgid().

  • setting some environment variables like $HOME and $SHELL to values appropriate for the new user.

    (Most but not all versions of su do this. Versions of su that do not change $HOME can be exciting, especially when combined with shells that read initialization files from $HOME.)

  • clearing various environment variables; in the extreme case, you will clear all environment variables and give yourself a new set of safe values for things like $PATH and so on.

    (Aggressively scrubbing the environment is generally the default for sudo. In general there are any number of environment variables that are very dangerous to leave intact, such as all of the LD_* variables that influence the behavior of the dynamic loader.)

  • running the user's shell, either interactively or with -c ... to execute commands.

    (su normally always runs the user's shell; sudo will often run commands directly without starting the user's shell.)

  • changing to the user's home directory.
  • running the user's shell as a login shell.

  • allocating a new pseudo-tty as the user and attaching the user's shell and so on to it as a new session. This is generally the domain of things that are making real login sessions, like sshd, instead of programs that just become the user.

(Note that this list is not in the order that your code wants to actually do these operations. For example, you want to set groups before changing to the other UID because the moment you setuid() to a non-root user you lose the power to set your own groups list.)

Many things that become another user deliberately run the the target user's shell even when they just want to run a command. This is done partly so that the user's shell can do any special initialization that, eg, may augment its $PATH and partly so that users with restricted shells can't escape them in various clever ways. However, not everything does this and sometimes running the user's shell is inconvenient.

There are a surprising number of cases where you want basically the first two only; you want to run a command as a user but in a way such that their environment (their shell, their shell initialization, and so on) is ignored. It's possible to do this with standard commands like su and sudo by carefully reading their manpages and picking exactly the right options, but I find it easier to have a very basic runas program sitting around.

(runas only works for root, so it can completely ignore authentication and similar issues.)

Written on 26 March 2012.
« Atom feeds and constrained (web) environments
Microkernels are quite attractive to academic computer science researchers »

Page tools: View Source, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Mon Mar 26 00:05:07 2012
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.