diff --git a/ci/gh-install.sh b/ci/gh-install.sh index f39331b1..c2928665 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 b7cc232f..3f301891 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))