Upstream patch on top of 8.22: http://lists.gnu.org/archive/html/coreutils/2014-01/msg00012.html Stripped down to the relevant part: NEWS and THANKS.in chunks removed. Original NEWS entry: cp -a again sets the correct SELinux context for existing directories in the destination. Previously it set the context of an existing directory to that of its last copied descendent. [bug introduced in coreutils-8.22] Originally reported for Fedora by Michal Trunecka in rh#1045122: https://bugzilla.redhat.com/show_bug.cgi?id=1045122 ______________________________________________________________________ From f2f8b688b87b94ed3551f47f9a6422c873acf5d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A1draig=20Brady?= Date: Sun, 5 Jan 2014 15:00:55 +0000 Subject: [PATCH] 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. --- src/copy.c | 13 ++++++++++++- tests/cp/cp-a-selinux.sh | 15 +++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) Index: src/copy.c =================================================================== --- src/copy.c.orig 2013-12-05 01:59:36.000000000 +0100 +++ src/copy.c 2014-01-09 02:47:33.108744454 +0100 @@ -2408,6 +2408,17 @@ copy_internal (char const *src_name, cha 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, cha /* 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, Index: tests/cp/cp-a-selinux.sh =================================================================== --- tests/cp/cp-a-selinux.sh.orig 2013-12-04 15:48:30.000000000 +0100 +++ tests/cp/cp-a-selinux.sh 2014-01-09 02:47:33.109744597 +0100 @@ -41,6 +41,21 @@ test -s err && fail=1 #there must be n 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 +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_ +# Set the permissions of the source to show they're reset too +chmod o+rw restore/existing_dir +# 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