From edb4f3893474736156c654aa43bdbf3784991811 Mon Sep 17 00:00:00 2001 From: Ondrej Mosnacek Date: Wed, 9 Mar 2022 15:27:11 +0100 Subject: [PATCH 1/2] 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 --- ci/gh-install.sh | 1 + src/libostree/ostree-sysroot-deploy.c | 117 ++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) diff --git a/ci/gh-install.sh b/ci/gh-install.sh index f39331b140..c2928665bc 100755 --- a/ci/gh-install.sh +++ b/ci/gh-install.sh @@ -69,6 +69,7 @@ case "$ID" in automake bison build-essential + bubblewrap ca-certificates cpio debhelper diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c index b7cc232f46..3f301891a5 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)) From c58a4fe661d9d3bf2c515aa5605b1e094c0a62ca Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Mon, 28 Mar 2022 17:46:59 -0400 Subject: [PATCH 2/2] deploy: Be a bit more verbose about SELinux bits Let's log when we don't find the expected CLI argument which will help debug things. --- src/libostree/ostree-sysroot-deploy.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c index 3f301891a5..5219e2a4f9 100644 --- a/src/libostree/ostree-sysroot-deploy.c +++ b/src/libostree/ostree-sysroot-deploy.c @@ -2926,9 +2926,12 @@ sysroot_finalize_selinux_policy (int deployment_dfd, GError **error) SEMODULE_HELP_ARGC, &exit_status, &stdout, error)) return FALSE; if (!g_spawn_check_exit_status (exit_status, error)) - return FALSE; + return glnx_prefix_error (error, "failed to run semodule"); if (!strstr(stdout, "--rebuild-if-modules-changed")) - return TRUE; + { + ot_journal_print (LOG_INFO, "semodule does not have --rebuild-if-modules-changed"); + return TRUE; + } static const gchar * const SEMODULE_REBUILD_ARGV[] = { "semodule", "-N", "--rebuild-if-modules-changed"