libpriv: Enhance internal bwrap API
Make it a real struct with methods. This noticeably increases the ergonomics and design of the API. The main goal here is to introduce the enum which defines whether or not the rootfs is mutable or not. We move the "rofiles" mode from the RPM script code down into the bwrap layer, which will make it easier to reuse for treecompose. Closes: #560 Approved by: jlebon
This commit is contained in:
parent
50ab2983ab
commit
f0ec738376
@ -22,6 +22,8 @@
|
|||||||
#include "rpmostree-bwrap.h"
|
#include "rpmostree-bwrap.h"
|
||||||
|
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <systemd/sd-journal.h>
|
||||||
|
|
||||||
void
|
void
|
||||||
rpmostree_ptrarray_append_strdup (GPtrArray *argv_array, ...)
|
rpmostree_ptrarray_append_strdup (GPtrArray *argv_array, ...)
|
||||||
@ -35,13 +37,162 @@ rpmostree_ptrarray_append_strdup (GPtrArray *argv_array, ...)
|
|||||||
va_end (args);
|
va_end (args);
|
||||||
}
|
}
|
||||||
|
|
||||||
GPtrArray *
|
struct RpmOstreeBwrap {
|
||||||
rpmostree_bwrap_base_argv_new_for_rootfs (int rootfs_fd, GError **error)
|
guint refcount;
|
||||||
|
|
||||||
|
gboolean executed;
|
||||||
|
|
||||||
|
int rootfs_fd;
|
||||||
|
|
||||||
|
GPtrArray *argv;
|
||||||
|
const char *child_argv0;
|
||||||
|
char *rofiles_mnt;
|
||||||
|
|
||||||
|
GSpawnChildSetupFunc child_setup_func;
|
||||||
|
gpointer child_setup_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
RpmOstreeBwrap *
|
||||||
|
rpmostree_bwrap_ref (RpmOstreeBwrap *bwrap)
|
||||||
{
|
{
|
||||||
g_autoptr(GPtrArray) bwrap_argv = g_ptr_array_new_with_free_func (g_free);
|
bwrap->refcount++;
|
||||||
|
return bwrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rpmostree_bwrap_unref (RpmOstreeBwrap *bwrap)
|
||||||
|
{
|
||||||
|
bwrap->refcount--;
|
||||||
|
if (bwrap->refcount > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (bwrap->rofiles_mnt)
|
||||||
|
{
|
||||||
|
g_autoptr(GError) tmp_error = NULL;
|
||||||
|
const char *fusermount_argv[] = { "fusermount", "-u", bwrap->rofiles_mnt, NULL};
|
||||||
|
int estatus;
|
||||||
|
|
||||||
|
if (!g_spawn_sync (NULL, (char**)fusermount_argv, NULL, G_SPAWN_SEARCH_PATH,
|
||||||
|
NULL, NULL, NULL, NULL, &estatus, &tmp_error))
|
||||||
|
{
|
||||||
|
g_prefix_error (&tmp_error, "Executing fusermount: ");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (!g_spawn_check_exit_status (estatus, &tmp_error))
|
||||||
|
{
|
||||||
|
g_prefix_error (&tmp_error, "Executing fusermount: ");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) unlinkat (AT_FDCWD, bwrap->rofiles_mnt, AT_REMOVEDIR);
|
||||||
|
out:
|
||||||
|
/* We don't want a failure to unmount to be fatal, so all we do here
|
||||||
|
* is log. Though in practice what we *really* want is for the
|
||||||
|
* fusermount to be in the bwrap namespace, and hence tied by the
|
||||||
|
* kernel to the lifecycle of the container. This would require
|
||||||
|
* special casing for somehow doing FUSE mounts in bwrap. Which
|
||||||
|
* would be hard because NO_NEW_PRIVS turns off the setuid bits for
|
||||||
|
* fuse.
|
||||||
|
*/
|
||||||
|
if (tmp_error)
|
||||||
|
sd_journal_print (LOG_WARNING, "%s", tmp_error->message);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ptr_array_unref (bwrap->argv);
|
||||||
|
g_free (bwrap->rofiles_mnt);
|
||||||
|
g_free (bwrap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rpmostree_bwrap_append_bwrap_argv (RpmOstreeBwrap *bwrap, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
char *arg;
|
||||||
|
|
||||||
|
g_assert (!bwrap->executed);
|
||||||
|
|
||||||
|
va_start (args, bwrap);
|
||||||
|
while ((arg = va_arg (args, char *)))
|
||||||
|
g_ptr_array_add (bwrap->argv, g_strdup (arg));
|
||||||
|
va_end (args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rpmostree_bwrap_append_child_argv (RpmOstreeBwrap *bwrap, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
char *arg;
|
||||||
|
|
||||||
|
g_assert (!bwrap->executed);
|
||||||
|
|
||||||
|
va_start (args, bwrap);
|
||||||
|
while ((arg = va_arg (args, char *)))
|
||||||
|
{
|
||||||
|
char *v = g_strdup (arg);
|
||||||
|
g_ptr_array_add (bwrap->argv, v);
|
||||||
|
/* Stash argv0 for error messages */
|
||||||
|
if (!bwrap->child_argv0)
|
||||||
|
bwrap->child_argv0 = v;
|
||||||
|
}
|
||||||
|
va_end (args);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
child_setup_fchdir (gpointer user_data)
|
||||||
|
{
|
||||||
|
int fd = GPOINTER_TO_INT (user_data);
|
||||||
|
if (fchdir (fd) < 0)
|
||||||
|
err (1, "fchdir");
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
setup_rofiles_usr (RpmOstreeBwrap *bwrap,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
int estatus;
|
||||||
|
const char *rofiles_argv[] = { "rofiles-fuse", "./usr", NULL, NULL};
|
||||||
|
gboolean mntpoint_created = FALSE;
|
||||||
|
|
||||||
|
bwrap->rofiles_mnt = g_strdup ("/tmp/rofiles-fuse.XXXXXX");
|
||||||
|
rofiles_argv[2] = bwrap->rofiles_mnt;
|
||||||
|
|
||||||
|
if (!glnx_mkdtempat (AT_FDCWD, bwrap->rofiles_mnt, 0700, error))
|
||||||
|
goto out;
|
||||||
|
mntpoint_created = TRUE;
|
||||||
|
|
||||||
|
if (!g_spawn_sync (NULL, (char**)rofiles_argv, NULL, G_SPAWN_SEARCH_PATH,
|
||||||
|
child_setup_fchdir, GINT_TO_POINTER (bwrap->rootfs_fd),
|
||||||
|
NULL, NULL, &estatus, error))
|
||||||
|
goto out;
|
||||||
|
if (!g_spawn_check_exit_status (estatus, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
rpmostree_bwrap_append_bwrap_argv (bwrap, "--bind", bwrap->rofiles_mnt, "/usr", NULL);
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
out:
|
||||||
|
if (!ret && mntpoint_created)
|
||||||
|
(void) unlinkat (AT_FDCWD, bwrap->rofiles_mnt, AT_REMOVEDIR);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
RpmOstreeBwrap *
|
||||||
|
rpmostree_bwrap_new (int rootfs_fd,
|
||||||
|
RpmOstreeBwrapMutability mutable,
|
||||||
|
GError **error,
|
||||||
|
...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
RpmOstreeBwrap *retval = NULL;
|
||||||
|
g_autoptr(RpmOstreeBwrap) ret = g_new0 (RpmOstreeBwrap, 1);
|
||||||
static const char *usr_links[] = {"lib", "lib32", "lib64", "bin", "sbin"};
|
static const char *usr_links[] = {"lib", "lib32", "lib64", "bin", "sbin"};
|
||||||
|
|
||||||
rpmostree_ptrarray_append_strdup (bwrap_argv,
|
ret->refcount = 1;
|
||||||
|
ret->rootfs_fd = rootfs_fd;
|
||||||
|
ret->argv = g_ptr_array_new_with_free_func (g_free);
|
||||||
|
|
||||||
|
rpmostree_bwrap_append_bwrap_argv (ret,
|
||||||
WITH_BUBBLEWRAP_PATH,
|
WITH_BUBBLEWRAP_PATH,
|
||||||
"--dev", "/dev",
|
"--dev", "/dev",
|
||||||
"--proc", "/proc",
|
"--proc", "/proc",
|
||||||
@ -58,7 +209,8 @@ rpmostree_bwrap_base_argv_new_for_rootfs (int rootfs_fd, GError **error)
|
|||||||
{
|
{
|
||||||
const char *subdir = usr_links[i];
|
const char *subdir = usr_links[i];
|
||||||
struct stat stbuf;
|
struct stat stbuf;
|
||||||
char *path;
|
g_autofree char *srcpath = NULL;
|
||||||
|
g_autofree char *destpath = NULL;
|
||||||
|
|
||||||
if (fstatat (rootfs_fd, subdir, &stbuf, AT_SYMLINK_NOFOLLOW) < 0)
|
if (fstatat (rootfs_fd, subdir, &stbuf, AT_SYMLINK_NOFOLLOW) < 0)
|
||||||
{
|
{
|
||||||
@ -72,70 +224,68 @@ rpmostree_bwrap_base_argv_new_for_rootfs (int rootfs_fd, GError **error)
|
|||||||
else if (!S_ISLNK (stbuf.st_mode))
|
else if (!S_ISLNK (stbuf.st_mode))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
g_ptr_array_add (bwrap_argv, g_strdup ("--symlink"));
|
srcpath = g_strconcat ("usr/", subdir, NULL);
|
||||||
|
destpath = g_strconcat ("/", subdir, NULL);
|
||||||
path = g_strconcat ("usr/", subdir, NULL);
|
rpmostree_bwrap_append_bwrap_argv (ret, "--symlink", srcpath, destpath, NULL);
|
||||||
g_ptr_array_add (bwrap_argv, path);
|
|
||||||
|
|
||||||
path = g_strconcat ("/", subdir, NULL);
|
|
||||||
g_ptr_array_add (bwrap_argv, path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return g_steal_pointer (&bwrap_argv);
|
switch (mutable)
|
||||||
|
{
|
||||||
|
case RPMOSTREE_BWRAP_IMMUTABLE:
|
||||||
|
rpmostree_bwrap_append_bwrap_argv (ret, "--ro-bind", "usr", "/usr", NULL);
|
||||||
|
break;
|
||||||
|
case RPMOSTREE_BWRAP_MUTATE_ROFILES:
|
||||||
|
if (!setup_rofiles_usr (ret, error))
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
case RPMOSTREE_BWRAP_MUTATE_FREELY:
|
||||||
|
rpmostree_bwrap_append_bwrap_argv (ret, "--bind", "usr", "/usr", NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
{ const char *arg;
|
||||||
|
va_start (args, error);
|
||||||
|
while ((arg = va_arg (args, char *)))
|
||||||
|
g_ptr_array_add (ret->argv, g_strdup (arg));
|
||||||
|
va_end (args);
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = g_steal_pointer (&ret);
|
||||||
|
out:
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
child_setup_fchdir (gpointer user_data)
|
|
||||||
{
|
|
||||||
int fd = GPOINTER_TO_INT (user_data);
|
|
||||||
if (fchdir (fd) < 0)
|
|
||||||
err (1, "fchdir");
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
rpmostree_run_sync_fchdir_setup (char **argv_array, GSpawnFlags flags,
|
|
||||||
int rootfs_fd, GError **error)
|
|
||||||
{
|
|
||||||
int estatus;
|
|
||||||
|
|
||||||
if (!g_spawn_sync (NULL, argv_array, NULL, flags,
|
|
||||||
child_setup_fchdir, GINT_TO_POINTER (rootfs_fd),
|
|
||||||
NULL, NULL, &estatus, error))
|
|
||||||
return FALSE;
|
|
||||||
if (!g_spawn_check_exit_status (estatus, error))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int rootfs_fd;
|
|
||||||
GSpawnChildSetupFunc func;
|
|
||||||
gpointer data;
|
|
||||||
} ChildSetupData;
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
bwrap_child_setup (gpointer data)
|
bwrap_child_setup (gpointer data)
|
||||||
{
|
{
|
||||||
ChildSetupData *cdata = data;
|
RpmOstreeBwrap *bwrap = data;
|
||||||
|
|
||||||
if (fchdir (cdata->rootfs_fd) < 0)
|
if (fchdir (bwrap->rootfs_fd) < 0)
|
||||||
err (1, "fchdir");
|
err (1, "fchdir");
|
||||||
|
|
||||||
if (cdata->func)
|
if (bwrap->child_setup_func)
|
||||||
cdata->func (cdata->data);
|
bwrap->child_setup_func (bwrap->child_setup_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rpmostree_bwrap_set_child_setup (RpmOstreeBwrap *bwrap,
|
||||||
|
GSpawnChildSetupFunc func,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
g_assert (!bwrap->executed);
|
||||||
|
bwrap->child_setup_func = func;
|
||||||
|
bwrap->child_setup_data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
rpmostree_run_bwrap_sync_setup (char **argv_array,
|
rpmostree_bwrap_run (RpmOstreeBwrap *bwrap,
|
||||||
int rootfs_fd,
|
|
||||||
GSpawnChildSetupFunc func,
|
|
||||||
gpointer data,
|
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
int estatus;
|
int estatus;
|
||||||
const char *current_lang = getenv ("LANG");
|
const char *current_lang = getenv ("LANG");
|
||||||
ChildSetupData csetupdata = { rootfs_fd, func, data };
|
|
||||||
|
g_assert (!bwrap->executed);
|
||||||
|
bwrap->executed = TRUE;
|
||||||
|
|
||||||
if (!current_lang)
|
if (!current_lang)
|
||||||
current_lang = "C";
|
current_lang = "C";
|
||||||
@ -151,43 +301,43 @@ rpmostree_run_bwrap_sync_setup (char **argv_array,
|
|||||||
lang_var,
|
lang_var,
|
||||||
NULL};
|
NULL};
|
||||||
|
|
||||||
if (!g_spawn_sync (NULL, argv_array, (char**) bwrap_env, G_SPAWN_SEARCH_PATH,
|
/* Add the final NULL */
|
||||||
bwrap_child_setup, &csetupdata,
|
g_ptr_array_add (bwrap->argv, NULL);
|
||||||
|
|
||||||
|
if (!g_spawn_sync (NULL, (char**)bwrap->argv->pdata, (char**) bwrap_env, G_SPAWN_SEARCH_PATH,
|
||||||
|
bwrap_child_setup, bwrap,
|
||||||
NULL, NULL, &estatus, error))
|
NULL, NULL, &estatus, error))
|
||||||
|
{
|
||||||
|
g_prefix_error (error, "Executing bwrap(%s): ", bwrap->child_argv0);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
}
|
||||||
if (!g_spawn_check_exit_status (estatus, error))
|
if (!g_spawn_check_exit_status (estatus, error))
|
||||||
|
{
|
||||||
|
g_prefix_error (error, "Executing bwrap(%s): ", bwrap->child_argv0);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
|
||||||
rpmostree_run_bwrap_sync (char **argv_array, int rootfs_fd, GError **error)
|
|
||||||
{
|
|
||||||
return rpmostree_run_bwrap_sync_setup (argv_array, rootfs_fd, NULL, NULL, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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)
|
||||||
{
|
{
|
||||||
glnx_fd_close int host_root_dfd = -1;
|
glnx_fd_close int host_root_dfd = -1;
|
||||||
g_autoptr(GPtrArray) bwrap_argv = NULL;
|
g_autoptr(RpmOstreeBwrap) bwrap = NULL;
|
||||||
|
|
||||||
if (!glnx_opendirat (AT_FDCWD, "/", TRUE, &host_root_dfd, error))
|
if (!glnx_opendirat (AT_FDCWD, "/", TRUE, &host_root_dfd, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
bwrap_argv = rpmostree_bwrap_base_argv_new_for_rootfs (host_root_dfd, error);
|
bwrap = rpmostree_bwrap_new (host_root_dfd, RPMOSTREE_BWRAP_IMMUTABLE, error, NULL);
|
||||||
if (!bwrap_argv)
|
if (!bwrap)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
rpmostree_ptrarray_append_strdup (bwrap_argv,
|
rpmostree_bwrap_append_child_argv (bwrap, "true", NULL);
|
||||||
"--ro-bind", "usr", "/usr",
|
|
||||||
NULL);
|
if (!rpmostree_bwrap_run (bwrap, error))
|
||||||
g_ptr_array_add (bwrap_argv, g_strdup ("true"));
|
|
||||||
g_ptr_array_add (bwrap_argv, NULL);
|
|
||||||
if (!rpmostree_run_bwrap_sync ((char**)bwrap_argv->pdata, host_root_dfd, error))
|
|
||||||
{
|
{
|
||||||
g_prefix_error (error, "bwrap test failed, see <https://github.com/projectatomic/rpm-ostree/pull/429>: ");
|
g_prefix_error (error, "bwrap test failed, see <https://github.com/projectatomic/rpm-ostree/pull/429>: ");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -24,17 +24,32 @@
|
|||||||
|
|
||||||
#include "libglnx.h"
|
#include "libglnx.h"
|
||||||
|
|
||||||
GPtrArray *rpmostree_bwrap_base_argv_new_for_rootfs (int rootfs, GError **error);
|
typedef enum {
|
||||||
|
RPMOSTREE_BWRAP_IMMUTABLE = 0,
|
||||||
|
RPMOSTREE_BWRAP_MUTATE_ROFILES,
|
||||||
|
RPMOSTREE_BWRAP_MUTATE_FREELY
|
||||||
|
} RpmOstreeBwrapMutability;
|
||||||
|
|
||||||
|
typedef struct RpmOstreeBwrap RpmOstreeBwrap;
|
||||||
|
RpmOstreeBwrap *rpmostree_bwrap_ref (RpmOstreeBwrap *bwrap);
|
||||||
|
void rpmostree_bwrap_unref (RpmOstreeBwrap *bwrap);
|
||||||
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(RpmOstreeBwrap, rpmostree_bwrap_unref)
|
||||||
|
|
||||||
|
/* TODO - move this utility elsewhere */
|
||||||
void rpmostree_ptrarray_append_strdup (GPtrArray *argv_array, ...) G_GNUC_NULL_TERMINATED;
|
void rpmostree_ptrarray_append_strdup (GPtrArray *argv_array, ...) G_GNUC_NULL_TERMINATED;
|
||||||
|
|
||||||
gboolean rpmostree_run_sync_fchdir_setup (char **argv_array, GSpawnFlags flags,
|
RpmOstreeBwrap *rpmostree_bwrap_new (int rootfs,
|
||||||
int rootfs_fd, GError **error);
|
RpmOstreeBwrapMutability mutable,
|
||||||
|
GError **error,
|
||||||
|
...) G_GNUC_NULL_TERMINATED;
|
||||||
|
|
||||||
gboolean rpmostree_run_bwrap_sync (char **argv_array, int rootfs_fd, GError **error);
|
void rpmostree_bwrap_append_bwrap_argv (RpmOstreeBwrap *bwrap, ...) G_GNUC_NULL_TERMINATED;
|
||||||
gboolean rpmostree_run_bwrap_sync_setup (char **argv_array, int rootfs_fd,
|
void rpmostree_bwrap_append_child_argv (RpmOstreeBwrap *bwrap, ...) G_GNUC_NULL_TERMINATED;
|
||||||
|
|
||||||
|
void rpmostree_bwrap_set_child_setup (RpmOstreeBwrap *bwrap,
|
||||||
GSpawnChildSetupFunc func,
|
GSpawnChildSetupFunc func,
|
||||||
gpointer data,
|
gpointer data);
|
||||||
GError **error);
|
|
||||||
|
gboolean rpmostree_bwrap_run (RpmOstreeBwrap *bwrap, GError **error);
|
||||||
|
|
||||||
gboolean rpmostree_bwrap_selftest (GError **error);
|
gboolean rpmostree_bwrap_selftest (GError **error);
|
||||||
|
@ -58,22 +58,20 @@ run_sync_in_root_at (int rootfs_fd,
|
|||||||
gpointer data,
|
gpointer data,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
g_autoptr(GPtrArray) bwrap_argv = NULL;
|
g_autoptr(RpmOstreeBwrap) bwrap = NULL;
|
||||||
|
|
||||||
bwrap_argv = rpmostree_bwrap_base_argv_new_for_rootfs (rootfs_fd, error);
|
|
||||||
if (!bwrap_argv)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
/* Bind all of the primary toplevel dirs; unlike the script case, treecompose
|
/* Bind all of the primary toplevel dirs; unlike the script case, treecompose
|
||||||
* isn't yet operating on hardlinks, so we can just bind mount things mutably.
|
* isn't yet operating on hardlinks, so we can just bind mount things mutably.
|
||||||
*/
|
*/
|
||||||
rpmostree_ptrarray_append_strdup (bwrap_argv,
|
bwrap = rpmostree_bwrap_new (rootfs_fd, RPMOSTREE_BWRAP_MUTATE_FREELY, error,
|
||||||
"--bind", "usr", "/usr",
|
|
||||||
"--bind", "var", "/var",
|
"--bind", "var", "/var",
|
||||||
"--bind", "etc", "/etc",
|
"--bind", "etc", "/etc",
|
||||||
NULL);
|
NULL);
|
||||||
|
if (!bwrap)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
rpmostree_bwrap_append_child_argv (bwrap, binpath, NULL);
|
||||||
|
|
||||||
g_ptr_array_add (bwrap_argv, g_strdup (binpath));
|
|
||||||
/* https://github.com/projectatomic/bubblewrap/issues/91 */
|
/* https://github.com/projectatomic/bubblewrap/issues/91 */
|
||||||
{ gboolean first = TRUE;
|
{ gboolean first = TRUE;
|
||||||
for (char **iter = child_argv; iter && *iter; iter++)
|
for (char **iter = child_argv; iter && *iter; iter++)
|
||||||
@ -81,17 +79,15 @@ run_sync_in_root_at (int rootfs_fd,
|
|||||||
if (first)
|
if (first)
|
||||||
first = FALSE;
|
first = FALSE;
|
||||||
else
|
else
|
||||||
g_ptr_array_add (bwrap_argv, g_strdup (*iter));
|
rpmostree_bwrap_append_child_argv (bwrap, *iter, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g_ptr_array_add (bwrap_argv, NULL);
|
|
||||||
|
|
||||||
if (!rpmostree_run_bwrap_sync_setup ((char**)bwrap_argv->pdata, rootfs_fd,
|
if (setup_func)
|
||||||
setup_func, data, error))
|
rpmostree_bwrap_set_child_setup (bwrap, setup_func, data);
|
||||||
{
|
|
||||||
g_prefix_error (error, "Executing bwrap(%s): ", child_argv[0]);
|
if (!rpmostree_bwrap_run (bwrap, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <gio/gio.h>
|
#include <gio/gio.h>
|
||||||
#include <systemd/sd-journal.h>
|
|
||||||
#include "rpmostree-output.h"
|
#include "rpmostree-output.h"
|
||||||
#include "rpmostree-bwrap.h"
|
#include "rpmostree-bwrap.h"
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
@ -77,38 +76,6 @@ static const KnownRpmScriptKind unsupported_scripts[] = {
|
|||||||
RPMTAG_VERIFYSCRIPT, RPMTAG_VERIFYSCRIPTPROG, RPMTAG_VERIFYSCRIPTFLAGS},
|
RPMTAG_VERIFYSCRIPT, RPMTAG_VERIFYSCRIPTPROG, RPMTAG_VERIFYSCRIPTFLAGS},
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
|
||||||
fusermount_cleanup (const char *mountpoint)
|
|
||||||
{
|
|
||||||
g_autoptr(GError) tmp_error = NULL;
|
|
||||||
const char *fusermount_argv[] = { "fusermount", "-u", mountpoint, NULL};
|
|
||||||
int estatus;
|
|
||||||
|
|
||||||
if (!g_spawn_sync (NULL, (char**)fusermount_argv, NULL, G_SPAWN_SEARCH_PATH,
|
|
||||||
NULL, NULL, NULL, NULL, &estatus, &tmp_error))
|
|
||||||
{
|
|
||||||
g_prefix_error (&tmp_error, "Executing fusermount: ");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (!g_spawn_check_exit_status (estatus, &tmp_error))
|
|
||||||
{
|
|
||||||
g_prefix_error (&tmp_error, "Executing fusermount: ");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
/* We don't want a failure to unmount to be fatal, so all we do here
|
|
||||||
* is log. Though in practice what we *really* want is for the
|
|
||||||
* fusermount to be in the bwrap namespace, and hence tied by the
|
|
||||||
* kernel to the lifecycle of the container. This would require
|
|
||||||
* special casing for somehow doing FUSE mounts in bwrap. Which
|
|
||||||
* would be hard because NO_NEW_PRIVS turns off the setuid bits for
|
|
||||||
* fuse.
|
|
||||||
*/
|
|
||||||
if (tmp_error)
|
|
||||||
sd_journal_print (LOG_WARNING, "%s", tmp_error->message);
|
|
||||||
}
|
|
||||||
|
|
||||||
static RpmOstreeScriptAction
|
static RpmOstreeScriptAction
|
||||||
lookup_script_action (DnfPackage *package,
|
lookup_script_action (DnfPackage *package,
|
||||||
GHashTable *ignored_scripts,
|
GHashTable *ignored_scripts,
|
||||||
@ -172,44 +139,27 @@ run_script_in_bwrap_container (int rootfs_fd,
|
|||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
char *rofiles_mnt = strdupa ("/tmp/rofiles-fuse.XXXXXX");
|
|
||||||
const char *rofiles_argv[] = { "rofiles-fuse", "./usr", rofiles_mnt, NULL};
|
|
||||||
const char *pkg_script = glnx_strjoina (name, ".", scriptdesc+1);
|
const char *pkg_script = glnx_strjoina (name, ".", scriptdesc+1);
|
||||||
const char *postscript_name = glnx_strjoina ("/", pkg_script);
|
const char *postscript_name = glnx_strjoina ("/", pkg_script);
|
||||||
const char *postscript_path_container = glnx_strjoina ("/usr/", postscript_name);
|
const char *postscript_path_container = glnx_strjoina ("/usr", postscript_name);
|
||||||
const char *postscript_path_host;
|
const char *postscript_path_host = postscript_path_container + 1;
|
||||||
gboolean mntpoint_created = FALSE;
|
g_autoptr(RpmOstreeBwrap) bwrap = NULL;
|
||||||
gboolean fuse_mounted = FALSE;
|
|
||||||
g_autoptr(GPtrArray) bwrap_argv = g_ptr_array_new ();
|
|
||||||
gboolean created_var_tmp = FALSE;
|
gboolean created_var_tmp = FALSE;
|
||||||
|
|
||||||
if (!glnx_mkdtempat (AT_FDCWD, rofiles_mnt, 0700, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
mntpoint_created = TRUE;
|
|
||||||
|
|
||||||
if (!rpmostree_run_sync_fchdir_setup ((char**)rofiles_argv, G_SPAWN_SEARCH_PATH,
|
|
||||||
rootfs_fd, error))
|
|
||||||
{
|
|
||||||
g_prefix_error (error, "Executing rofiles-fuse: ");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
fuse_mounted = TRUE;
|
|
||||||
|
|
||||||
postscript_path_host = glnx_strjoina (rofiles_mnt, "/", postscript_name);
|
|
||||||
|
|
||||||
/* TODO - Create a pipe and send this to bwrap so it's inside the
|
/* TODO - Create a pipe and send this to bwrap so it's inside the
|
||||||
* tmpfs
|
* tmpfs. Note the +1 on the path to skip the leading /.
|
||||||
*/
|
*/
|
||||||
if (!g_file_set_contents (postscript_path_host, script, -1, error))
|
if (!glnx_file_replace_contents_at (rootfs_fd, postscript_path_host,
|
||||||
|
(guint8*)script, -1,
|
||||||
|
GLNX_FILE_REPLACE_NODATASYNC,
|
||||||
|
NULL, error))
|
||||||
{
|
{
|
||||||
g_prefix_error (error, "Writing script to %s: ", postscript_path_host);
|
g_prefix_error (error, "Writing script to %s: ", postscript_path_host);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (chmod (postscript_path_host, 0755) != 0)
|
if (fchmodat (rootfs_fd, postscript_path_host, 0755, 0) != 0)
|
||||||
{
|
{
|
||||||
g_prefix_error (error, "chmod %s: ", postscript_path_host);
|
glnx_set_error_from_errno (error);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,12 +186,7 @@ run_script_in_bwrap_container (int rootfs_fd,
|
|||||||
else
|
else
|
||||||
created_var_tmp = TRUE;
|
created_var_tmp = TRUE;
|
||||||
|
|
||||||
bwrap_argv = rpmostree_bwrap_base_argv_new_for_rootfs (rootfs_fd, error);
|
bwrap = rpmostree_bwrap_new (rootfs_fd, RPMOSTREE_BWRAP_MUTATE_ROFILES, error,
|
||||||
if (!bwrap_argv)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
rpmostree_ptrarray_append_strdup (bwrap_argv,
|
|
||||||
"--bind", rofiles_mnt, "/usr",
|
|
||||||
/* Scripts can see a /var with compat links like alternatives */
|
/* Scripts can see a /var with compat links like alternatives */
|
||||||
"--ro-bind", "./var", "/var",
|
"--ro-bind", "./var", "/var",
|
||||||
/* But no need to access persistent /tmp, so make it /tmp */
|
/* But no need to access persistent /tmp, so make it /tmp */
|
||||||
@ -249,27 +194,20 @@ run_script_in_bwrap_container (int rootfs_fd,
|
|||||||
/* Allow RPM scripts to change the /etc defaults */
|
/* Allow RPM scripts to change the /etc defaults */
|
||||||
"--symlink", "usr/etc", "/etc",
|
"--symlink", "usr/etc", "/etc",
|
||||||
NULL);
|
NULL);
|
||||||
|
if (!bwrap)
|
||||||
g_ptr_array_add (bwrap_argv, g_strdup (postscript_path_container));
|
goto out;
|
||||||
/* http://www.rpm.org/max-rpm/s1-rpm-inside-scripts.html#S3-RPM-INSIDE-PRE-SCRIPT */
|
|
||||||
g_ptr_array_add (bwrap_argv, g_strdup ("1"));
|
rpmostree_bwrap_append_child_argv (bwrap,
|
||||||
g_ptr_array_add (bwrap_argv, NULL);
|
postscript_path_container,
|
||||||
|
/* http://www.rpm.org/max-rpm/s1-rpm-inside-scripts.html#S3-RPM-INSIDE-PRE-SCRIPT */
|
||||||
if (!rpmostree_run_bwrap_sync ((char**)bwrap_argv->pdata, rootfs_fd, error))
|
"1",
|
||||||
{
|
NULL);
|
||||||
g_prefix_error (error, "Executing bwrap: ");
|
|
||||||
|
if (!rpmostree_bwrap_run (bwrap, error))
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
out:
|
out:
|
||||||
if (fuse_mounted)
|
|
||||||
{
|
|
||||||
(void) unlink (postscript_path_host);
|
|
||||||
fusermount_cleanup (rofiles_mnt);
|
|
||||||
}
|
|
||||||
if (mntpoint_created)
|
|
||||||
(void) unlinkat (AT_FDCWD, rofiles_mnt, AT_REMOVEDIR);
|
|
||||||
if (created_var_tmp)
|
if (created_var_tmp)
|
||||||
(void) unlinkat (rootfs_fd, "var/tmp", AT_REMOVEDIR);
|
(void) unlinkat (rootfs_fd, "var/tmp", AT_REMOVEDIR);
|
||||||
return ret;
|
return ret;
|
||||||
|
Loading…
Reference in New Issue
Block a user