lib: Extract bwrap-executing internal API

The treecompose code will learn how to use bwrap instead of
libcontainer in libglnx, since the latter is a buggy copy of a subset
of the former.

Closes: #429
Approved by: jlebon
This commit is contained in:
Colin Walters 2016-08-12 13:03:23 -04:00 committed by Atomic Bot
parent 873f4766d7
commit 88a130da09
4 changed files with 155 additions and 70 deletions

View File

@ -30,6 +30,8 @@ librpmostreepriv_la_SOURCES = \
src/libpriv/rpmostree-refts.c \
src/libpriv/rpmostree-core.c \
src/libpriv/rpmostree-core.h \
src/libpriv/rpmostree-bwrap.c \
src/libpriv/rpmostree-bwrap.h \
src/libpriv/rpmostree-scripts.c \
src/libpriv/rpmostree-scripts.h \
src/libpriv/rpmostree-refsack.h \

View File

@ -0,0 +1,109 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2016 Red Hat, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2 of the licence or (at
* your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "rpmostree-bwrap.h"
#include <err.h>
void
rpmostree_ptrarray_append_strdup (GPtrArray *argv_array, ...)
{
va_list args;
char *arg;
va_start (args, argv_array);
while ((arg = va_arg (args, char *)))
g_ptr_array_add (argv_array, g_strdup (arg));
va_end (args);
}
GPtrArray *
rpmostree_bwrap_base_argv_new_for_rootfs (int rootfs_fd, GError **error)
{
g_autoptr(GPtrArray) bwrap_argv = g_ptr_array_new_with_free_func (g_free);
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);
for (guint i = 0; i < G_N_ELEMENTS (usr_links); i++)
{
const char *subdir = usr_links[i];
struct stat stbuf;
char *path;
if (fstatat (rootfs_fd, subdir, &stbuf, AT_SYMLINK_NOFOLLOW) < 0)
{
if (errno != ENOENT)
{
glnx_set_error_from_errno (error);
return FALSE;
}
continue;
}
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);
}
return g_steal_pointer (&bwrap_argv);
}
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;
}

View File

@ -0,0 +1,32 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2016 Colin Walters <walters@verbum.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2 of the licence or (at
* your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#pragma once
#include <ostree.h>
#include "libglnx.h"
GPtrArray *rpmostree_bwrap_base_argv_new_for_rootfs (int rootfs, GError **error);
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);

View File

@ -23,6 +23,7 @@
#include <gio/gio.h>
#include <systemd/sd-journal.h>
#include "rpmostree-output.h"
#include "rpmostree-bwrap.h"
#include <err.h>
#include "libglnx.h"
@ -73,26 +74,6 @@ static const KnownRpmScriptKind unsupported_scripts[] = {
RPMTAG_VERIFYSCRIPT, RPMTAG_VERIFYSCRIPTPROG, RPMTAG_VERIFYSCRIPTFLAGS},
};
static void
child_setup_fchdir (gpointer user_data)
{
int fd = GPOINTER_TO_INT (user_data);
if (fchdir (fd) < 0)
err (1, "fchdir");
}
static void
add_const_args (GPtrArray *argv_array, ...)
{
va_list args;
char *arg;
va_start (args, argv_array);
while ((arg = va_arg (args, char *)))
g_ptr_array_add (argv_array, arg);
va_end (args);
}
static void
fusermount_cleanup (const char *mountpoint)
{
@ -188,9 +169,6 @@ run_script_in_bwrap_container (int rootfs_fd,
GError **error)
{
gboolean ret = FALSE;
int i;
const char *usr_links[] = {"lib", "lib32", "lib64", "bin", "sbin"};
int estatus;
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);
@ -200,7 +178,6 @@ run_script_in_bwrap_container (int rootfs_fd,
gboolean mntpoint_created = FALSE;
gboolean fuse_mounted = FALSE;
g_autoptr(GPtrArray) bwrap_argv = g_ptr_array_new ();
g_autoptr(GPtrArray) bwrap_argv_mallocd = g_ptr_array_new_with_free_func (g_free);
GSpawnFlags bwrap_spawnflags = G_SPAWN_SEARCH_PATH;
gboolean created_var_tmp = FALSE;
@ -209,11 +186,8 @@ run_script_in_bwrap_container (int rootfs_fd,
mntpoint_created = TRUE;
if (!g_spawn_sync (NULL, (char**)rofiles_argv, NULL, G_SPAWN_SEARCH_PATH,
child_setup_fchdir, GINT_TO_POINTER (rootfs_fd),
NULL, NULL, &estatus, error))
goto out;
if (!g_spawn_check_exit_status (estatus, error))
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;
@ -260,65 +234,33 @@ run_script_in_bwrap_container (int rootfs_fd,
else
created_var_tmp = TRUE;
add_const_args (bwrap_argv,
WITH_BUBBLEWRAP_PATH,
bwrap_argv = rpmostree_bwrap_base_argv_new_for_rootfs (rootfs_fd, error);
if (!bwrap_argv)
goto out;
rpmostree_ptrarray_append_strdup (bwrap_argv,
"--bind", rofiles_mnt, "/usr",
"--dev", "/dev",
"--proc", "/proc",
"--dir", "/tmp",
"--chdir", "/",
/* 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",
"--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 (i = 0; i < G_N_ELEMENTS (usr_links); i++)
{
const char *subdir = usr_links[i];
struct stat stbuf;
char *path;
if (!(fstatat (rootfs_fd, subdir, &stbuf, AT_SYMLINK_NOFOLLOW) == 0 && S_ISLNK (stbuf.st_mode)))
continue;
g_ptr_array_add (bwrap_argv, "--symlink");
path = g_strconcat ("usr/", subdir, NULL);
g_ptr_array_add (bwrap_argv_mallocd, path);
g_ptr_array_add (bwrap_argv, path);
path = g_strconcat ("/", subdir, NULL);
g_ptr_array_add (bwrap_argv_mallocd, path);
g_ptr_array_add (bwrap_argv, path);
}
{ const char *debugscript = getenv ("RPMOSTREE_DEBUG_SCRIPT");
if (g_strcmp0 (debugscript, pkg_script) == 0)
{
g_ptr_array_add (bwrap_argv, (char*)"/bin/bash");
g_ptr_array_add (bwrap_argv, g_strdup ("/bin/bash"));
bwrap_spawnflags |= G_SPAWN_CHILD_INHERITS_STDIN;
}
else
g_ptr_array_add (bwrap_argv, (char*)postscript_path_container);
g_ptr_array_add (bwrap_argv, g_strdup (postscript_path_container));
}
g_ptr_array_add (bwrap_argv, NULL);
if (!g_spawn_sync (NULL, (char**)bwrap_argv->pdata, NULL, bwrap_spawnflags,
child_setup_fchdir, GINT_TO_POINTER (rootfs_fd),
NULL, NULL, &estatus, error))
{
g_prefix_error (error, "Executing bwrap: ");
goto out;
}
if (!g_spawn_check_exit_status (estatus, error))
if (!rpmostree_run_sync_fchdir_setup ((char**)bwrap_argv->pdata,
bwrap_spawnflags, rootfs_fd, error))
{
g_prefix_error (error, "Executing bwrap: ");
goto out;