[prev in list] [next in list] [prev in thread] [next in thread] 

List:       bugtraq
Subject:    Re: Temporary Files (was Re: mktemp() and friends)
From:       Zoltan Hidvegi <hzoli () cs ! elte ! hu>
Date:       1996-12-27 1:45:29
[Download RAW message or body]

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

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic