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

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