Blame SOURCES/0005-deploy-Try-to-rebuild-policy-in-new-deployment-if-ne.patch

a98e04
From 62e62bcfd8a1770b906faed083d11e451a50f566 Mon Sep 17 00:00:00 2001
a98e04
From: Ondrej Mosnacek <omosnace@redhat.com>
a98e04
Date: Wed, 9 Mar 2022 15:27:11 +0100
a98e04
Subject: [PATCH 5/6] deploy: Try to rebuild policy in new deployment if needed
a98e04
a98e04
Whenever the user has SELinux enabled and has any local
a98e04
modules/modifications installed, it is necessary to rebuild the policy
a98e04
in the final deployment, otherwise ostree will leave the binary policy
a98e04
files unchanged from last deployment as it detects difference against
a98e04
the base content (in rpm-ostree case this is the RPM content).
a98e04
a98e04
To avoid the situation where the policy binaries go stale once any local
a98e04
customization of the policy is made, try to rebuild the policy as part
a98e04
of sysroot_finalize_deployment(). Use the special
a98e04
--rebuild-if-modules-changed switch, which detects if the input module
a98e04
files have changed relative to last time the policy was built and skips
a98e04
the most time-consuming part of the rebuild process if modules are
a98e04
unchanged (thus making this a relatively cheap operation if the user
a98e04
hasn't made any modifications to the shipped policy).
a98e04
a98e04
As suggested by Jonathan Lebon, this uses bubblewrap (via
a98e04
g_spawn_sync()) to perform the rebuild inside the deployment's
a98e04
filesystem tree, which also means that ostree will have a runtime
a98e04
dependency on bubblewrap.
a98e04
a98e04
Partially addresses: https://github.com/coreos/fedora-coreos-tracker/issues/701
a98e04
a98e04
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
a98e04
(cherry picked from commit edb4f3893474736156c654aa43bdbf3784991811)
a98e04
---
a98e04
 ci/gh-install.sh                      |   1 +
a98e04
 src/libostree/ostree-sysroot-deploy.c | 117 ++++++++++++++++++++++++++
a98e04
 2 files changed, 118 insertions(+)
a98e04
a98e04
diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c
a98e04
index fc5916d8..a44721d8 100644
a98e04
--- a/src/libostree/ostree-sysroot-deploy.c
a98e04
+++ b/src/libostree/ostree-sysroot-deploy.c
a98e04
@@ -2830,6 +2830,118 @@ get_var_dfd (OstreeSysroot      *self,
a98e04
   return glnx_opendirat (base_dfd, base_path, TRUE, ret_fd, error);
a98e04
 }
a98e04
 
a98e04
+#ifdef HAVE_SELINUX
a98e04
+static void
a98e04
+child_setup_fchdir (gpointer data)
a98e04
+{
a98e04
+  int fd = (int) (uintptr_t) data;
a98e04
+  int rc __attribute__((unused));
a98e04
+
a98e04
+  rc = fchdir (fd);
a98e04
+}
a98e04
+
a98e04
+/*
a98e04
+ * Derived from rpm-ostree's rust/src/bwrap.rs
a98e04
+ */
a98e04
+static gboolean
a98e04
+run_in_deployment (int deployment_dfd,
a98e04
+                   const gchar * const *child_argv,
a98e04
+                   gsize child_argc,
a98e04
+                   gint *exit_status,
a98e04
+                   gchar **stdout,
a98e04
+                   GError **error)
a98e04
+{
a98e04
+  static const gchar * const COMMON_ARGV[] = {
a98e04
+    "/usr/bin/bwrap",
a98e04
+    "--dev", "/dev", "--proc", "/proc", "--dir", "/run", "--dir", "/tmp",
a98e04
+    "--chdir", "/",
a98e04
+    "--die-with-parent",
a98e04
+    "--unshare-pid",
a98e04
+    "--unshare-uts",
a98e04
+    "--unshare-ipc",
a98e04
+    "--unshare-cgroup-try",
a98e04
+    "--ro-bind", "/sys/block",    "/sys/block",
a98e04
+    "--ro-bind", "/sys/bus",      "/sys/bus",
a98e04
+    "--ro-bind", "/sys/class",    "/sys/class",
a98e04
+    "--ro-bind", "/sys/dev",      "/sys/dev",
a98e04
+    "--ro-bind", "/sys/devices",  "/sys/devices",
a98e04
+    "--bind", "usr", "/usr",
a98e04
+    "--bind", "etc", "/etc",
a98e04
+    "--bind", "var", "/var",
a98e04
+    "--symlink", "/usr/lib",      "/lib",
a98e04
+    "--symlink", "/usr/lib32",    "/lib32",
a98e04
+    "--symlink", "/usr/lib64",    "/lib64",
a98e04
+    "--symlink", "/usr/bin",      "/bin",
a98e04
+    "--symlink", "/usr/sbin",     "/sbin",
a98e04
+  };
a98e04
+  static const gsize COMMON_ARGC = sizeof (COMMON_ARGV) / sizeof (*COMMON_ARGV);
a98e04
+
a98e04
+  gsize i;
a98e04
+  GPtrArray *args = g_ptr_array_sized_new (COMMON_ARGC + child_argc + 1);
a98e04
+  g_autofree gchar **args_raw = NULL;
a98e04
+
a98e04
+  for (i = 0; i < COMMON_ARGC; i++)
a98e04
+    g_ptr_array_add (args, (gchar *) COMMON_ARGV[i]);
a98e04
+
a98e04
+  for (i = 0; i < child_argc; i++)
a98e04
+    g_ptr_array_add (args, (gchar *) child_argv[i]);
a98e04
+
a98e04
+  g_ptr_array_add (args, NULL);
a98e04
+
a98e04
+  args_raw = (gchar **) g_ptr_array_free (args, FALSE);
a98e04
+
a98e04
+  return g_spawn_sync (NULL, args_raw, NULL, 0, &child_setup_fchdir,
a98e04
+                       (gpointer) (uintptr_t) deployment_dfd,
a98e04
+                       stdout, NULL, exit_status, error);
a98e04
+}
a98e04
+
a98e04
+/*
a98e04
+ * Run semodule to check if the module content changed after merging /etc
a98e04
+ * and rebuild the policy if needed.
a98e04
+ */
a98e04
+static gboolean
a98e04
+sysroot_finalize_selinux_policy (int deployment_dfd, GError **error)
a98e04
+{
a98e04
+  struct stat stbuf;
a98e04
+  gint exit_status;
a98e04
+  g_autofree gchar *stdout = NULL;
a98e04
+
a98e04
+  if (!glnx_fstatat_allow_noent (deployment_dfd, "etc/selinux/config", &stbuf,
a98e04
+                                 AT_SYMLINK_NOFOLLOW, error))
a98e04
+    return FALSE;
a98e04
+
a98e04
+  /* Skip the SELinux policy refresh if /etc/selinux/config doesn't exist. */
a98e04
+  if (errno != 0)
a98e04
+    return TRUE;
a98e04
+
a98e04
+  /*
a98e04
+   * Skip the SELinux policy refresh if the --rebuild-if-modules-changed
a98e04
+   * flag is not supported by semodule.
a98e04
+   */
a98e04
+  static const gchar * const SEMODULE_HELP_ARGV[] = {
a98e04
+    "semodule", "--help"
a98e04
+  };
a98e04
+  static const gsize SEMODULE_HELP_ARGC = sizeof (SEMODULE_HELP_ARGV) / sizeof (*SEMODULE_HELP_ARGV);
a98e04
+  if (!run_in_deployment (deployment_dfd, SEMODULE_HELP_ARGV,
a98e04
+                          SEMODULE_HELP_ARGC, &exit_status, &stdout, error))
a98e04
+    return FALSE;
a98e04
+  if (!g_spawn_check_exit_status (exit_status, error))
a98e04
+    return FALSE;
a98e04
+  if (!strstr(stdout, "--rebuild-if-modules-changed"))
a98e04
+    return TRUE;
a98e04
+
a98e04
+  static const gchar * const SEMODULE_REBUILD_ARGV[] = {
a98e04
+    "semodule", "-N", "--rebuild-if-modules-changed"
a98e04
+  };
a98e04
+  static const gsize SEMODULE_REBUILD_ARGC = sizeof (SEMODULE_REBUILD_ARGV) / sizeof (*SEMODULE_REBUILD_ARGV);
a98e04
+
a98e04
+  if (!run_in_deployment (deployment_dfd, SEMODULE_REBUILD_ARGV,
a98e04
+                          SEMODULE_REBUILD_ARGC, &exit_status, NULL, error))
a98e04
+    return FALSE;
a98e04
+  return g_spawn_check_exit_status (exit_status, error);
a98e04
+}
a98e04
+#endif /* HAVE_SELINUX */
a98e04
+
a98e04
 static gboolean
a98e04
 sysroot_finalize_deployment (OstreeSysroot     *self,
a98e04
                              OstreeDeployment  *deployment,
a98e04
@@ -2866,6 +2978,11 @@ sysroot_finalize_deployment (OstreeSysroot     *self,
a98e04
         return FALSE;
a98e04
     }
a98e04
 
a98e04
+#ifdef HAVE_SELINUX
a98e04
+  if (!sysroot_finalize_selinux_policy(deployment_dfd, error))
a98e04
+    return FALSE;
a98e04
+#endif /* HAVE_SELINUX */
a98e04
+
a98e04
   const char *osdeploypath = glnx_strjoina ("ostree/deploy/", ostree_deployment_get_osname (deployment));
a98e04
   glnx_autofd int os_deploy_dfd = -1;
a98e04
   if (!glnx_opendirat (self->sysroot_fd, osdeploypath, TRUE, &os_deploy_dfd, error))
a98e04
-- 
a98e04
2.31.1
a98e04