>From d17ca013f3aadcf697663830fa9ec34cba551f66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A1draig=20Brady?= Date: Mon, 20 Feb 2017 18:46:49 -0800 Subject: [PATCH] cp: set SElinux context for --parents directories * src/copy.h (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 | 4 ++++ src/copy.c | 4 ++-- src/copy.h | 9 +++++++++ src/cp.c | 20 ++++++++++++++++++++ tests/cp/cp-a-selinux.sh | 23 +++++++++++++++++++++-- 5 files changed, 56 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index 7473e6e..167c376 100644 --- 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] diff --git a/src/copy.c b/src/copy.c index 9dbd536..3711539 100644 --- a/src/copy.c +++ b/src/copy.c @@ -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 +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) { @@ -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 +extern bool set_file_security_ctx (char const *dst_name, bool process_local, bool recurse, const struct cp_options *x) { diff --git a/src/copy.h b/src/copy.h index f7047bc..db65c4a 100644 --- a/src/copy.h +++ b/src/copy.h @@ -285,6 +285,15 @@ 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); +bool +set_process_security_ctx (char const *src_name, char const *dst_name, + mode_t mode, bool new_dst, + const struct cp_options *x); + +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 *); diff --git a/src/cp.c b/src/cp.c index 88db3a3..6e18263 100644 --- 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 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 diff --git a/tests/cp/cp-a-selinux.sh b/tests/cp/cp-a-selinux.sh index 19a9e64..de07406 100755 --- a/tests/cp/cp-a-selinux.sh +++ b/tests/cp/cp-a-selinux.sh @@ -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_ -- 2.5.5