Kamil Dudka 3bf1e5
From c424bbcb532c5b9924349e3522b3b431eaa7c178 Mon Sep 17 00:00:00 2001
Kamil Dudka 3bf1e5
From: Kamil Dudka <kdudka@redhat.com>
Kamil Dudka 3bf1e5
Date: Fri, 8 Jul 2016 18:59:35 +0200
Kamil Dudka 3bf1e5
Subject: [PATCH] install: with -Z, set default SELinux context for created
Kamil Dudka 3bf1e5
 directories
Kamil Dudka 3bf1e5
Kamil Dudka 3bf1e5
* doc/coreutils.texi (install invocation): Update -Z documentation.
Kamil Dudka 3bf1e5
* src/install.c (make_ancestor): Set default security context before
Kamil Dudka 3bf1e5
calling mkdir() if the -Z option is given.
Kamil Dudka 3bf1e5
(process_dir): Call restorecon() on the destination directory if the
Kamil Dudka 3bf1e5
-Z option is given.
Kamil Dudka 3bf1e5
(usage): Update -Z documentation.
Kamil Dudka 3bf1e5
* tests/install/install-Z-selinux.sh: A new test for 'install -Z -D'
Kamil Dudka 3bf1e5
and 'install -Z -d' based on tests/mkdir/restorecon.sh.
Kamil Dudka 3bf1e5
* tests/local.mk: Reference the test.
Kamil Dudka 3bf1e5
* NEWS: Mention the improvement.
Kamil Dudka 3bf1e5
Reported at https://bugzilla.redhat.com/1339135
Kamil Dudka 3bf1e5
Fixes http://bugs.gnu.org/23868
Kamil Dudka 3bf1e5
Kamil Dudka 3bf1e5
Upstream-commit: 502518b44039138d148e2e15157d125c82d02af0
Kamil Dudka 3bf1e5
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
Kamil Dudka 3bf1e5
---
Kamil Dudka 3bf1e5
 doc/coreutils.texi                 |  2 +-
Kamil Dudka 3bf1e5
 src/install.c                      | 33 ++++++++++++++++++----
Kamil Dudka 3bf1e5
 tests/install/install-Z-selinux.sh | 58 ++++++++++++++++++++++++++++++++++++++
Kamil Dudka 3bf1e5
 tests/local.mk                     |  1 +
Kamil Dudka 3bf1e5
 4 files changed, 88 insertions(+), 6 deletions(-)
Kamil Dudka 3bf1e5
 create mode 100644 tests/install/install-Z-selinux.sh
Kamil Dudka 3bf1e5
Kamil Dudka 3bf1e5
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
Kamil Dudka 3bf1e5
index 092192c..1543f27 100644
Kamil Dudka 3bf1e5
--- a/doc/coreutils.texi
Kamil Dudka 3bf1e5
+++ b/doc/coreutils.texi
Kamil Dudka 3bf1e5
@@ -9208,7 +9208,7 @@ Print the name of each file before moving it.
Kamil Dudka 3bf1e5
 @cindex security context
Kamil Dudka 3bf1e5
 This option functions similarly to the @command{restorecon} command,
Kamil Dudka 3bf1e5
 by adjusting the SELinux security context according
Kamil Dudka 3bf1e5
-to the system default type for destination files.
Kamil Dudka 3bf1e5
+to the system default type for destination files and each created directory.
Kamil Dudka 3bf1e5
 
Kamil Dudka 3bf1e5
 @end table
Kamil Dudka 3bf1e5
 
Kamil Dudka 3bf1e5
diff --git a/src/install.c b/src/install.c
Kamil Dudka 3bf1e5
index 089f298..1b7a209 100644
Kamil Dudka 3bf1e5
--- a/src/install.c
Kamil Dudka 3bf1e5
+++ b/src/install.c
Kamil Dudka 3bf1e5
@@ -39,6 +39,7 @@
Kamil Dudka 3bf1e5
 #include "prog-fprintf.h"
Kamil Dudka 3bf1e5
 #include "quote.h"
Kamil Dudka 3bf1e5
 #include "savewd.h"
Kamil Dudka 3bf1e5
+#include "selinux.h"
Kamil Dudka 3bf1e5
 #include "stat-time.h"
Kamil Dudka 3bf1e5
 #include "utimens.h"
Kamil Dudka 3bf1e5
 #include "xstrtol.h"
Kamil Dudka 3bf1e5
@@ -423,6 +424,12 @@ announce_mkdir (char const *dir, void *options)
Kamil Dudka 3bf1e5
 static int
Kamil Dudka 3bf1e5
 make_ancestor (char const *dir, char const *component, void *options)
Kamil Dudka 3bf1e5
 {
Kamil Dudka 3bf1e5
+  struct cp_options const *x = options;
Kamil Dudka 3bf1e5
+  if (x->set_security_context && defaultcon (dir, S_IFDIR) < 0
Kamil Dudka 3bf1e5
+      && ! ignorable_ctx_err (errno))
Kamil Dudka 3bf1e5
+    error (0, errno, _("failed to set default creation context for %s"),
Kamil Dudka 3bf1e5
+           quoteaf (dir));
Kamil Dudka 3bf1e5
+
Kamil Dudka 3bf1e5
   int r = mkdir (component, DEFAULT_MODE);
Kamil Dudka 3bf1e5
   if (r == 0)
Kamil Dudka 3bf1e5
     announce_mkdir (dir, options);
Kamil Dudka 3bf1e5
@@ -433,12 +440,28 @@ make_ancestor (char const *dir, char const *component, void *options)
Kamil Dudka 3bf1e5
 static int
Kamil Dudka 3bf1e5
 process_dir (char *dir, struct savewd *wd, void *options)
Kamil Dudka 3bf1e5
 {
Kamil Dudka 3bf1e5
-  return (make_dir_parents (dir, wd,
Kamil Dudka 3bf1e5
-                            make_ancestor, options,
Kamil Dudka 3bf1e5
-                            dir_mode, announce_mkdir,
Kamil Dudka 3bf1e5
-                            dir_mode_bits, owner_id, group_id, false)
Kamil Dudka 3bf1e5
+  struct cp_options const *x = options;
Kamil Dudka 3bf1e5
+
Kamil Dudka 3bf1e5
+  int ret = (make_dir_parents (dir, wd, make_ancestor, options,
Kamil Dudka 3bf1e5
+                               dir_mode, announce_mkdir,
Kamil Dudka 3bf1e5
+                               dir_mode_bits, owner_id, group_id, false)
Kamil Dudka 3bf1e5
           ? EXIT_SUCCESS
Kamil Dudka 3bf1e5
           : EXIT_FAILURE);
Kamil Dudka 3bf1e5
+
Kamil Dudka 3bf1e5
+  /* FIXME: Due to the current structure of make_dir_parents()
Kamil Dudka 3bf1e5
+     we don't have the facility to call defaultcon() before the
Kamil Dudka 3bf1e5
+     final component of DIR is created.  So for now, create the
Kamil Dudka 3bf1e5
+     final component with the context from previous component
Kamil Dudka 3bf1e5
+     and here we set the context for the final component. */
Kamil Dudka 3bf1e5
+  if (ret == EXIT_SUCCESS && x->set_security_context)
Kamil Dudka 3bf1e5
+    {
Kamil Dudka 3bf1e5
+      if (! restorecon (last_component (dir), false, false)
Kamil Dudka 3bf1e5
+          && ! ignorable_ctx_err (errno))
Kamil Dudka 3bf1e5
+        error (0, errno, _("failed to restore context for %s"),
Kamil Dudka 3bf1e5
+               quoteaf (dir));
Kamil Dudka 3bf1e5
+    }
Kamil Dudka 3bf1e5
+
Kamil Dudka 3bf1e5
+  return ret;
Kamil Dudka 3bf1e5
 }
Kamil Dudka 3bf1e5
 
Kamil Dudka 3bf1e5
 /* Copy file FROM onto file TO, creating TO if necessary.
Kamil Dudka 3bf1e5
@@ -651,7 +674,7 @@ In the 4th form, create all components of the given DIRECTORY(ies).\n\
Kamil Dudka 3bf1e5
       fputs (_("\
Kamil Dudka 3bf1e5
   -P, --preserve-context  preserve SELinux security context (-P deprecated)\n\
Kamil Dudka 3bf1e5
   -Z                      set SELinux security context of destination\n\
Kamil Dudka 3bf1e5
-                            file to default type\n\
Kamil Dudka 3bf1e5
+                            file and each created directory to default type\n\
Kamil Dudka 3bf1e5
       --context[=CTX]     like -Z, or if CTX is specified then set the\n\
Kamil Dudka 3bf1e5
                             SELinux or SMACK security context to CTX\n\
Kamil Dudka 3bf1e5
 "), stdout);
Kamil Dudka 3bf1e5
diff --git a/tests/install/install-Z-selinux.sh b/tests/install/install-Z-selinux.sh
Kamil Dudka 3bf1e5
new file mode 100644
Kamil Dudka 3bf1e5
index 0000000..9c3b642
Kamil Dudka 3bf1e5
--- /dev/null
Kamil Dudka 3bf1e5
+++ b/tests/install/install-Z-selinux.sh
Kamil Dudka 3bf1e5
@@ -0,0 +1,58 @@
Kamil Dudka 3bf1e5
+#!/bin/sh
Kamil Dudka 3bf1e5
+# test 'install -Z -D' and 'install -Z -d'
Kamil Dudka 3bf1e5
+# based on tests/mkdir/restorecon.sh
Kamil Dudka 3bf1e5
+
Kamil Dudka 3bf1e5
+# Copyright (C) 2013-2016 Free Software Foundation, Inc.
Kamil Dudka 3bf1e5
+
Kamil Dudka 3bf1e5
+# This program is free software: you can redistribute it and/or modify
Kamil Dudka 3bf1e5
+# it under the terms of the GNU General Public License as published by
Kamil Dudka 3bf1e5
+# the Free Software Foundation, either version 3 of the License, or
Kamil Dudka 3bf1e5
+# (at your option) any later version.
Kamil Dudka 3bf1e5
+
Kamil Dudka 3bf1e5
+# This program is distributed in the hope that it will be useful,
Kamil Dudka 3bf1e5
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
Kamil Dudka 3bf1e5
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Kamil Dudka 3bf1e5
+# GNU General Public License for more details.
Kamil Dudka 3bf1e5
+
Kamil Dudka 3bf1e5
+# You should have received a copy of the GNU General Public License
Kamil Dudka 3bf1e5
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
Kamil Dudka 3bf1e5
+
Kamil Dudka 3bf1e5
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
Kamil Dudka 3bf1e5
+print_ver_ ginstall
Kamil Dudka 3bf1e5
+require_selinux_
Kamil Dudka 3bf1e5
+
Kamil Dudka 3bf1e5
+
Kamil Dudka 3bf1e5
+get_selinux_type() { ls -Zd "$1" | sed -n 's/.*:\(.*_t\):.*/\1/p'; }
Kamil Dudka 3bf1e5
+
Kamil Dudka 3bf1e5
+mkdir subdir || framework_failure_
Kamil Dudka 3bf1e5
+chcon 'root:object_r:tmp_t:s0' subdir || framework_failure_
Kamil Dudka 3bf1e5
+cd subdir
Kamil Dudka 3bf1e5
+
Kamil Dudka 3bf1e5
+# Since in a tmp_t dir, dirs can be created as user_tmp_t ...
Kamil Dudka 3bf1e5
+touch standard || framework_failure_
Kamil Dudka 3bf1e5
+mkdir restored || framework_failure_
Kamil Dudka 3bf1e5
+if restorecon restored 2>/dev/null; then
Kamil Dudka 3bf1e5
+  # ... but when restored can be set to user_home_t
Kamil Dudka 3bf1e5
+  # So ensure the type for these mkdir -Z cases matches
Kamil Dudka 3bf1e5
+  # the directory type as set by restorecon.
Kamil Dudka 3bf1e5
+  ginstall -Z standard single || fail=1
Kamil Dudka 3bf1e5
+  ginstall -Z -d single_d || fail=1
Kamil Dudka 3bf1e5
+  # Run these as separate processes in case global context
Kamil Dudka 3bf1e5
+  # set for an arg, impacts on another arg
Kamil Dudka 3bf1e5
+  # TODO: Have the defaultcon() vary over these directories
Kamil Dudka 3bf1e5
+  for dst in single_d/existing/file multi/ple/file; do
Kamil Dudka 3bf1e5
+    ginstall -Z -D standard "$dst" || fail=1
Kamil Dudka 3bf1e5
+  done
Kamil Dudka 3bf1e5
+  restored_type=$(get_selinux_type 'restored')
Kamil Dudka 3bf1e5
+  test "$(get_selinux_type 'single')" = "$restored_type" || fail=1
Kamil Dudka 3bf1e5
+  test "$(get_selinux_type 'single_d')" = "$restored_type" || fail=1
Kamil Dudka 3bf1e5
+  test "$(get_selinux_type 'single_d/existing')" = "$restored_type" || fail=1
Kamil Dudka 3bf1e5
+  test "$(get_selinux_type 'multi')" = "$restored_type" || fail=1
Kamil Dudka 3bf1e5
+  test "$(get_selinux_type 'multi/ple')" = "$restored_type" || fail=1
Kamil Dudka 3bf1e5
+fi
Kamil Dudka 3bf1e5
+if test "$fail" = '1'; then
Kamil Dudka 3bf1e5
+  ls -UZd standard restored
Kamil Dudka 3bf1e5
+  ls -UZd single single_d single_d/existing multi multi/ple
Kamil Dudka 3bf1e5
+fi
Kamil Dudka 3bf1e5
+
Kamil Dudka 3bf1e5
+Exit $fail
Kamil Dudka 3bf1e5
diff --git a/tests/local.mk b/tests/local.mk
Kamil Dudka 3bf1e5
index ec23448..42d39f2 100644
Kamil Dudka 3bf1e5
--- a/tests/local.mk
Kamil Dudka 3bf1e5
+++ b/tests/local.mk
Kamil Dudka 3bf1e5
@@ -548,6 +548,7 @@ all_tests =					\
Kamil Dudka 3bf1e5
   tests/install/d-slashdot.sh			\
Kamil Dudka 3bf1e5
   tests/install/install-C.sh			\
Kamil Dudka 3bf1e5
   tests/install/install-C-selinux.sh		\
Kamil Dudka 3bf1e5
+  tests/install/install-Z-selinux.sh		\
Kamil Dudka 3bf1e5
   tests/install/strip-program.sh		\
Kamil Dudka 3bf1e5
   tests/install/trap.sh				\
Kamil Dudka 3bf1e5
   tests/ln/backup-1.sh				\
Kamil Dudka 3bf1e5
-- 
Kamil Dudka 3bf1e5
2.5.5
Kamil Dudka 3bf1e5