repo: Add an option to label /usr/etc as /etc
authorColin Walters <walters@verbum.org>
Mon, 2 Oct 2023 15:05:31 +0000 (11:05 -0400)
committerColin Walters <walters@verbum.org>
Wed, 11 Oct 2023 17:25:08 +0000 (13:25 -0400)
This will be very useful for enabling a "transient /etc" option
because we won't have to do hacks relabling in the initramfs, or
forcing it on just for composefs.

man/ostree-commit.xml
src/libostree/ostree-repo-commit.c
src/libostree/ostree-repo.h
src/ostree/ot-builtin-commit.c
tests/kolainst/destructive/itest-label-selinux.sh

index 3e22b1723fdd3ecfaf948f6a81e7a0bb58708041..12f4fd10fac6e514918a6a142fbe425cc17e397d 100644 (file)
@@ -184,6 +184,14 @@ License along with this library. If not, see <https://www.gnu.org/licenses/>.
                 </para></listitem>
             </varlistentry>
 
+            <varlistentry>
+                <term><option>--selinux-labeling-epoch</option>0 | 1</term>
+
+                <listitem><para>
+                    When SELinux labeling is enabled, epoch <literal>1</literal> ensures that <literal>/usr/etc</literal> is labeled as if it was <literal>/etc</literal>.
+                </para></listitem>
+            </varlistentry>
+
             <varlistentry>
                 <term><option>--bootable</option></term>
                 <listitem><para>
index c269142e727c6801a0aa846f6b7875b0c0165bc0..d9fbb25104ec489cc4df3e2c3f08481d0e16370a 100644 (file)
@@ -28,6 +28,7 @@
 #include <gio/gunixoutputstream.h>
 #include <glib-unix.h>
 #include <glib/gprintf.h>
+#include <stdbool.h>
 #include <sys/ioctl.h>
 #include <sys/statvfs.h>
 #include <sys/xattr.h>
@@ -3272,8 +3273,14 @@ get_final_xattrs (OstreeRepo *self, OstreeRepoCommitModifier *modifier, const ch
   if (modifier && modifier->sepolicy)
     {
       g_autofree char *label = NULL;
+      const char *path_for_labeling = relpath;
 
-      if (!ostree_sepolicy_get_label (modifier->sepolicy, relpath,
+      bool using_v1 = (modifier->flags & OSTREE_REPO_COMMIT_MODIFIER_FLAGS_SELINUX_LABEL_V1) > 0;
+      bool is_usretc = g_str_equal (relpath, "/usr/etc") || g_str_has_prefix (relpath, "/usr/etc/");
+      if (using_v1 && is_usretc)
+        path_for_labeling += strlen ("/usr");
+
+      if (!ostree_sepolicy_get_label (modifier->sepolicy, path_for_labeling,
                                       g_file_info_get_attribute_uint32 (file_info, "unix::mode"),
                                       &label, cancellable, error))
         return FALSE;
index 2dea9092230a97685e709b7f89c3992ba4920ec5..73e62f5cd7d8285ce9a0324cd849639bee7c2a6f 100644 (file)
@@ -517,6 +517,8 @@ typedef OstreeRepoCommitFilterResult (*OstreeRepoCommitFilter) (OstreeRepo *repo
  * 2017.13
  * @OSTREE_REPO_COMMIT_MODIFIER_FLAGS_DEVINO_CANONICAL: If a devino cache hit is found, skip
  * modifier filters (non-directories only); Since: 2017.14
+ * @OSTREE_REPO_COMMIT_MODIFIER_FLAGS_SELINUX_LABEL_V1: For SELinux and other systems, label
+ * /usr/etc as if it was /etc.
  *
  * Flags modifying commit behavior. In bare-user-only mode,
  * @OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CANONICAL_PERMISSIONS and
@@ -532,6 +534,7 @@ typedef enum
   OSTREE_REPO_COMMIT_MODIFIER_FLAGS_ERROR_ON_UNLABELED = (1 << 3),
   OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CONSUME = (1 << 4),
   OSTREE_REPO_COMMIT_MODIFIER_FLAGS_DEVINO_CANONICAL = (1 << 5),
+  OSTREE_REPO_COMMIT_MODIFIER_FLAGS_SELINUX_LABEL_V1 = (1 << 6),
 } OstreeRepoCommitModifierFlags;
 
 /**
index 98aa5f952ab969df302fcc6453c15a67b1817b23..0309e73f2a801e237d721adeafd30721fbb821ae 100644 (file)
@@ -54,6 +54,7 @@ static char *opt_tar_pathname_filter;
 static gboolean opt_no_xattrs;
 static char *opt_selinux_policy;
 static gboolean opt_selinux_policy_from_base;
+static int opt_selinux_labeling_epoch;
 static gboolean opt_canonical_permissions;
 static gboolean opt_ro_executables;
 static gboolean opt_consume;
@@ -134,6 +135,10 @@ static GOptionEntry options[] = {
     "Set SELinux labels based on policy in root filesystem PATH (may be /)", "PATH" },
   { "selinux-policy-from-base", 'P', 0, G_OPTION_ARG_NONE, &opt_selinux_policy_from_base,
     "Set SELinux labels based on first --tree argument", NULL },
+  { "selinux-labeling-epoch", 0, 0, G_OPTION_ARG_INT, &opt_selinux_labeling_epoch,
+    "Configure the default SELinux labeling rules; 0 is the default, 1 enables labeling /usr/etc "
+    "as /etc",
+    NULL },
   { "link-checkout-speedup", 0, 0, G_OPTION_ARG_NONE, &opt_link_checkout_speedup,
     "Optimize for commits of trees composed of hardlinks into the repository", NULL },
   { "devino-canonical", 'I', 0, G_OPTION_ARG_NONE, &opt_devino_canonical,
@@ -597,6 +602,19 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio
     flags |= OSTREE_REPO_COMMIT_MODIFIER_FLAGS_SKIP_XATTRS;
   if (opt_consume)
     flags |= OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CONSUME;
+  switch (opt_selinux_labeling_epoch)
+    {
+    case 0:
+      break;
+    case 1:
+      flags |= OSTREE_REPO_COMMIT_MODIFIER_FLAGS_SELINUX_LABEL_V1;
+      break;
+    default:
+      {
+        glnx_throw (error, "Unknown SELinux labeling epoch: %d", opt_selinux_labeling_epoch);
+        goto out;
+      }
+    }
   if (opt_devino_canonical)
     {
       opt_link_checkout_speedup = TRUE; /* Imply this */
index 97b5cc5426a73ccc3d0e8313c5b21751fd3c9f33..29444fbc8dd681b010660421726d51514489aac4 100755 (executable)
@@ -32,6 +32,21 @@ ostree refs --delete testbranch
 rm co -rf
 echo "ok commit with sepolicy"
 
+ostree ls -X ${host_refspec} /usr/etc/sysctl.conf > ls.txt
+if grep -qF ':etc_t:' ls.txt; then
+  ostree checkout -H ${host_refspec} co
+  ostree commit -b testbranch --link-checkout-speedup \
+       --selinux-policy co --tree=dir=co --selinux-labeling-epoch=1
+  ostree ls -X testbranch /usr/etc/sysctl.conf > ls.txt
+  assert_file_has_content ls.txt ':system_conf_t:'
+  rm co ls.txt -rf
+  ostree refs --delete testbranch
+else
+  echo 'Already using --selinux-labeling-epoch > 0 on host, hopefully!'
+fi
+
+echo "ok --selinux-labeling-epoch=1"
+
 # Now let's check that selinux policy labels can be applied on checkout
 
 rm rootfs -rf