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:
- The process changes euid to the file owner
- The system parses the shebang
- 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:
- The process changes euid to the file owner
- The system parses the shebang
- The system executes (still as root),
/bin/sh - -i
- "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):
- atomically: find out the file is setuid and open the file on some file descriptor
x
of the process.
- process euid changes to the file owner.
- Run
/bin/sh /dev/fd/x
sh
opens /dev/fd/x
which can only refer to the file that was execve
d.
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.