]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
mkdir: fix -pZ with existing parent directories
authorPádraig Brady <P@draigBrady.com>
Thu, 21 May 2015 10:38:13 +0000 (11:38 +0100)
committerPádraig Brady <P@draigBrady.com>
Sat, 23 May 2015 01:04:24 +0000 (02:04 +0100)
When the parent directory exists and has a different
default context to the final directory, the context
was incorrectly left as that of the parent directory.

* src/mkdir.c (process_dir): Because defaultcon() is called for
existing ancestors (as it must be to avoid races), then we must
unconditionally call restorecon() on the last component due to
the already documented caveat with make_dir_parents().
Alternatively you could temp disable o->set_security_context
around make_dir_parents(), but that would be subject to races.
* tests (tests/mkdir/restorecon.sh): Add a TODO for improvement.
Reference mknod and mkfifo with print_ver_.
* NEWS: Mention the bug fix.
Fixes http://bugs.gnu.org/20616

NEWS
src/mkdir.c
tests/mkdir/restorecon.sh

diff --git a/NEWS b/NEWS
index 1d4b718b1736b23d60f57f3a59c7fc3b0985d950..c2576c5569013691e4f788d58e37efcef8e7872b 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -27,6 +27,10 @@ GNU coreutils NEWS                                    -*- outline -*-
   head, od, split, tac, tail, and wc no longer mishandle input from files in
   /proc and /sys file systems that report somewhat-incorrect file sizes.
 
+  mkdir --parents -Z now correctly sets the context for the last component,
+  even if the parent directory exists and has a different default context.
+  [bug introduced with the -Z restorecon functionality in coreutils-8.22]
+
   paste no longer truncates output for large input files.  This would happen
   for example with files larger than 4GiB on 32 bit systems with a '\n'
   character at the 4GiB position.
index 404a04a71e2cb2c82177cdb07da8bb8afc8c947d..ff51ae1e60d289ae825a3362fb2bdaf2d8b24762 100644 (file)
@@ -151,23 +151,11 @@ static int
 process_dir (char *dir, struct savewd *wd, void *options)
 {
   struct mkdir_options const *o = options;
-  bool set_defaultcon = false;
 
   /* If possible set context before DIR created.  */
   if (o->set_security_context)
     {
-      if (! o->make_ancestor_function)
-        set_defaultcon = true;
-      else
-        {
-          char *pdir = dir_name (dir);
-          struct stat st;
-          if (STREQ (pdir, ".")
-              || (stat (pdir, &st) == 0 && S_ISDIR (st.st_mode)))
-            set_defaultcon = true;
-          free (pdir);
-        }
-      if (set_defaultcon && defaultcon (dir, S_IFDIR) < 0
+      if (! o->make_ancestor_function && defaultcon (dir, S_IFDIR) < 0
           && ! ignorable_ctx_err (errno))
         error (0, errno, _("failed to set default creation context for %s"),
                quote (dir));
@@ -184,7 +172,8 @@ process_dir (char *dir, struct savewd *wd, void *options)
      final component of DIR is created.  So for now, create the
      final component with the context from previous component
      and here we set the context for the final component. */
-  if (ret == EXIT_SUCCESS && o->set_security_context && ! set_defaultcon)
+  if (ret == EXIT_SUCCESS && o->set_security_context
+      && o->make_ancestor_function)
     {
       if (! restorecon (last_component (dir), false, false)
           && ! ignorable_ctx_err (errno))
index a31cab9bce790fa1921bd8c46083f91538df085f..7d6a671b58a8d24cec2593c74a7891c50c025e77 100755 (executable)
@@ -17,7 +17,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 . "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
-print_ver_ mkdir
+print_ver_ mkdir mknod mkfifo
 require_selinux_
 
 
@@ -38,6 +38,7 @@ if restorecon restored 2>/dev/null; then
   mkdir -Z single || fail=1
   # Run these as separate processes in case global context
   # set for an arg, impacts on another arg
+  # TODO: Have the defaultcon() vary over these directories
   for dir in single_p single_p/existing multi/ple; do
     mkdir -Zp "$dir" || fail=1
   done