summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPádraig Brady <P@draigBrady.com>2014-01-02 16:40:58 +0000
committerPádraig Brady <P@draigBrady.com>2014-01-13 12:52:26 +0000
commit243128dbf0293be7b170dd47c8dbf3ed1834c093 (patch)
tree55b105c10b08539b90491398275c7f62c35f130e
parent5d7591d0edf0dd31c2daa195ee766c1383b89f4c (diff)
downloadcoreutils-243128dbf0293be7b170dd47c8dbf3ed1834c093.tar.xz
copy: fix SELinux context preservation for existing directories
* src/copy.c (copy_internal): Use the global process context to set the context of existing directories before they're populated. This is more consistent with the new directory case, and fixes a bug for existing directories where we erroneously set the context to the last copied descendent, rather than to that of the source directory itself. * tests/cp/cp-a-selinux.sh: Add a test for this case. * NEWS: Mention the fix. * THANKS.in: Add reporter Michal Trunecka.
-rw-r--r--NEWS7
-rw-r--r--THANKS.in1
-rw-r--r--src/copy.c13
-rwxr-xr-xtests/cp/cp-a-selinux.sh16
4 files changed, 36 insertions, 1 deletions
diff --git a/NEWS b/NEWS
index 66884db74..3e1f9c6ac 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,13 @@ GNU coreutils NEWS -*- outline -*-
* Noteworthy changes in release ?.? (????-??-??) [?]
+** Bug fixes
+
+ cp -a, mv, and install --preserve-context, once again set the correct SELinux
+ context for existing directories in the destination. Previously they set
+ the context of an existing directory to that of its last copied descendent.
+ [bug introduced in coreutils-8.22]
+
* Noteworthy changes in release 8.22 (2013-12-13) [stable]
diff --git a/THANKS.in b/THANKS.in
index 658837601..5b3e96ed2 100644
--- a/THANKS.in
+++ b/THANKS.in
@@ -441,6 +441,7 @@ Michael Veksler mveksler@techunix.technion.ac.il
Michail Litvak mci@owl.openwall.com
Michal Politowski mpol@charybda.icm.edu.pl
Michal Svec msvec@suse.cz
+Michal Trunecka mtruneck@redhat.com
Michel Robitaille robitail@IRO.UMontreal.CA
Michiel Bacchiani bacchian@raven.bu.edu
Mike Castle dalgoda@ix.netcom.com
diff --git a/src/copy.c b/src/copy.c
index 557d37b2b..3e4cbff7f 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -2408,6 +2408,17 @@ copy_internal (char const *src_name, char const *dst_name,
else
{
omitted_permissions = 0;
+
+ /* For directories, the process global context could be reset for
+ descendents, so use it to set the context for existing dirs here.
+ This will also give earlier indication of failure to set ctx. */
+ if (x->set_security_context || x->preserve_security_context)
+ if (! set_file_security_ctx (dst_name, x->preserve_security_context,
+ false, x))
+ {
+ if (x->require_preserve_context)
+ goto un_backup;
+ }
}
/* Decide whether to copy the contents of the directory. */
@@ -2598,7 +2609,7 @@ copy_internal (char const *src_name, char const *dst_name,
/* With -Z or --preserve=context, set the context for existing files.
Note this is done already for copy_reg() for reasons described therein. */
- if (!new_dst && !x->copy_as_regular
+ if (!new_dst && !x->copy_as_regular && !S_ISDIR (src_mode)
&& (x->set_security_context || x->preserve_security_context))
{
if (! set_file_security_ctx (dst_name, x->preserve_security_context,
diff --git a/tests/cp/cp-a-selinux.sh b/tests/cp/cp-a-selinux.sh
index 79b1c0acf..3ab7e0e28 100755
--- a/tests/cp/cp-a-selinux.sh
+++ b/tests/cp/cp-a-selinux.sh
@@ -41,6 +41,22 @@ test -s err && fail=1 #there must be no stderr output for -a
ls -Z e | grep $ctx || fail=1
ls -Z f | grep $ctx || fail=1
+# Check handling of existing dirs which requires specific handling
+# due to recursion, and was handled incorrectly in coreutils-8.22
+# Note standard permissions are updated for existing directories
+# in the destination, so SELinux contexts should be updated too.
+chmod o+rw restore/existing_dir
+mkdir -p backup/existing_dir/ || framework_failure_
+ls -Zd backup/existing_dir | grep $ctx && framework_failure_
+touch backup/existing_dir/file || framework_failure_
+chcon $ctx backup/existing_dir/file || framework_failure_
+# Set the dir context to ensure it is reset
+mkdir -p --context="$ctx" restore/existing_dir || framework_failure_
+# Copy and ensure existing directories updated
+cp -a backup/. restore/
+ls -Zd restore/existing_dir | grep $ctx &&
+ { ls -lZd restore/existing_dir; fail=1; }
+
# Check restorecon (-Z) functionality for file and directory
get_selinux_type() { ls -Zd "$1" | sed -n 's/.*:\(.*_t\):.*/\1/p'; }
# Also make a dir with our known context