Modern shells and running shell scripts while seteuid

November 13, 2016

You can't and shouldn't make a shell script setuid, but there are times when you can want to deliberately run a shell script from within a seteuid context, especially a seteuid root one. One case for this is if you want to kick off a script from PAM module that may be run for, eg, password changes.

I will cut to the chase: you probably don't want to do this today, because modern Unixes or more exactly modern shells on Unixes are making this harder and harder to do reliably. If at all possible, transition fully to the new UID you want the shell script to operate under, either by doing the appropriate setuid() call in your own code before you invoke the script or by changing how the entire system is invoked (for example, by doing things through sudo).

In the old days of Unix, shells were blithely unconcerned about security issues; those were your problem, and it was up to you to do things right. Over time, it became obvious that a certain number of people were not going to do things right and that perhaps it would be a good idea for shells to save people from themselves, at least some of the time. For example, one fruitful source of security issues here is setuid programs using popen() to run things. popen() starts a shell, which was running seteuid, and there are any number of ways to subvert a shell if you aren't careful (especially modern shells, which can have their behavior influenced by any number of environment variables).

So shells started saving people from themselves in this situation. If you start a modern shell in a seteuid environment and don't give it a special flag (people seem to have standardized on -p), it immediately drops seteuid privileges and generally also ignores a number of environment variables that would normally influence its behavior.

(Some shells in the Bourne family will do this all of the time, even if they're being used as /bin/sh, but some of them will do this only if they're invoked under their own name and stick to the traditional behavior when run as /bin/sh. The latter is less secure but more compatible with existing behavior.)

This presents not one but two problems if you intend to run a shell script in such a seteuid environment on a modern Unix with such a modern shell. The obvious and direct problem is that you have to make sure to start the shell script with '#!/bin/sh -p' or '#!/bin/bash -p' or the like; otherwise the shell will immediately drop permissions on you. The good news is that you're probably going to notice and fix this right away, at least once you work out what's happening.

The less obvious problem is that running your own script with -p has armed a gun that's pointed at any other shell scripts that your script runs. Unless those scripts also start with -p, they may (or will) immediately drop seteuid when they start to run and will quite possibly malfunction as a result. Effectively, running with -p poisons your environment in a subtle way. It's possible to work around this in various ways, but it makes your whole shell script fragile; all you need is one thing that your script runs deciding to call a shell script that doesn't have a -p and things can blow up.

(And naturally many of the things that your script uses may not ever have thought about this, because they're just regular scripts, not special security-related scripts that ever expected to run in a seteuid environment. Some of them may not even really be safe in a seteuid environment in general, so just slapping a -p on them is dangerous in its own way.)

Given that running seteuid is now a taint as far as modern shells are concerned, it's more reliable to avoid this taint in the first place. In other words, run your initial shell script without it being seteuid (one way or another).

Written on 13 November 2016.
« My view on accepting bounces and replies to your email
Why I believe native apps are not doomed by progressive web apps »

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

Last modified: Sun Nov 13 02:01:25 2016
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.