6

At the end of the man page for sudo, there's the following remark:

   Running shell scripts via sudo can expose the same kernel bugs that
   make setuid shell scripts unsafe on some operating systems (if your OS
   has a /dev/fd/ directory, setuid shell scripts are generally safe).

Pretty much everything in that paragraph is obscure to me. In particular, I'd like to learn what the allusion to /dev/fd is all about. I tried to guess some possible man pages where I may find this information, but I came up empty.

Any suggestions?

(Ultimately I'd like to run a few scripts under sudo via cron, if that's possible, but of course I'm concerned about possible security holes in such an unsupervised arrangement.)

kjo
  • 15,339
  • 25
  • 73
  • 114
  • Total guess: because the presence of /dev/fd coincides with a historical change made to the kernel "on some operating system", aka. linux. – goldilocks Mar 21 '13 at 12:47
  • 4
    General question: Why are you performing a sudo in a cron job spec? Why not just put the commands in the target user's crontab? – Bratchley Mar 21 '13 at 13:15

1 Answers1

6

I can't see how that can apply to sudo.

For the setuid scripts, the idea is this:

Assume you have a /usr/local/bin/myscript that is setuid root and starts with #! /bin/sh. Nobody has write access to /usr/local/bin or myscript, but anybody can do:

ln -s /usr/local/bin/myscript /tmp/-i

And /tmp/-i also becomes a setuid script, and even though you still won't have write access to it, you do have write access to /tmp.

On systems where setuid scripts are not executed by means of /dev/fd, when you execute cd /tmp && -i, the setuid bit means it will run: /bin/sh -i as root:

  1. The process changes euid to the file owner
  2. The system parses the shebang
  3. The system executes (still as root), /bin/sh -i

Now, for that particular case, the easy work around is to write the shebang the recommended way: #! /bin/sh -, but even then, there's a race condition. Now it becomes:

  1. The process changes euid to the file owner
  2. The system parses the shebang
  3. The system executes (still as root), /bin/sh - -i
  4. "sh" opens the "-i" file in the current directory (fine you would think).

But between 3 and 4 above, you have plenty of time to change "-i" or ("any-file", as it's a different attack vector here) to some evil "-i" file that contains for instance just "sh" and you get a root shell (for a setuid root script).

With older versions of ksh, you didn't even need to do that because in 4, ksh first looked for "-i" in $PATH, so it was enough to put your evil "-i" in $PATH (ksh would open that one instead of the one in /tmp).

All those attack vectors are fixed if when you do: cd /tmp; -i, the system does instead (still in the execve system call):

  1. atomically: find out the file is setuid and open the file on some file descriptor x of the process.
  2. process euid changes to the file owner.
  3. Run /bin/sh /dev/fd/x
  4. sh opens /dev/fd/x which can only refer to the file that was execved.

The point is that the file is opened as part of the execve so we know it's the code with the trusted content that is going to be interpreted with changed priviledges.

Now that doesn't apply to sudo because the sudo policy is based on path.

If the sudo rule says you can run /usr/local/bin/myscript as root, then you can do:

sudo /usr/local/bin/myscript

But you can't do:

sudo /tmp/any-file

Even if "any-file" is a hardlink or symlink to /usr/local/bin/myscript. sudo doesn't make use of /dev/fd AFAICT.

  • That was an education! I think I got almost everything, but you lost me here: some evil* "-i" file that contains for instance just "sh"*. In the last "for instance", did you mean a file that contains the two-character string "sh", or the executable for sh (i.e. a copy of /bin/sh)? – kjo Mar 21 '13 at 14:20
  • 1
    @kjo, Well, the 3 characters "s", "h" and "\n". That is, when "sh" will interpret that, it will run an interactive "sh". – Stéphane Chazelas Mar 21 '13 at 19:41