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