-exec
The ‘-exec’ action causes another program to be run. It passes to the program the name of the file which is being considered at the time. The invoked program will typically then perform some action on that file. Once again, there is a race condition which can be exploited here. We shall take as a specific example the command
find /tmp -path /tmp/umsp/passwd -exec /bin/rm
In this simple example, we are identifying just one file to be deleted
and invoking /bin/rm
to delete it. A problem exists because
there is a time gap between the point where find
decides that
it needs to process the ‘-exec’ action and the point where the
/bin/rm
command actually issues the unlink()
system
call to delete the file from the filesystem. Within this time period, an attacker can rename the
/tmp/umsp directory, replacing it with a symbolic link to
/etc. There is no way for /bin/rm
to determine that it
is working on the same file that find
had in mind. Once the
symbolic link is in place, the attacker has persuaded find
to
cause the deletion of the /etc/passwd file, which is not the
effect intended by the command which was actually invoked.
One possible defence against this type of attack is to modify the
behaviour of ‘-exec’ so that the /bin/rm
command is run
with the argument ./passwd and a suitable choice of working
directory. This would allow the normal sanity check that find
performs to protect against this form of attack too. Unfortunately,
this strategy cannot be used as the POSIX standard specifies that the
current working directory for commands invoked with ‘-exec’ must
be the same as the current working directory from which find
was invoked. This means that the ‘-exec’ action is inherently
insecure and can’t be fixed.
GNU find
implements a more secure variant of the ‘-exec’
action, ‘-execdir’. The ‘-execdir’ action
ensures that it is not necessary to dereference subdirectories to
process target files. The current directory used to invoke programs
is the same as the directory in which the file to be processed exists
(/tmp/umsp in our example, and only the basename of the file to
be processed is passed to the invoked command, with a ‘./’
prepended (giving ./passwd in our example).
The ‘-execdir’ action refuses to do anything if the current
directory is included in the PATH
environment variable. This
is necessary because ‘-execdir’ runs programs in the same
directory in which it finds files – in general, such a directory
might be writable by untrusted users. For similar reasons,
‘-execdir’ does not allow ‘{}’ to appear in the name of
the command to be run.