]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
cp: set SELinux context for --parents directories
authorPádraig Brady <P@draigBrady.com>
Tue, 21 Feb 2017 02:46:49 +0000 (18:46 -0800)
committerPádraig Brady <P@draigBrady.com>
Thu, 23 Feb 2017 04:23:31 +0000 (20:23 -0800)
* src/copy.c (set_process_security_ctx, set_file_security_ctx):
Export for use in cp.c.
* src/copy.h: Likewise.
* src/cp.c (make_dir_parents_private): Call the exported functions
to set the security context for new and updated directories.
* tests/cp/cp-a-selinux.sh: Add a test case.

Fixes http://bugs.gnu.org/25378

NEWS
src/copy.c
src/copy.h
src/cp.c
tests/cp/cp-a-selinux.sh

diff --git a/NEWS b/NEWS
index 7473e6e4ac1605286854fc0e0516e3494b0c4025..167c3768ac6953b48bc4637fc1ee67aad2f4e76a 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,10 @@ GNU coreutils NEWS                                    -*- outline -*-
 
 ** Bug fixes
 
+  cp --parents will now set an SELinux context for created directories,
+  as appropriate for the -a, --preseve=context, or -Z options.
+  [bug present since SELinux support added in coreutils-6.10]
+
   date again converts from a specified time zone.  Previously output was
   not converted to the local time zone, and remained in the specified one.
   [bug introduced in coreutils-8.26]
index 9dbd5365583f6b1b4bb5a06c31aa60ea9c26a3cd..7bfbcfcd088df2851b135494598864f455abf7c7 100644 (file)
@@ -889,7 +889,7 @@ set_author (const char *dst_name, int dest_desc, const struct stat *src_sb)
    Based on CP_OPTIONS, diagnose warnings and fail when appropriate.
    Return FALSE on failure, TRUE on success.  */
 
-static bool
+bool
 set_process_security_ctx (char const *src_name, char const *dst_name,
                           mode_t mode, bool new_dst, const struct cp_options *x)
 {
@@ -951,7 +951,7 @@ set_process_security_ctx (char const *src_name, char const *dst_name,
    failure, when allowed by various settings in CP_OPTIONS.
    Return FALSE on failure, TRUE on success.  */
 
-static bool
+bool
 set_file_security_ctx (char const *dst_name, bool process_local,
                        bool recurse, const struct cp_options *x)
 {
index f7047bccdd222b29aa3f0886f736941574118885..c4bf23c85790ad1011a58cdf6477473d1bb07fd4 100644 (file)
@@ -285,6 +285,14 @@ bool copy (char const *src_name, char const *dst_name,
            bool nonexistent_dst, const struct cp_options *options,
            bool *copy_into_self, bool *rename_succeeded);
 
+extern bool set_process_security_ctx (char const *src_name,
+                                      char const *dst_name,
+                                      mode_t mode, bool new_dst,
+                                      const struct cp_options *x);
+
+extern bool set_file_security_ctx (char const *dst_name, bool process_local,
+                                   bool recurse, const struct cp_options *x);
+
 void dest_info_init (struct cp_options *);
 void src_info_init (struct cp_options *);
 
index 88db3a3e94426635480ab8445c4728044993f188..a2f67d864b477738a6f36d727b660e6cb9af4703 100644 (file)
--- a/src/cp.c
+++ b/src/cp.c
@@ -394,6 +394,8 @@ make_dir_parents_private (char const *const_dir, size_t src_offset,
 
   *attr_list = NULL;
 
+  /* XXX: If all dirs are present at the destination,
+     no permissions or security contexts will be updated.  */
   if (stat (dst_dir, &stats) != 0)
     {
       /* A parent of CONST_DIR does not exist.
@@ -437,6 +439,12 @@ make_dir_parents_private (char const *const_dir, size_t src_offset,
               *attr_list = new;
             }
 
+          /* If required set the default context for created dirs.  */
+          if (! set_process_security_ctx (src, dir,
+                                          missing_dir ? new->st.st_mode : 0,
+                                          missing_dir, x))
+            return false;
+
           if (missing_dir)
             {
               mode_t src_mode;
@@ -524,6 +532,18 @@ make_dir_parents_private (char const *const_dir, size_t src_offset,
             }
           else
             *new_dst = false;
+
+          /* For existing dirs, set the security context as per that already
+             set for the process global context.  */
+          if (! *new_dst
+              && (x->set_security_context || x->preserve_security_context))
+            {
+              if (! set_file_security_ctx (dir, x->preserve_security_context,
+                                           false, x)
+                  && x->require_preserve_context)
+                  return false;
+            }
+
           *slash++ = '/';
 
           /* Avoid unnecessary calls to 'stat' when given
index 19a9e649e23aee64809cf41118a691b6dec447f6..de0740656f9536cb02b5e158bdfd8f041f96ff1e 100755 (executable)
@@ -48,7 +48,6 @@ rm -f f
 # 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 > ed_ctx || fail=1
 grep $ctx ed_ctx && framework_failure_
@@ -57,11 +56,31 @@ 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/
+cp -a backup/. restore/ || fail=1
 ls -Zd restore/existing_dir > ed_ctx || fail=1
 grep $ctx ed_ctx &&
   { ls -lZd restore/existing_dir; fail=1; }
 
+# Check context preserved with directories created with --parents,
+# which was not handled before coreutils-8.27
+mkdir -p parents/a/b || framework_failure_
+ls -Zd parents/a/b > ed_ctx || fail=1
+grep $ctx ed_ctx && framework_failure_
+touch parents/a/b/file || framework_failure_
+chcon $ctx parents/a/b || framework_failure_
+# Set the dir context to ensure it is reset
+mkdir -p --context="$ctx" parents_dest/parents/a || framework_failure_
+# Copy and ensure existing directories updated
+cp -r --parents --preserve=context parents/a/b/file parents_dest || fail=1
+# Check new context
+ls -Zd parents_dest/parents/a/b > ed_ctx || fail=1
+grep $ctx ed_ctx ||
+  { ls -lZd parents_dest/parents/a/b; fail=1; }
+# Check updated context
+ls -Zd parents_dest/parents/a > ed_ctx || fail=1
+grep $ctx ed_ctx &&
+  { ls -lZd parents_dest/parents/a; fail=1; }
+
 # Check restorecon (-Z) functionality for file and directory
 # Also make a dir with our known context
 mkdir c_d || framework_failure_