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 <err.h>
|
||||
#include <stdio.h>
|
||||
#include <systemd/sd-journal.h>
|
||||
|
||||
void
|
||||
rpmostree_ptrarray_append_strdup (GPtrArray *argv_array, ...)
|
||||
@ -35,30 +37,180 @@ rpmostree_ptrarray_append_strdup (GPtrArray *argv_array, ...)
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
GPtrArray *
|
||||
rpmostree_bwrap_base_argv_new_for_rootfs (int rootfs_fd, GError **error)
|
||||
struct RpmOstreeBwrap {
|
||||
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"};
|
||||
|
||||
rpmostree_ptrarray_append_strdup (bwrap_argv,
|
||||
WITH_BUBBLEWRAP_PATH,
|
||||
"--dev", "/dev",
|
||||
"--proc", "/proc",
|
||||
"--dir", "/tmp",
|
||||
"--chdir", "/",
|
||||
"--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",
|
||||
NULL);
|
||||
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,
|
||||
"--dev", "/dev",
|
||||
"--proc", "/proc",
|
||||
"--dir", "/tmp",
|
||||
"--chdir", "/",
|
||||
"--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",
|
||||
NULL);
|
||||
|
||||
for (guint i = 0; i < G_N_ELEMENTS (usr_links); i++)
|
||||
{
|
||||
const char *subdir = usr_links[i];
|
||||
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)
|
||||
{
|
||||
@ -72,70 +224,68 @@ rpmostree_bwrap_base_argv_new_for_rootfs (int rootfs_fd, GError **error)
|
||||
else if (!S_ISLNK (stbuf.st_mode))
|
||||
continue;
|
||||
|
||||
g_ptr_array_add (bwrap_argv, g_strdup ("--symlink"));
|
||||
|
||||
path = g_strconcat ("usr/", subdir, NULL);
|
||||
g_ptr_array_add (bwrap_argv, path);
|
||||
|
||||
path = g_strconcat ("/", subdir, NULL);
|
||||
g_ptr_array_add (bwrap_argv, path);
|
||||
srcpath = g_strconcat ("usr/", subdir, NULL);
|
||||
destpath = g_strconcat ("/", subdir, NULL);
|
||||
rpmostree_bwrap_append_bwrap_argv (ret, "--symlink", srcpath, destpath, NULL);
|
||||
}
|
||||
|
||||
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
|
||||
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");
|
||||
|
||||
if (cdata->func)
|
||||
cdata->func (cdata->data);
|
||||
if (bwrap->child_setup_func)
|
||||
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
|
||||
rpmostree_run_bwrap_sync_setup (char **argv_array,
|
||||
int rootfs_fd,
|
||||
GSpawnChildSetupFunc func,
|
||||
gpointer data,
|
||||
GError **error)
|
||||
rpmostree_bwrap_run (RpmOstreeBwrap *bwrap,
|
||||
GError **error)
|
||||
{
|
||||
int estatus;
|
||||
const char *current_lang = getenv ("LANG");
|
||||
ChildSetupData csetupdata = { rootfs_fd, func, data };
|
||||
|
||||
g_assert (!bwrap->executed);
|
||||
bwrap->executed = TRUE;
|
||||
|
||||
if (!current_lang)
|
||||
current_lang = "C";
|
||||
@ -151,43 +301,43 @@ rpmostree_run_bwrap_sync_setup (char **argv_array,
|
||||
lang_var,
|
||||
NULL};
|
||||
|
||||
if (!g_spawn_sync (NULL, argv_array, (char**) bwrap_env, G_SPAWN_SEARCH_PATH,
|
||||
bwrap_child_setup, &csetupdata,
|
||||
/* Add the final NULL */
|
||||
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))
|
||||
return FALSE;
|
||||
{
|
||||
g_prefix_error (error, "Executing bwrap(%s): ", bwrap->child_argv0);
|
||||
return FALSE;
|
||||
}
|
||||
if (!g_spawn_check_exit_status (estatus, error))
|
||||
return FALSE;
|
||||
{
|
||||
g_prefix_error (error, "Executing bwrap(%s): ", bwrap->child_argv0);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
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 */
|
||||
gboolean
|
||||
rpmostree_bwrap_selftest (GError **error)
|
||||
{
|
||||
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))
|
||||
return FALSE;
|
||||
|
||||
bwrap_argv = rpmostree_bwrap_base_argv_new_for_rootfs (host_root_dfd, error);
|
||||
if (!bwrap_argv)
|
||||
bwrap = rpmostree_bwrap_new (host_root_dfd, RPMOSTREE_BWRAP_IMMUTABLE, error, NULL);
|
||||
if (!bwrap)
|
||||
return FALSE;
|
||||
|
||||
rpmostree_ptrarray_append_strdup (bwrap_argv,
|
||||
"--ro-bind", "usr", "/usr",
|
||||
NULL);
|
||||
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))
|
||||
rpmostree_bwrap_append_child_argv (bwrap, "true", NULL);
|
||||
|
||||
if (!rpmostree_bwrap_run (bwrap, error))
|
||||
{
|
||||
g_prefix_error (error, "bwrap test failed, see <https://github.com/projectatomic/rpm-ostree/pull/429>: ");
|
||||
return FALSE;
|
||||
|
@ -24,17 +24,32 @@
|
||||
|
||||
#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;
|
||||
|
||||
gboolean rpmostree_run_sync_fchdir_setup (char **argv_array, GSpawnFlags flags,
|
||||
int rootfs_fd, GError **error);
|
||||
RpmOstreeBwrap *rpmostree_bwrap_new (int rootfs,
|
||||
RpmOstreeBwrapMutability mutable,
|
||||
GError **error,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
|
||||
gboolean rpmostree_run_bwrap_sync (char **argv_array, int rootfs_fd, GError **error);
|
||||
gboolean rpmostree_run_bwrap_sync_setup (char **argv_array, int rootfs_fd,
|
||||
GSpawnChildSetupFunc func,
|
||||
gpointer data,
|
||||
GError **error);
|
||||
void rpmostree_bwrap_append_bwrap_argv (RpmOstreeBwrap *bwrap, ...) G_GNUC_NULL_TERMINATED;
|
||||
void rpmostree_bwrap_append_child_argv (RpmOstreeBwrap *bwrap, ...) G_GNUC_NULL_TERMINATED;
|
||||
|
||||
void rpmostree_bwrap_set_child_setup (RpmOstreeBwrap *bwrap,
|
||||
GSpawnChildSetupFunc func,
|
||||
gpointer data);
|
||||
|
||||
gboolean rpmostree_bwrap_run (RpmOstreeBwrap *bwrap, GError **error);
|
||||
|
||||
gboolean rpmostree_bwrap_selftest (GError **error);
|
||||
|
@ -58,22 +58,20 @@ run_sync_in_root_at (int rootfs_fd,
|
||||
gpointer data,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GPtrArray) bwrap_argv = NULL;
|
||||
|
||||
bwrap_argv = rpmostree_bwrap_base_argv_new_for_rootfs (rootfs_fd, error);
|
||||
if (!bwrap_argv)
|
||||
return FALSE;
|
||||
g_autoptr(RpmOstreeBwrap) bwrap = NULL;
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
rpmostree_ptrarray_append_strdup (bwrap_argv,
|
||||
"--bind", "usr", "/usr",
|
||||
"--bind", "var", "/var",
|
||||
"--bind", "etc", "/etc",
|
||||
NULL);
|
||||
bwrap = rpmostree_bwrap_new (rootfs_fd, RPMOSTREE_BWRAP_MUTATE_FREELY, error,
|
||||
"--bind", "var", "/var",
|
||||
"--bind", "etc", "/etc",
|
||||
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 */
|
||||
{ gboolean first = TRUE;
|
||||
for (char **iter = child_argv; iter && *iter; iter++)
|
||||
@ -81,17 +79,15 @@ run_sync_in_root_at (int rootfs_fd,
|
||||
if (first)
|
||||
first = FALSE;
|
||||
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,
|
||||
setup_func, data, error))
|
||||
{
|
||||
g_prefix_error (error, "Executing bwrap(%s): ", child_argv[0]);
|
||||
return FALSE;
|
||||
}
|
||||
if (setup_func)
|
||||
rpmostree_bwrap_set_child_setup (bwrap, setup_func, data);
|
||||
|
||||
if (!rpmostree_bwrap_run (bwrap, error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <systemd/sd-journal.h>
|
||||
#include "rpmostree-output.h"
|
||||
#include "rpmostree-bwrap.h"
|
||||
#include <err.h>
|
||||
@ -77,38 +76,6 @@ static const KnownRpmScriptKind unsupported_scripts[] = {
|
||||
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
|
||||
lookup_script_action (DnfPackage *package,
|
||||
GHashTable *ignored_scripts,
|
||||
@ -172,44 +139,27 @@ run_script_in_bwrap_container (int rootfs_fd,
|
||||
GError **error)
|
||||
{
|
||||
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 *postscript_name = glnx_strjoina ("/", pkg_script);
|
||||
const char *postscript_path_container = glnx_strjoina ("/usr/", postscript_name);
|
||||
const char *postscript_path_host;
|
||||
gboolean mntpoint_created = FALSE;
|
||||
gboolean fuse_mounted = FALSE;
|
||||
g_autoptr(GPtrArray) bwrap_argv = g_ptr_array_new ();
|
||||
const char *postscript_path_container = glnx_strjoina ("/usr", postscript_name);
|
||||
const char *postscript_path_host = postscript_path_container + 1;
|
||||
g_autoptr(RpmOstreeBwrap) bwrap = NULL;
|
||||
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
|
||||
* 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);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -236,40 +186,28 @@ run_script_in_bwrap_container (int rootfs_fd,
|
||||
else
|
||||
created_var_tmp = TRUE;
|
||||
|
||||
bwrap_argv = rpmostree_bwrap_base_argv_new_for_rootfs (rootfs_fd, error);
|
||||
if (!bwrap_argv)
|
||||
bwrap = rpmostree_bwrap_new (rootfs_fd, RPMOSTREE_BWRAP_MUTATE_ROFILES, error,
|
||||
/* Scripts can see a /var with compat links like alternatives */
|
||||
"--ro-bind", "./var", "/var",
|
||||
/* But no need to access persistent /tmp, so make it /tmp */
|
||||
"--bind", "/tmp", "/var/tmp",
|
||||
/* Allow RPM scripts to change the /etc defaults */
|
||||
"--symlink", "usr/etc", "/etc",
|
||||
NULL);
|
||||
if (!bwrap)
|
||||
goto out;
|
||||
|
||||
rpmostree_ptrarray_append_strdup (bwrap_argv,
|
||||
"--bind", rofiles_mnt, "/usr",
|
||||
/* Scripts can see a /var with compat links like alternatives */
|
||||
"--ro-bind", "./var", "/var",
|
||||
/* But no need to access persistent /tmp, so make it /tmp */
|
||||
"--bind", "/tmp", "/var/tmp",
|
||||
/* Allow RPM scripts to change the /etc defaults */
|
||||
"--symlink", "usr/etc", "/etc",
|
||||
NULL);
|
||||
rpmostree_bwrap_append_child_argv (bwrap,
|
||||
postscript_path_container,
|
||||
/* http://www.rpm.org/max-rpm/s1-rpm-inside-scripts.html#S3-RPM-INSIDE-PRE-SCRIPT */
|
||||
"1",
|
||||
NULL);
|
||||
|
||||
g_ptr_array_add (bwrap_argv, g_strdup (postscript_path_container));
|
||||
/* 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"));
|
||||
g_ptr_array_add (bwrap_argv, NULL);
|
||||
|
||||
if (!rpmostree_run_bwrap_sync ((char**)bwrap_argv->pdata, rootfs_fd, error))
|
||||
{
|
||||
g_prefix_error (error, "Executing bwrap: ");
|
||||
goto out;
|
||||
}
|
||||
if (!rpmostree_bwrap_run (bwrap, error))
|
||||
goto out;
|
||||
|
||||
ret = TRUE;
|
||||
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)
|
||||
(void) unlinkat (rootfs_fd, "var/tmp", AT_REMOVEDIR);
|
||||
return ret;
|
||||
|
Loading…
Reference in New Issue
Block a user