2016-11-02 15:40:40 +0700, Robert Elz:
[...]
>   | If 'mktemp' were a POSIX standard utility, this wouldn't be an issue,
>   | but it's not, so it is.
> 
> mktemp certainly makes it easier (and more efficient) to create unique
> filenames (and is now ubiquitous enough that it probably ought be added)
> but it isn't required - locking can be done without it, and with locking
> a scheme can be written which creates files as needed (the lock file isn't
> the file ultimately to be created, just a lock - when the lock is owned,
> the script no longer needs atomic operations, it can test and create quite
> safely.)
[...]

You're looking at it from the point of view of locking. As you
say, ln or mkdir can be used for that instead.

set -C is often used as a way to create a temp file (a poor
man's mktemp). And as currently implemented it is not safe.

A typical implementation of mktemp as a POSIX shell function is:

mktemp() {
  mktemp_prefix=${TMPDIR:-/tmp}/$1.$$
  mktemp_suffix=
  mktemp_fd=${2-1}

  case $- in
    (*C*) mktemp_restore=;;
    (*) mktemp_restore="set +C"; set -C;;
  esac

  mktemp_mask=$(umask)
  umask 077 || return

  mktemp_ret=0
  mktemp_n=0

  until
    REPLY=$mktemp_prefix$mktemp_suffix
    eval 'command exec '"$mktemp_fd"'<> "$REPLY"' 2> /dev/null &&
      [ -f "$REPLY" ] &&
      [ ! -L "$REPLY" ]
  do
    mktemp_n=$((mktemp_n + 1))
    if [ "$mktemp_n" -gt 20 ]; then
      echo >&2 "Unable to create a temp file after $mktemp_n attemps"
      eval "command exec $mktemp_fd>&-" 2> /dev/null
      REPLY=
      mktemp_ret=1
      break
    fi
    mktemp_suffix=.$mktemp_n
  done

  eval "$mktemp_restore"
  umask "$mktemp_mask"
  return "$mktemp_ret"
}

mktemp "${0##*/}.tmp" 3 || exit
echo test >&3
rm -f "$REPLY"


Here, the fact that set -C has an internal race condition
matters as much as the fact that it will happily open non-regular files.
Our [ -f "$REPLY" ] is also racy.

The race in set -C means an attacker can make you clobber any file, but
even if that race window is closed, that still means an attacker can
make you open or clobber any device/fifo file.

At the moment, there's no way (that I know) to create a temp file
reliably with POSIX utilities (though it may be possible to create a
temp dir reliably, which is generally a better idea than creating a temp
file in a world writable directory anyway).

Or IOW, rather than adding a O_NOCLOBBER open flag to fix that (not very
useful) "set -C", it would be more useful to add a proper shell
interface to O_EXCL.

One to O_NOFOLLOW (or to any arbitrary open flag supported by
the system as suggested in that zsh ML thread) would be welcome as well.

-- 
Stephane

Reply via email to