Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

deploy: Try to rebuild policy in new deployment if needed #2569

Merged
merged 2 commits into from
Mar 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ci/gh-install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ case "$ID" in
automake
bison
build-essential
bubblewrap
ca-certificates
cpio
debhelper
Expand Down
120 changes: 120 additions & 0 deletions src/libostree/ostree-sysroot-deploy.c
Original file line number Diff line number Diff line change
Expand Up @@ -2830,6 +2830,121 @@ 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",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One messy thing is this is distribution-specific. Looks like there's some bits related to this here too https://github.com/flatpak/flatpak/blob/aac1205d66e03facc965279d5825272597b305d0/common/flatpak-run.c#L77

I think it's OK for now, but we will likely need to be updating this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coming in to this late, but why not do an --ro-bind of . to / followed by the writable binds for /usr, /etc and /var? Presumably the usr-merge symlinks are already setup properly in the deployment.

"--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 glnx_prefix_error (error, "failed to run semodule");
if (!strstr(stdout, "--rebuild-if-modules-changed"))
{
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"
};
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,
Expand Down Expand Up @@ -2866,6 +2981,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))
Expand Down