Add a test for cp -p and existing file permissions.
authorPaul Eggert <eggert@cs.ucla.edu>
Sat, 1 Dec 2007 09:10:52 +0000 (10:10 +0100)
committerJim Meyering <meyering@redhat.com>
Sat, 1 Dec 2007 09:10:52 +0000 (10:10 +0100)
* tests/cp/Makefile.am (TESTS): Add existing-perm-race.
* tests/cp/existing-perm-race: New test.  It isn't much of a
test yet, since it's hard to catch the race, but it has a FIXME
that will let us do a better test later.

ChangeLog
tests/cp/Makefile.am
tests/cp/existing-perm-race [new file with mode: 0644]

index f662660..83ca215 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2007-11-29  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Add a test for cp -p and existing file permissions.
+       * tests/cp/Makefile.am (TESTS): Add existing-perm-race.
+       * tests/cp/existing-perm-race: New test.  It isn't much of a
+       test yet, since it's hard to catch the race, but it has a FIXME
+       that will let us do a better test later.
+
 2007-11-28  Paul Eggert  <eggert@cs.ucla.edu>
 
        Fix a security race with "cp -p A B" when B already exists.
index 159b93a..4af269c 100644 (file)
@@ -21,6 +21,7 @@ TESTS = \
   thru-dangling \
   cp-a-selinux \
   file-perm-race parent-perm-race \
+  existing-perm-race \
   backup-dir \
   src-base-dot \
   sparse \
diff --git a/tests/cp/existing-perm-race b/tests/cp/existing-perm-race
new file mode 100644 (file)
index 0000000..11f38d2
--- /dev/null
@@ -0,0 +1,94 @@
+#!/bin/sh
+# Make sure cp -p isn't too generous with existing file permissions.
+
+# Copyright (C) 2006-2007 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+if test "$VERBOSE" = yes; then
+  set -x
+  cp --version
+fi
+
+. $srcdir/../group-names
+. $srcdir/../test-lib.sh
+
+set _ $groups; shift
+g1=$1
+g2=$2
+
+fail=0
+
+umask 077
+mkfifo fifo || {
+  echo "$0: fifos not supported; skipping this test." 1>&2
+  (exit 77); exit 77
+}
+
+touch fifo-copy &&
+chgrp $g1 fifo &&
+chgrp $g2 fifo-copy &&
+chmod g+r fifo-copy || framework-failure
+
+# Copy a fifo's contents.  That way, we can examine the
+# destination permissions before they're finalized.
+cp -p --copy-contents fifo fifo-copy &
+cp_pid=$!
+
+(
+  # Now 'cp' is reading the fifo.  Wait for the destination file to
+  # be written to, encouraging things along by echoing to the fifo.
+  while test ! -s fifo-copy; do
+    echo foo
+  done
+
+  # Check the permissions of the destination.
+  ls -l -n fifo-copy >ls.out &&
+
+  # Close the fifo so that "cp" can continue.  But output first,
+  # before exiting, otherwise some shells would optimize away the file
+  # descriptor that holds the fifo open.
+  echo foo
+) >fifo || fail=1
+
+# Check that the destination mode is safe while the file is being copied.
+read mode links owner group etc <ls.out || fail=1
+case $mode in
+  -rw-------*) ;;
+
+  # FIXME: Remove the following case; the file mode should always be
+  # 600 while the data are being copied.  This will require changing
+  # cp so that it also does not put $g1's data in a file that is
+  # accessible to $g2.  This fix will not close a security hole, since
+  # a $g2 process can maintain an open file descriptor to the
+  # destination, but it's safer anyway.
+  -rw-r-----*)
+    # If the file has group $g1 and is group-readable, that is definitely
+    # bogus, as neither the source nor the destination was readable to group $g1.
+    test "$group" = "$g1" && fail=1;;
+
+  *) fail=1;;
+esac
+
+wait $cp_pid || fail=1
+
+# Check that the final mode and group are right.
+ls -l -n fifo-copy >ls.out &&
+read mode links owner group etc <ls.out || fail=1
+case $mode in
+  -rw-------*) test "$group" = "$g1" || fail=1;;
+  *) fail=1;;
+esac
+
+(exit $fail); exit $fail