148 lines
5.3 KiB
Diff
148 lines
5.3 KiB
Diff
From 3ad4e6c72bb5b25745252da4fd1cab6e00827f72 Mon Sep 17 00:00:00 2001
|
|
From: Colin Walters <walters@verbum.org>
|
|
Date: Mon, 15 Aug 2016 11:58:03 -0400
|
|
Subject: [PATCH] bwrap/compose: Add a workaround for Fedora's use of
|
|
rpm-ostree-in-mock
|
|
|
|
Decided to test this on Sunday evening. Of course it was broken =(
|
|
(Actually I tested mock-in-Docker but it should be the same)
|
|
|
|
The core problem is that mock does `chroot()` without using `/`
|
|
as a mount point. This breaks an assumption in bwrap that it is.
|
|
Now, in theory we could move this same logic down into bwrap to
|
|
work around this situation, but for now let's hack it here.
|
|
|
|
Mock is old, legacy container code that doesn't really do anything
|
|
in a modern way - in fact our goal should be to replace it
|
|
with a combination of rpm-ostree and bwrap. So carrying this
|
|
hack here to get us to that future should be OK for now.
|
|
|
|
Closes: #431
|
|
Approved by: jlebon
|
|
---
|
|
src/app/rpmostree-compose-builtin-tree.c | 4 ++
|
|
src/libpriv/rpmostree-bwrap.c | 81 ++++++++++++++++++++++++++++++++
|
|
src/libpriv/rpmostree-bwrap.h | 1 +
|
|
3 files changed, 86 insertions(+)
|
|
|
|
diff --git a/src/app/rpmostree-compose-builtin-tree.c b/src/app/rpmostree-compose-builtin-tree.c
|
|
index 5ea1cbe..e49c5e4 100644
|
|
--- a/src/app/rpmostree-compose-builtin-tree.c
|
|
+++ b/src/app/rpmostree-compose-builtin-tree.c
|
|
@@ -630,6 +630,10 @@ rpmostree_compose_builtin_tree (int argc,
|
|
"compose tree must presently be run as uid 0 (root)");
|
|
goto out;
|
|
}
|
|
+
|
|
+ /* Mock->bwrap bootstrap for Fedora */
|
|
+ if (!rpmostree_bwrap_bootstrap_if_in_mock (error))
|
|
+ goto out;
|
|
/* Test whether or not bwrap is going to work - we will fail inside e.g. a Docker
|
|
* container without --privileged or userns exposed.
|
|
*/
|
|
diff --git a/src/libpriv/rpmostree-bwrap.c b/src/libpriv/rpmostree-bwrap.c
|
|
index bd7c793..85e7837 100644
|
|
--- a/src/libpriv/rpmostree-bwrap.c
|
|
+++ b/src/libpriv/rpmostree-bwrap.c
|
|
@@ -108,6 +108,87 @@ rpmostree_run_sync_fchdir_setup (char **argv_array, GSpawnFlags flags,
|
|
return TRUE;
|
|
}
|
|
|
|
+/* mock doesn't actually use a mount namespace, and hence bwrap will
|
|
+ * fail to remount /. Work around this by doing it here. Fedora
|
|
+ * runs rpm-ostree inside of mock instead of Docker or something
|
|
+ * more modern.
|
|
+ */
|
|
+gboolean
|
|
+rpmostree_bwrap_bootstrap_if_in_mock (GError **error)
|
|
+{
|
|
+ const char *env_ps1 = getenv ("PS1");
|
|
+ static const char *mock_mounted_paths[] = { "/proc", "/sys" };
|
|
+ static const char *findmnt_argv[] = { "findmnt", "/", NULL };
|
|
+ g_autofree char *pwd = NULL;
|
|
+ int estatus;
|
|
+
|
|
+ if (!(env_ps1 && strstr (env_ps1, "<mock-chroot>")))
|
|
+ return TRUE;
|
|
+
|
|
+ /* Okay, we detected we're inside mock. Let's double check now
|
|
+ * whether or not / is already a mount point. The simplest way to
|
|
+ * do this is to execute findmnt...maybe someday we'll link to libmount
|
|
+ * but this is legacy.
|
|
+ */
|
|
+ if (!g_spawn_sync (NULL, (char**)findmnt_argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
|
|
+ NULL, NULL, &estatus, error))
|
|
+ {
|
|
+ g_prefix_error (error, "Executing findmnt: ");
|
|
+ return FALSE;
|
|
+ }
|
|
+ /* Did findmnt say / is a mount point? Okay, nothing to do here. */
|
|
+ if (estatus == 0)
|
|
+ return TRUE;
|
|
+
|
|
+ pwd = getcwd (NULL, 0);
|
|
+
|
|
+ g_print ("Detected mock chroot without / as mount, enabling workaround.\n");
|
|
+ if (unshare (CLONE_NEWNS) < 0)
|
|
+ {
|
|
+ glnx_set_prefix_error_from_errno (error, "%s", "unshare(CLONE_NEWNS)");
|
|
+ return FALSE;
|
|
+ }
|
|
+ /* For reasons I don't fully understand, trying to bind mount / -> /
|
|
+ * doesn't work. We seem to hit a check in the kernel:
|
|
+ *
|
|
+ * static int do_change_type(struct path *path, int flag)
|
|
+ * {
|
|
+ * ...
|
|
+ * if (path->dentry != path->mnt->mnt_root)
|
|
+ * return -EINVAL;
|
|
+ */
|
|
+ if (mount ("/", "/mnt", NULL, MS_MGC_VAL | MS_BIND, NULL) != 0)
|
|
+ {
|
|
+ glnx_set_prefix_error_from_errno (error, "%s", "mount(/ as bind)");
|
|
+ return FALSE;
|
|
+ }
|
|
+ /* Now take the paths that mock mounted (that we need) and move them
|
|
+ * underneath the new rootfs mount.
|
|
+ */
|
|
+ for (guint i = 0; i < G_N_ELEMENTS (mock_mounted_paths); i++)
|
|
+ {
|
|
+ const char *mockpath = mock_mounted_paths[i];
|
|
+ g_autofree char *destpath = g_strconcat ("/mnt", mockpath, NULL);
|
|
+ if (mount (mockpath, destpath, NULL, MS_MGC_VAL | MS_MOVE, NULL) != 0)
|
|
+ {
|
|
+ glnx_set_prefix_error_from_errno (error, "%s", "mount(move)");
|
|
+ return FALSE;
|
|
+ }
|
|
+ }
|
|
+ if (chroot ("/mnt") < 0)
|
|
+ {
|
|
+ glnx_set_error_from_errno (error);
|
|
+ return FALSE;
|
|
+ }
|
|
+ if (chdir (pwd) < 0)
|
|
+ {
|
|
+ glnx_set_error_from_errno (error);
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
/* Execute /bin/true inside a bwrap container on the host */
|
|
gboolean
|
|
rpmostree_bwrap_selftest (GError **error)
|
|
diff --git a/src/libpriv/rpmostree-bwrap.h b/src/libpriv/rpmostree-bwrap.h
|
|
index b4bb88c..b464355 100644
|
|
--- a/src/libpriv/rpmostree-bwrap.h
|
|
+++ b/src/libpriv/rpmostree-bwrap.h
|
|
@@ -31,4 +31,5 @@ void rpmostree_ptrarray_append_strdup (GPtrArray *argv_array, ...) G_GNUC_NULL_T
|
|
gboolean rpmostree_run_sync_fchdir_setup (char **argv_array, GSpawnFlags flags,
|
|
int rootfs_fd, GError **error);
|
|
|
|
+gboolean rpmostree_bwrap_bootstrap_if_in_mock (GError **error);
|
|
gboolean rpmostree_bwrap_selftest (GError **error);
|
|
--
|
|
2.7.4
|
|
|