From: Pavel Raiskup Date: Sat, 15 Aug 2015 04:40:57 -0400 Subject: install-sh: avoid (low risk) race in /tmp Ensure that nobody can cross privilege boundaries by pre-creating symlink on '$tmpdir' path. Just testing 'mkdir -p' by creating '/tmp/ins$RANDOM-$$/d' is not safe because '/tmp' directory is usually world-writeable and '/tmp/ins$RANDOM-$$' content could be pretty easily guessed by attacker (at least for shells where $RANDOM is not supported). So, as the first step, create the '/tmp/ins$RANDOM-$$' without -p. This step would fail early if somebody wanted catch us. Note that systems that implement (and have enabled) fs.protected_symlinks kernel feature are not affected even without this commit. References: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=760455 https://bugzilla.redhat.com/show_bug.cgi?id=1140725 * lib/install-sh: Implement safer 'mkdir -p' test by running '$mkdirprog $mkdir_mode "$tmpdir"' first. (scriptversion): Bump. --- a/lib/install-sh +++ b/lib/install-sh @@ -345,34 +345,41 @@ do # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) + # $RANDOM is not portable (e.g. dash); use it when possible to + # lower collision chance tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ - trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0 + # As "mkdir -p" follows symlinks and we work in /tmp possibly; so + # create the $tmpdir first (and fail if unsuccessful) to make sure + # that nobody tries to guess the $tmpdir name. if (umask $mkdir_umask && - exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + $mkdirprog $mkdir_mode "$tmpdir" && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. - ls_ld_tmpdir=`ls -ld "$tmpdir"` + test_tmpdir="$tmpdir/a" + ls_ld_tmpdir=`ls -ld "$test_tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && - $mkdirprog -m$different_mode -p -- "$tmpdir" && { - ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi - rmdir "$tmpdir/d" "$tmpdir" + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. - rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null fi trap '' 0;; esac;;