From 1b3bdc243e761a81f7ac648859601b296095c208 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Sat, 13 Mar 2021 16:07:54 +0000 Subject: [PATCH] Move high level bwrap postprocess interface to C++ A future patch will then expose this interface via cxxrs, allowing us to port more of the postprocess.cxx code to Rust. --- rust/src/lib.rs | 10 +++ src/libpriv/rpmostree-bwrap.cxx | 72 ++++++++++++++++++++ src/libpriv/rpmostree-bwrap.h | 10 +++ src/libpriv/rpmostree-postprocess.cxx | 96 +++++---------------------- 4 files changed, 108 insertions(+), 80 deletions(-) diff --git a/rust/src/lib.rs b/rust/src/lib.rs index c1970b3e..0ed904d6 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -316,6 +316,16 @@ pub mod ffi { fn main_print_error(msg: &str); } + unsafe extern "C++" { + include!("rpmostree-bwrap.h"); + fn bwrap_run_mutable( + rootfs_dfd: i32, + binpath: &str, + child_argv: &Vec, + unified_core_mode: bool, + ) -> Result<()>; + } + unsafe extern "C++" { include!("rpmostree-clientlib.h"); fn client_require_root() -> Result<()>; diff --git a/src/libpriv/rpmostree-bwrap.cxx b/src/libpriv/rpmostree-bwrap.cxx index 4b29dde6..9ddade74 100644 --- a/src/libpriv/rpmostree-bwrap.cxx +++ b/src/libpriv/rpmostree-bwrap.cxx @@ -528,3 +528,75 @@ rpmostree_bwrap_selftest (GError **error) return TRUE; } + +namespace rpmostreecxx { + +// High level interface to bwrap, currently used by the postprocess code. +// This deals with renaming `/etc` to `/usr/etc` for example. +void +bwrap_run_mutable(int32_t rootfs_fd, rust::Str binpath, + const rust::Vec &child_argv, + bool unified_core_mode) +{ + g_autoptr(GError) local_error = NULL; + /* For scripts, it's /etc, not /usr/etc */ + if (!glnx_fstatat_allow_noent (rootfs_fd, "etc", NULL, 0, &local_error)) + util::throw_gerror(local_error); + const bool renamed_usretc = (errno == ENOENT); + if (renamed_usretc) + { + if (!glnx_renameat (rootfs_fd, "usr/etc", rootfs_fd, "etc", &local_error)) + util::throw_gerror(local_error); + /* But leave a compat symlink, as we used to bind mount, so scripts + * could still use that too. + */ + if (symlinkat ("../etc", rootfs_fd, "usr/etc") < 0) + { + (void)glnx_throw_errno_prefix (&local_error, "symlinkat"); + util::throw_gerror(local_error); + } + } + + RpmOstreeBwrapMutability mut = + unified_core_mode ? RPMOSTREE_BWRAP_MUTATE_ROFILES : RPMOSTREE_BWRAP_MUTATE_FREELY; + g_autoptr(RpmOstreeBwrap) bwrap = rpmostree_bwrap_new (rootfs_fd, mut, &local_error); + if (!bwrap) + util::throw_gerror(local_error); + + if (unified_core_mode) + rpmostree_bwrap_bind_read (bwrap, "var", "/var"); + else + rpmostree_bwrap_bind_readwrite (bwrap, "var", "/var"); + + { auto binpath_s = std::string(binpath); + rpmostree_bwrap_append_child_argv (bwrap, binpath_s.c_str(), NULL); + } + + /* https://github.com/projectatomic/bubblewrap/issues/91 */ + { bool first = true; + for (auto &elt : child_argv) + { + if (first) + first = false; + else + { + auto s = std::string(elt); // NUL terminate + rpmostree_bwrap_append_child_argv (bwrap, s.c_str(), NULL); + } + } + } + + if (!rpmostree_bwrap_run (bwrap, NULL, &local_error)) + util::throw_gerror(local_error); + + /* Remove the symlink and swap back */ + if (renamed_usretc) + { + if (!glnx_unlinkat (rootfs_fd, "usr/etc", 0, &local_error)) + util::throw_gerror(local_error); + if (!glnx_renameat (rootfs_fd, "etc", rootfs_fd, "usr/etc", &local_error)) + util::throw_gerror(local_error); + } +} + +} /* namespace */ diff --git a/src/libpriv/rpmostree-bwrap.h b/src/libpriv/rpmostree-bwrap.h index ddd96521..f7931745 100644 --- a/src/libpriv/rpmostree-bwrap.h +++ b/src/libpriv/rpmostree-bwrap.h @@ -24,6 +24,16 @@ #include "libglnx.h" +#include "rust/cxx.h" + +namespace rpmostreecxx { + +void bwrap_run_mutable(int32_t rootfs_dfd, rust::Str binpath, + const rust::Vec &child_argv, + bool unified_core_mode); + +} + G_BEGIN_DECLS typedef enum { diff --git a/src/libpriv/rpmostree-postprocess.cxx b/src/libpriv/rpmostree-postprocess.cxx index 13e2b64e..49f9f873 100644 --- a/src/libpriv/rpmostree-postprocess.cxx +++ b/src/libpriv/rpmostree-postprocess.cxx @@ -55,71 +55,6 @@ typedef enum { RPMOSTREE_POSTPROCESS_BOOT_LOCATION_MODULES, } RpmOstreePostprocessBootLocation; -/* The "unified_core_mode" flag controls whether or not we use rofiles-fuse, - * just like pkg layering. - */ -static gboolean -run_bwrap_mutably (int rootfs_fd, - const char *binpath, - char **child_argv, - gboolean unified_core_mode, - GCancellable *cancellable, - GError **error) -{ - /* For scripts, it's /etc, not /usr/etc */ - if (!glnx_fstatat_allow_noent (rootfs_fd, "etc", NULL, 0, error)) - return FALSE; - gboolean renamed_usretc = (errno == ENOENT); - if (renamed_usretc) - { - if (!glnx_renameat (rootfs_fd, "usr/etc", rootfs_fd, "etc", error)) - return FALSE; - /* But leave a compat symlink, as we used to bind mount, so scripts - * could still use that too. - */ - if (symlinkat ("../etc", rootfs_fd, "usr/etc") < 0) - return glnx_throw_errno_prefix (error, "symlinkat"); - } - - RpmOstreeBwrapMutability mut = - unified_core_mode ? RPMOSTREE_BWRAP_MUTATE_ROFILES : RPMOSTREE_BWRAP_MUTATE_FREELY; - g_autoptr(RpmOstreeBwrap) bwrap = rpmostree_bwrap_new (rootfs_fd, mut, error); - if (!bwrap) - return FALSE; - - if (unified_core_mode) - rpmostree_bwrap_bind_read (bwrap, "var", "/var"); - else - rpmostree_bwrap_bind_readwrite (bwrap, "var", "/var"); - - rpmostree_bwrap_append_child_argv (bwrap, binpath, NULL); - - /* https://github.com/projectatomic/bubblewrap/issues/91 */ - { gboolean first = TRUE; - for (char **iter = child_argv; iter && *iter; iter++) - { - if (first) - first = FALSE; - else - rpmostree_bwrap_append_child_argv (bwrap, *iter, NULL); - } - } - - if (!rpmostree_bwrap_run (bwrap, cancellable, error)) - return FALSE; - - /* Remove the symlink and swap back */ - if (renamed_usretc) - { - if (!glnx_unlinkat (rootfs_fd, "usr/etc", 0, error)) - return FALSE; - if (!glnx_renameat (rootfs_fd, "etc", rootfs_fd, "usr/etc", error)) - return FALSE; - } - - return TRUE; -} - static gboolean rename_if_exists (int src_dfd, const char *from, @@ -278,9 +213,8 @@ rpmostree_postprocess_run_depmod (int rootfs_dfd, GCancellable *cancellable, GError **error) { - const char *child_argv[] = { "depmod", "-a", kver, NULL }; - if (!run_bwrap_mutably (rootfs_dfd, "depmod", (char**)child_argv, unified_core_mode, cancellable, error)) - return FALSE; + rust::Vec child_argv = { rust::String("depmod"), rust::String("-a"), rust::String(kver) }; + rpmostreecxx::bwrap_run_mutable (rootfs_dfd, "depmod", child_argv, (bool)unified_core_mode); return TRUE; } @@ -888,10 +822,8 @@ rpmostree_postprocess_final (int rootfs_dfd, /* Now regenerate SELinux policy so that postprocess scripts from users and from us * (e.g. the /etc/default/useradd incision) that affect it are baked in. */ - const char *child_argv[] = { "semodule", "-nB", NULL }; - if (!run_bwrap_mutably (rootfs_dfd, "semodule", (char**)child_argv, unified_core_mode, - cancellable, error)) - return FALSE; + rust::Vec child_argv = { rust::String("semodule"), rust::String("-nB") }; + rpmostreecxx::bwrap_run_mutable (rootfs_dfd, "semodule", child_argv, (bool)unified_core_mode); } gboolean container = FALSE; @@ -1607,9 +1539,13 @@ rpmostree_treefile_postprocessing (int rootfs_fd, cancellable, error)) return FALSE; g_print ("Executing `postprocess` inline script '%u'\n", i); - char *child_argv[] = { binpath, NULL }; - if (!run_bwrap_mutably (rootfs_fd, binpath, child_argv, unified_core_mode, cancellable, error)) - return glnx_prefix_error (error, "While executing inline postprocessing script '%i'", i); + rust::Vec child_argv = { rust::String(binpath)}; + try { + rpmostreecxx::bwrap_run_mutable (rootfs_fd, binpath, child_argv, (bool)unified_core_mode); + } catch (std::exception& e) { + g_autofree char* msg = g_strdup_printf ("While executing inline postprocessing script '%i'", i); + util::rethrow_prefixed(e, msg); + } if (!glnx_unlinkat (rootfs_fd, target_binpath, 0, error)) return FALSE; @@ -1638,12 +1574,12 @@ rpmostree_treefile_postprocessing (int rootfs_fd, g_print ("Executing postprocessing script\n"); - { - char *child_argv[] = { (char*)binpath, NULL }; - if (!run_bwrap_mutably (rootfs_fd, binpath, child_argv, unified_core_mode, cancellable, error)) - return glnx_prefix_error (error, "While executing postprocessing script"); + rust::Vec child_argv = { rust::String(binpath) }; + try { + rpmostreecxx::bwrap_run_mutable (rootfs_fd, binpath, child_argv, (bool)unified_core_mode); + } catch (std::exception& e) { + util::rethrow_prefixed(e, "Executing postprocessing script"); } - if (!glnx_unlinkat (rootfs_fd, target_binpath, 0, error)) return FALSE;