From 4f560d6e5e5678763f736f974862fd253b3285a3 Mon Sep 17 00:00:00 2001 From: =?utf-8?q?Ond=C5=99ej=20Va=C5=A1=C3=ADk?= Date: Tue, 17 Feb 2009 15:53:39 +0100 Subject: [PATCH] cp: make -a option preserve SELinux ctx with reduced diagnostics * copy.c (copy_reg): Reduce SELinux context diagnostics for 'cp -a'. (copy_internal): Likewise * copy.h (cp_options): Add boolean reduce_diagnostics. * cp.c (usage): Mention that --archive (-a) behaves like -dR --preserve=all. (cp_option_init): Initialize added reduce_diagnostics. (main): Add reduce_diagnostics for -a option and preserve SELinux context, if possible. * mv.c (cp_options_init): Set initial value for added booleans in cp_options. * install.c (cp_option_init): Likewise. * NEWS: Mention those behaviour changes. * doc/coreutils.texi: Document --preserve=context, document that diagnostics are not shown for failures of non-mandatory attributes (just SELinux at the moment). * tests/cp/cp-a-selinux: Check not only failures, but succesful use of preserving SELinux context in cp. --- NEWS | 5 ++++- doc/coreutils.texi | 14 +++++++++++--- src/copy.c | 28 ++++++++++++++++------------ src/copy.h | 6 ++++++ src/cp.c | 8 ++++++-- src/install.c | 2 ++ src/mv.c | 2 ++ tests/cp/cp-a-selinux | 22 ++++++++++++++++++---- 8 files changed, 65 insertions(+), 22 deletions(-) diff --git a/NEWS b/NEWS index 2b17e74..c01756d 100644 --- a/NEWS +++ b/NEWS @@ -6,7 +6,7 @@ GNU coreutils NEWS -*- outline -*- Add extended attribute support available on certain filesystems like ext2 and XFS. - cp: Tries to copy xattrs when --preserve=xattr specified + cp: Tries to copy xattrs when --preserve=xattr or --preserve=all specified mv: Always tries to copy xattrs install: Never copies xattrs @@ -32,6 +32,9 @@ GNU coreutils NEWS -*- outline -*- cp uses much less memory in some situations + cp -a now correctly tries to preserve SELinux context (announced in 6.9.90), + doesn't inform about failure unlike with --preserve=all + du --files0-from=FILE no longer reads all of FILE into RAM before processing the first file name diff --git a/doc/coreutils.texi b/doc/coreutils.texi index ba1e74e..ba6f6e0 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi @@ -7261,8 +7261,11 @@ The program accepts the following options. Also see @ref{Common options}. Preserve as much as possible of the structure and attributes of the original files in the copy (but do not attempt to preserve internal directory structure; i.e., @samp{ls -U} may list the entries in a copied -directory in a different order). -Equivalent to @option{-dpR}. +directory in a different order). Try to preserve SELinux security context, +but do not fail when this is not succesful. Diagnostic errors are not +displayed for this non-guaranteed attribute. Option doesn't preserve +extended attributes(xattr) at the moment. +Equivalent to @option{-dR --preserve=all} with few exceptions. @item -b @itemx @address@hidden@var{method}]} @@ -7404,6 +7407,9 @@ Preserve in the destination files any links between corresponding source files. @c Give examples illustrating how hard links are preserved. @c Also, show how soft links map to hard links with -L and -H. address@hidden context +Preserve SELinux security context of the file. @command{cp} will fail +if the preserving of SELinux security context is not succesful. @itemx xattr Preserve extended attributes if @command{cp} is built with xattr support, and xattrs are supported and enabled on your file system. @@ -7411,7 +7417,9 @@ If SELinux context and/or ACLs are implemented using xattrs, they are preserved by this option as well. @itemx all Preserve all file attributes. -Equivalent to specifying all of the above. +Equivalent to specifying all of the above. Ignore failure +to preserve SELinux security context or extended attributes, +but show diagnostic messages about failures. @end table Using @option{--preserve} with no @var{attribute_list} is equivalent diff --git a/src/copy.c b/src/copy.c index a6ca9dd..7a7fae4 100644 --- a/src/copy.c +++ b/src/copy.c @@ -450,7 +450,8 @@ copy_reg (char const *src_name, char const *dst_name, security_context_t con = NULL; if (getfscreatecon (&con) < 0) { - error (0, errno, _("failed to get file system create context")); + if (!x->reduce_diagnostics) + error (0, errno, _("failed to get file system create context")); if (x->require_preserve_context) { return_val = false; @@ -462,9 +463,10 @@ copy_reg (char const *src_name, char const *dst_name, { if (fsetfilecon (dest_desc, con) < 0) { - error (0, errno, - _("failed to set the security context of %s to %s"), - quote_n (0, dst_name), quote_n (1, con)); + if (!x->reduce_diagnostics) + error (0, errno, + _("failed to set the security context of %s to %s"), + quote_n (0, dst_name), quote_n (1, con)); if (x->require_preserve_context) { return_val = false; @@ -472,7 +474,7 @@ copy_reg (char const *src_name, char const *dst_name, goto close_src_and_dst_desc; } } - freecon(con); + freecon (con); } } @@ -495,7 +497,7 @@ copy_reg (char const *src_name, char const *dst_name, if (*new_dst) { int open_flags = O_WRONLY | O_CREAT | O_BINARY; - dest_desc = open (dst_name, open_flags | O_EXCL , + dest_desc = open (dst_name, open_flags | O_EXCL, dst_mode & ~omitted_permissions); dest_errno = errno; @@ -1721,9 +1723,10 @@ copy_internal (char const *src_name, char const *dst_name, { if (setfscreatecon (con) < 0) { - error (0, errno, - _("failed to set default file creation context to %s"), - quote (con)); + if (!x->reduce_diagnostics) + error (0, errno, + _("failed to set default file creation context to %s"), + quote (con)); if (x->require_preserve_context) { freecon (con); @@ -1736,9 +1739,10 @@ copy_internal (char const *src_name, char const *dst_name, { if (errno != ENOTSUP && errno != ENODATA) { - error (0, errno, - _("failed to get security context of %s"), - quote (src_name)); + if (!x->reduce_diagnostics) + error (0, errno, + _("failed to get security context of %s"), + quote (src_name)); if (x->require_preserve_context) return false; } diff --git a/src/copy.h b/src/copy.h index 0cdf16b..ac980f4 100644 --- a/src/copy.h +++ b/src/copy.h @@ -186,6 +186,12 @@ struct cp_options this flag is "true", while with "cp --preserve=all", it is false. */ bool require_preserve_xattr; + /* Used as difference boolean between cp -a and cp -dR --preserve=all. + If true, non-mandatory failure diagnostics are not displayed. This + should prevent poluting cp -a output. + */ + bool reduce_diagnostics; + /* If true, copy directories recursively and copy special files as themselves rather than copying their contents. */ bool recursive; diff --git a/src/cp.c b/src/cp.c index 9171fa6..57907cc 100644 --- a/src/cp.c +++ b/src/cp.c @@ -160,7 +160,7 @@ Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n\ Mandatory arguments to long options are mandatory for short options too.\n\ "), stdout); fputs (_("\ - -a, --archive same as -dpR\n\ + -a, --archive same as -dR --preserve=all\n\ --backup[=CONTROL] make a backup of each existing destination file\n\ -b like --backup but does not accept an argument\n\ --copy-contents copy contents of special files when recursive\n\ @@ -766,6 +766,7 @@ cp_option_init (struct cp_options *x) x->preserve_security_context = false; x->require_preserve_context = false; x->preserve_xattr = false; + x->reduce_diagnostics = false; x->require_preserve_xattr = false; x->require_preserve = false; @@ -921,13 +922,16 @@ main (int argc, char **argv) sparse_type_string, sparse_type); break; - case 'a': /* Like -dpR. */ + case 'a': /* Like -dR --preserve=all with reduced failure diagnostics. */ x.dereference = DEREF_NEVER; x.preserve_links = true; x.preserve_ownership = true; x.preserve_mode = true; x.preserve_timestamps = true; x.require_preserve = true; + if (selinux_enabled) + x.preserve_security_context = true; + x.reduce_diagnostics = true; x.recursive = true; break; diff --git a/src/install.c b/src/install.c index 669fbea..905b838 100644 --- a/src/install.c +++ b/src/install.c @@ -289,8 +289,10 @@ cp_option_init (struct cp_options *x) x->preserve_links = false; x->preserve_mode = false; x->preserve_timestamps = false; + x->reduce_diagnostics=false; x->require_preserve = false; x->require_preserve_context = false; + x->require_preserve_xattr = false; x->recursive = false; x->sparse_mode = SPARSE_AUTO; x->symbolic_link = false; diff --git a/src/mv.c b/src/mv.c index db9207b..77ad2fb 100644 --- a/src/mv.c +++ b/src/mv.c @@ -122,9 +122,11 @@ cp_option_init (struct cp_options *x) x->preserve_mode = true; x->preserve_timestamps = true; x->preserve_security_context = selinux_enabled; + x->reduce_diagnostics = false; x->require_preserve = false; /* FIXME: maybe make this an option */ x->require_preserve_context = false; x->preserve_xattr = true; + x->require_preserve_xattr = false; x->recursive = true; x->sparse_mode = SPARSE_AUTO; /* FIXME: maybe make this an option */ x->symbolic_link = false; diff --git a/tests/cp/cp-a-selinux b/tests/cp/cp-a-selinux index 2f4af35..8b7cc4d 100755 --- a/tests/cp/cp-a-selinux +++ b/tests/cp/cp-a-selinux @@ -1,8 +1,10 @@ #!/bin/sh # Ensure that cp -a and cp --preserve=context work properly. # In particular, test on a writable NFS partition. +# Check also locally if --preserve=context, -a and --preserve=all +# does work -# Copyright (C) 2007-2008 Free Software Foundation, Inc. +# Copyright (C) 2007-2009 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 @@ -29,6 +31,21 @@ require_selinux_ cwd=`pwd` cleanup_() { cd /; umount "$cwd/mnt"; } +# This context is special: it works even when mcstransd isn't running. +ctx=root:object_r:tmp_t:s0 + +# Check basic functionality - before check on fixed context mount +touch c || framework_failure +chcon $ctx c || framework_failure +cp -a c d 2>err || framework_failure +cp --preserve=context c e || framework_failure +cp --preserve=all c f || framework_failure +ls -Z d | grep $ctx || fail=1 +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 + + # Create a file system, then mount it with the context=... option. dd if=/dev/zero of=blob bs=8192 count=200 > /dev/null 2>&1 \ || framework_failure @@ -36,9 +53,6 @@ mkdir mnt || framework_failure mkfs -t ext2 -F blob || skip_test_ "failed to create an ext2 file system" -# This context is special: it works even when mcstransd isn't running. -ctx=root:object_r:tmp_t:s0 - mount -oloop,context=$ctx blob mnt || framework_failure cd mnt || framework_failure -- 1.5.6.1.156.ge903b