Bugtraq mailing list archives

Re: Temporary Files (was Re: mktemp() and friends)


From: hzoli () cs elte hu (Zoltan Hidvegi)
Date: Fri, 27 Dec 1996 01:45:29 +0100


Benedikt Stockebrand <benedikt () devnull ruhr de> wrote:
[...]
DIR=/tmp/_dirname$$
FILE=$DIR/_filename
[...]
Sorry, I forgot to mention that I usually use noclobber with bash (I'm
decadent enough to use bash wherever I can --- AFAIK plain sh and ash
don't supports this) as well as umask in about any shell script used
for cron-based use.  While I consider your approach more fool-proof
and probably more portable than my suggestion, I think that noclobber
has about the same effect (except for all those annoying ...||exit 1).
Everyone feel free to correct me if I'm wrong.

Unfortunately you cannot trust nolobber.  POSIX mandates noclobber (set -C)
but it also allos writing to device special files even if noclobber is set
to allow redirects to /dev/null work without changes.

This means that if one symlinks a file to your disk device, the shell will
overwrite it happily.

Under bash this can be avoided theoretically:

set -C
exec > /tmp/foo
if ! test -f /dev/fd/1; then
        error...
fi

There are two bugs in bash which makes this unsafe.  The bash manual tells
you that tests to /dev/fd/n apply to the file descriptor n but in fact they
apply to the real /dev/fd/n if the OS supports the /dev/fd filesystem.  On
Solaris /dev/fd/n is always a device special file which makes the above
test fail in all cases.

The other bug is that noclobber is not implemented atomically.  Here is the
code.  Redirect->flags contains O_TRUNC | O_WRONLY | O_CREAT here:

          r = stat (redirectee_word, &finfo);

          if (r == 0 && (S_ISREG (finfo.st_mode)))
            {
              free (redirectee_word);
              return (NOCLOBBER_REDIRECT);
            }

          /* If the file was not present, make sure we open it exclusively
             so that if it is created before we open it, our open will fail. */
          if (r != 0)
            redirect->flags |= O_EXCL;

          fd = open (redirectee_word, redirect->flags, 0666);

As you can see bash will happily truncate any symlink created between the
stat and open.  I have already mailed the bash maintainer about these bugs.

I checked that ksh and pdksh behave similarity (and anyone can use strace
or truss to check his favourite shell).

Of course the right way to do that is to never use O_TRUNC with noclobber,
try O_WRONLY | O_CREAT | O_EXCL first, and if that fails, open it with
O_WRONLY, fstat the returned file descriptor and close it and fail if it is
a regular file.

I am decadent enough to use zsh even for /bin/sh which does not have these
two bugs and additionally it has many features I miss from bash.

Zoltan



Current thread: