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
This commit is contained in:
parent
09c5f9a4fe
commit
3ad4e6c72b
@ -630,6 +630,10 @@ rpmostree_compose_builtin_tree (int argc,
|
|||||||
"compose tree must presently be run as uid 0 (root)");
|
"compose tree must presently be run as uid 0 (root)");
|
||||||
goto out;
|
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
|
/* Test whether or not bwrap is going to work - we will fail inside e.g. a Docker
|
||||||
* container without --privileged or userns exposed.
|
* container without --privileged or userns exposed.
|
||||||
*/
|
*/
|
||||||
|
@ -108,6 +108,87 @@ rpmostree_run_sync_fchdir_setup (char **argv_array, GSpawnFlags flags,
|
|||||||
return TRUE;
|
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 */
|
/* Execute /bin/true inside a bwrap container on the host */
|
||||||
gboolean
|
gboolean
|
||||||
rpmostree_bwrap_selftest (GError **error)
|
rpmostree_bwrap_selftest (GError **error)
|
||||||
|
@ -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,
|
gboolean rpmostree_run_sync_fchdir_setup (char **argv_array, GSpawnFlags flags,
|
||||||
int rootfs_fd, GError **error);
|
int rootfs_fd, GError **error);
|
||||||
|
|
||||||
|
gboolean rpmostree_bwrap_bootstrap_if_in_mock (GError **error);
|
||||||
gboolean rpmostree_bwrap_selftest (GError **error);
|
gboolean rpmostree_bwrap_selftest (GError **error);
|
||||||
|
Loading…
Reference in New Issue
Block a user