sudo policy basics

John Sonmez has been encouraging me to write more online. [1]

And as the other day I found some discussion and advice online suggesting something in sudoers I don't agree with I decided to write on that subject.

This article covers technical basics together with policy. Managers and auditors might benefit from an improved understanding of what's involved even if they don't write configuration themselves.


sudo is a setuid root program that allows non-root accounts to run certain commands as if another account had run them - governed by the configuration which contains details of who is supposed to run what. Examples can be seen at [2]

The program and the usual configuration file are documented. [3] [4]

policy goals

When you are making or amending sudoers content you are using technology to try to reach policy goals. These might be to allow execution as root of certain commands (and no others), to produce usable logging and to keep the configuration understandable and maintainable.

There's great variation in the commands you might be interested in but that will not be the subject of the article. There is nothing new in the technical remarks here - I am explaining the policy implications arising from what people may have found in the documentation since I first downloaded sudo in 1994. Anybody who uses a program and expects good results without reading the manual is likely to be disappointed. In the case of a program like this that probably means insecure configuration.

policy choices

A major piece of policy thinking is about whether you want a certain account allowed to run arbitrary commands as root (e.g. root shell). If you do you can most easily allow this with a rule for running su.

If you don't then you need to be very careful what you allow. This suggests these main policy groups:

  1. allow a root shell (simplest and least restrictive policy)
  2. allow specific commands as root (without root shell)
  3. allow commands run as non-root (less capacity for causing damage)
These could be combined e.g. by allowing restart of services as root plus allow root shell. The root shell would be intended for use only when needed (situations other than restarting the services) and a log entry that it had been used would be made. The organisation could follow that up by asking what the shell was needed for.

A stricter policy would be that no root shells (or arbitrary commands) are allowed. There is the approved set of commands and no more. If you have this aim you need to take care over what is included in the approved commands. The following commands would be unsafe choices because they change security state after which the user may have access to do anything.

ways to a shell

There are plenty of ways to get from a specific chosen command to any other command (such as a shell).

There are commands that run other commands - for some commands that is their main purpose but for others it is just a small (and perhaps little-known) feature of the program. There are programs that write files - and with nearly everything in unix being a file there's a lot of scope for overcoming security that way.

Obvious commands that run other commands include:

Obvious commands that write files include:

denying commands

This brings me to the discussion that started me writing this. Someone had suggested

Cmnd_Alias NSHELLS = /bin/sh,/bin/bash
Cmnd_Alias NSU = /bin/su
Cmnd_Alias NVIS = /usr/sbin/visudo
Cmnd_Alias NSDO = /usr/bin/sudo

UserA can't execute commands like sudo su - , sudo bash , sudo sudo bash etc
The above configuration attempts to allow all commands except for some exclusions. In fact it allows all commands.

The exclusions expressed above are for program names - not the programs themselves. Since a copy of any program file is a file with the same content but a different name it follows that anyone making a copy (or only a link) gets a program of the same content but at a name that is not one of the set banned by the sudoers configuration.

cp /bin/bash /tmp/harmless
sudo /tmp/harmless # oops

Also the vast number of ways to arbitrary commands includes the programs with shell escapes and the other categories listed above.

sudo more /etc/services # followed by !sh, oops
sudo man ls # followed by !sh, oops (gets root on Fedora, not on SuSE)

In an article I'm trying to keep simple I won't go into the NOEXEC tag available in sudoers except to say that it would prevent

sudo man ls
completely which is different from allowing it to be run and preventing shell escapes from it.

The above examples show that there are many commands that will need to be banned if you want to prevent root shells - and a list of what to ban doesn't work. The way forward is to start with everything banned and allow only specific things you want (after ensuring they don't breach your policy). Of course what a program does depends not only on the program but also on the input such as the command line.

denying parameters

john ALL=/usr/bin/crontab -u * -l
The above configuration is a real example I've encountered - it allows john to run crontab as root using the -u option to make crontab act for a particular user. Also the '-l' at the end of the line is supposed to mean list the cron file for that user. That looks a bit like read-only access to the cron files for all users with no ability to change them. In fact it allows creating or changing cron files for any user.

A manual for crontab (there are different versions) shows that you can supply a filename at the end of a command to be used as input - importing that file as the cron settings. The alert reader will notice that the configuration above ends the line with '-l' so to import a file with that sudo rule we'd better put our desired commands in a file called '-l' (which is perfectly possible). One more detail is needed to import the file as root's cron.

sudo crontab -u root -- -l
The "--" is not in the manual for crontab but it comes from the getopt library function; and the "*" in the rule allows it by matching "root --" as explained in the manual [4] (under "wildcards").
The special argument "--" forces an end of option-scanning regardless of the scanning mode.
A better rule would be this where there is no variation allowed in the parameters but the username is supplied with '-u' to sudo rather than crontab.
john ALL=(ALL) /usr/bin/crontab -l

file manipulation

This is another suggested entry I have seen - I don't think there was a strong reason for it.
evil ALL=/usr/bin/ssh-keygen
If the 'evil' user wants to take over the account 'victim' on the same host it will be useful to write/overwrite ~victim/.ssh/authorized_keys. with ssh-keygen run via sudo.
cd ~/.ssh
ln -s ~victim/.ssh/authorized_keys
touch id_rsa
# Now you are ready to generate a key - the two output files overwrite what you made already. sudo ssh-keygen -t rsa -f `pwd`/id_rsa
chmod go= id_rsa # you own this file
ssh victim@localhost # ~victim/.ssh/authorized_keys contains your public key

Probably the maintainers haven't used O_EXCL or O_NOFOLLOW in opening the key files because they can't believe anyone would enable ordinary users to run it via sudo.

further examples

The list of dangerous commands is almost unlimited - some more examples:


sendmail can be told what to use as a configuration file (and when run as root will do so) - the file contains commands. Here is a demo I did on Fedora 22. The sudoers file contains this:

evil ALL=/sbin/sendmail
The 'evil' user first copies /var/mail/ to /tmp/ and edits it to use an alternative port number (1025) and to run different versions of procmail and smrsh which he also provides as scripts in /tmp/ .
O DaemonPortOptions=Port=1025,Addr=, Name=MTA
Mprocmail, P=/tmp/procmail, F=DFMSPhnu9, S=EnvFromSMTP/HdrFromSMTP, R=EnvToSMTP/HdrFromSMTP,
Mlocal, P=/tmp/procmail, F=lsDFMAw5:/|@qSPfhn9, S=EnvFromL/HdrFromL, R=EnvToL/HdrToL,
Mprog, P=/tmp/smrsh, F=lsDFMoqeu9, S=EnvFromL/HdrFromL, R=EnvToL/HdrToL, D=$z:/,
This demo /tmp/procmail script creates a logfile to show it has been run as root.

Next comes the command run by 'evil'
root 1392 0.0 0.1 233440 7852 pts/0 S+ 00:22 0:00 sudo /usr/sbin/sendmail -C /tmp/ -bD
And another session is used to send mail to that sendmail listener causing it to make a mail delivery with the nobbled procmail and the log shows it worked.
-rw-r--r--. 1 root root 29 Jul 18 00:25 SUDO_WARNING_PROCMAIL
SElinux was enabled in enforcing mode but failed to prevent this security lapse.

The above may remind readers of Olaf Kirch's report of a bug in vixie-cron in 1999 [5] where a user's cron settings caused sendmail to be run as root. All I've done here is demonstrate the same thing but called from sudo.


What could be wrong with allowing merely the tvf option that won't make or extract a tarfile?

evil ALL=/bin/tar tvf *
How about this which despite encountering an error has first run the command supplied as a replacement for rsh.
tar tvf localhost:/wibble --rsh-command=/tmp/something-evil


The -w option to tcpdump causes it to write a file (that will follow symbolic links). That is enough to overwrite files but it's hard to get complete control of what's in the file you'd write. In some cases though that's unimportant. If you wrote to .rhosts a line with a + by itself can be made with three characters "\n+\n" which is ascii 10,43,10 - easy to slip into some network data (such as an IP address). It's probably not much used these days but where it is that one line is the configuration to allow access from any host that resolves - and it won't matter that the rest of the file is junk.

More ominously there is an option to run external commands for handling output files.

sudo tcpdump -w OUT -Z root -G 5 -z /tmp/do_evil
I saw this mentioned on the web but I can't remember where so I'll leave a link to an article [6] someone else wrote about the -z post-rotate option.
SElinux was enabled in enforcing mode but failed to prevent this security lapse. I don't know how to extend an SElinux policy to prevent this but using Apparmor is easy.

the literature

Extracts from the manual deal with attempting to exclude commands with ! [4]
Note, however, that using a '!' in conjunction with the built-in ALL alias to allow a user to run 'all but a few' commands rarely works as intended (see SECURITY NOTES below).
It is generally not effective to 'subtract' commands from ALL using the '!' operator. A user can trivially circumvent this by copying the desired command to a different name and then executing that. For example:

bill ALL = ALL, !SU, !SHELLS

Doesn't really prevent bill from running the commands listed in SU or SHELLS since he can simply copy those commands to a different name, or use a shell escape from an editor or other program. Therefore, these kind of restrictions should be considered advisory at best (and reinforced by policy). In general, if a user has sudo ALL there is nothing to prevent them from creating their own program that gives them a root shell (or making their own copy of a shell) regardless of any '!' elements in the user specification.

Beside knowing the tools you are working with, it is also good to know something about the subject of security when working toward security goals. It has been known for decades that you should explicitly define access rather than permit everything minus some exceptions. That is true in relation to sudo as in many other situations. Here is some work by other people summarising the most famous statement on this. [7] [8]

Smith writes about principles [9]

Only a handful of Saltzer and Schroeder's original 1975 design principles have stood the test of time.
I would put that as only a handful have made it into widespread use. It it true some of them are not easy to do in current systems and it can be easy to find excuses not to do them. The rule on failsafe defaults is one that I think normally can be applied.
Perhaps lists of principles belong primarily in the classroom and not in the workplace. The short phrases are easy to remember, but they may promote a simplistic view of technical problems. Students need simplicity to help them build an understanding of a more complex reality.
As someone whose attitude was developed more in the workplace than the classroom I think people are not aiming for simple correctness as much as they can and should.

The original 1975 paper [10] is not an easy read.

There is some overlap between the above and the writing of Marcus Ranum (not at all hard to read). [11]


Commands that take input or use files writable by users (for input or output) make it harder to tell what was done when reviewing logs. There is some capacity for logging input and output but that's a significant burden that might be reserved for actual root shells provided you can avoid the commands capable of giving root shells when misused.

final notes

I have only shown commands used as intended (by the programmers - not by the people behind the sudoers rule in the examples). This leaves untouched the whole subject of memory corruption which could make many more programs execute unintended code.

I have not found any large or representative collections of real sudoers files published - without that I have more anecdote than data on the prevalence of the problems I have described. If someone can publish such a thing (perhaps with some obscuring of the origin) I think that would make interesting reading.


  1. Soft Skills

  2. A P Lawrence

  3. sudo manual

  4. sudoers manual

  5. 1999 cron bug using sendmail

  6. why sudo tcpdump is dangerous
    Even if you had been satisfied with a previous version of the program you would need to be alert to new features. git bisect at tells me
    commit d047be29f9c87ec5db3168a132a732a6c5aaff38
    Date: Thu Mar 23 17:33:01 2006 +0000
    add support for the the post-rotate -z flag (to be used in

  7. Saltzer & Schroeder commentary by Shostack from the series The Security Principles of Saltzer and Schroeder

  8. Saltzer & Schroeder commentary by Wagner

  9. Security Design Principles

  10. Saltzer and Schroeder

  11. Ranum Six Dumbest
version 1
Written by Peter M Allan. 2016
back to articles