core,scripts: When no cachedir+unified-core, disable rofiles-fuse
This is prep for running inside (unprivileged) Kube containers as they exist today: https://github.com/projectatomic/rpm-ostree/issues/1329 Sadly FUSE today uses a suid binary that ends up wanting CAP_SYS_ADMIN. I think there's some work on FUSE-in-containers but I'm not sure of the current status. What rofiles-fuse here is doing here is protecting is the hardlinked repo imports. But if `--cachedir` isn't specified, that repository gets thrown away anyways. So there's no real value to using FUSE here. Also since nothing is cached, disable the devino cache. We also make use of --force-copy-zerosized that just landed in libostree: https://github.com/ostreedev/ostree/pull/1752 Down the line ideally we gain the capability to detect if either unprivileged overlayfs/FUSE are available. Then if `--cachedir` is specified we can make things work. Closes: #1591 Approved by: jlebon
This commit is contained in:
parent
8ba5bda821
commit
b3f6f25637
@ -113,6 +113,7 @@ typedef struct {
|
||||
int workdir_dfd;
|
||||
int rootfs_dfd;
|
||||
int cachedir_dfd;
|
||||
gboolean unified_core_and_fuse;
|
||||
OstreeRepo *repo;
|
||||
OstreeRepo *pkgcache_repo;
|
||||
OstreeRepoDevInoCache *devino_cache;
|
||||
@ -340,9 +341,37 @@ install_packages_in_root (RpmOstreeTreeComposeContext *self,
|
||||
cancellable, error);
|
||||
if (!self->pkgcache_repo)
|
||||
return FALSE;
|
||||
|
||||
if (!opt_cachedir)
|
||||
{
|
||||
/* This is part of enabling rpm-ostree inside Docker/Kubernetes/OpenShift;
|
||||
* in this case we probably don't have access to FUSE as today it uses a
|
||||
* suid binary which doesn't have the capabilities it needs.
|
||||
*
|
||||
* So this magical bit tells the core to disable FUSE, which we only do
|
||||
* if --cachedir isn't specified. Another way to say this is that
|
||||
* running inside an unprivileged container today requires turning off
|
||||
* some of the rpm-ostree intelligence around caching.
|
||||
*
|
||||
* We don't make this actually conditional somehow on running in a
|
||||
* container since if you're not using a persistent cache there's no
|
||||
* real advantage to taking the overhead of FUSE. If the hardlinks are
|
||||
* corrupted, it doesn't matter as they're going to be deleted
|
||||
* anyways.
|
||||
*/
|
||||
rpmostree_context_disable_rofiles (self->corectx);
|
||||
}
|
||||
else
|
||||
{
|
||||
self->unified_core_and_fuse = TRUE;
|
||||
/* We also only enable the devino cache if we know we have the FUSE protection
|
||||
* against mutation of the underlying files.
|
||||
*/
|
||||
self->devino_cache = ostree_repo_devino_cache_new ();
|
||||
rpmostree_context_set_devino_cache (self->corectx, self->devino_cache);
|
||||
}
|
||||
|
||||
rpmostree_context_set_repos (self->corectx, self->repo, self->pkgcache_repo);
|
||||
self->devino_cache = ostree_repo_devino_cache_new ();
|
||||
rpmostree_context_set_devino_cache (self->corectx, self->devino_cache);
|
||||
|
||||
/* Ensure that the imported packages are labeled with *a* policy if
|
||||
* possible, even if it's not the final one. This helps avoid duplicating
|
||||
@ -886,7 +915,7 @@ impl_install_tree (RpmOstreeTreeComposeContext *self,
|
||||
|
||||
/* Start postprocessing */
|
||||
if (!rpmostree_treefile_postprocessing (self->rootfs_dfd, self->treefile_rs, self->treefile,
|
||||
next_version, opt_unified_core,
|
||||
next_version, self->unified_core_and_fuse,
|
||||
cancellable, error))
|
||||
return glnx_prefix_error (error, "Postprocessing");
|
||||
|
||||
@ -999,7 +1028,7 @@ impl_commit_tree (RpmOstreeTreeComposeContext *self,
|
||||
|
||||
if (!rpmostree_rootfs_postprocess_common (self->rootfs_dfd, cancellable, error))
|
||||
return FALSE;
|
||||
if (!rpmostree_postprocess_final (self->rootfs_dfd, self->treefile, opt_unified_core,
|
||||
if (!rpmostree_postprocess_final (self->rootfs_dfd, self->treefile, self->unified_core_and_fuse,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
|
@ -42,6 +42,7 @@ struct _RpmOstreeContext {
|
||||
RpmOstreeContextDnfCachePolicy dnf_cache_policy;
|
||||
OstreeRepo *ostreerepo;
|
||||
OstreeRepo *pkgcache_repo;
|
||||
gboolean enable_rofiles;
|
||||
OstreeRepoDevInoCache *devino_cache;
|
||||
gboolean unprivileged;
|
||||
OstreeSePolicy *sepolicy;
|
||||
|
@ -381,6 +381,7 @@ rpmostree_context_init (RpmOstreeContext *self)
|
||||
{
|
||||
self->tmprootfs_dfd = -1;
|
||||
self->dnf_cache_policy = RPMOSTREE_CONTEXT_DNF_CACHE_DEFAULT;
|
||||
self->enable_rofiles = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -555,11 +556,19 @@ void
|
||||
rpmostree_context_set_devino_cache (RpmOstreeContext *self,
|
||||
OstreeRepoDevInoCache *devino_cache)
|
||||
{
|
||||
g_assert (self->enable_rofiles);
|
||||
if (self->devino_cache)
|
||||
ostree_repo_devino_cache_unref (self->devino_cache);
|
||||
self->devino_cache = devino_cache ? ostree_repo_devino_cache_ref (devino_cache) : NULL;
|
||||
}
|
||||
|
||||
void
|
||||
rpmostree_context_disable_rofiles (RpmOstreeContext *self)
|
||||
{
|
||||
g_assert (!self->devino_cache);
|
||||
self->enable_rofiles = FALSE;
|
||||
}
|
||||
|
||||
DnfContext *
|
||||
rpmostree_context_get_dnf (RpmOstreeContext *self)
|
||||
{
|
||||
@ -2577,6 +2586,7 @@ checkout_package (OstreeRepo *repo,
|
||||
const char *pkg_commit,
|
||||
GHashTable *files_skip,
|
||||
OstreeRepoCheckoutOverwriteMode ovwmode,
|
||||
gboolean force_copy_zerosized,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
@ -2591,6 +2601,8 @@ checkout_package (OstreeRepo *repo,
|
||||
|
||||
/* Always want hardlinks */
|
||||
opts.no_copy_fallback = TRUE;
|
||||
/* Used in the no-rofiles-fuse path */
|
||||
opts.force_copy_zerosized = force_copy_zerosized;
|
||||
|
||||
if (files_skip && g_hash_table_size (files_skip) > 0)
|
||||
{
|
||||
@ -2632,6 +2644,7 @@ checkout_package_into_root (RpmOstreeContext *self,
|
||||
|
||||
if (!checkout_package (pkgcache_repo, dfd, path,
|
||||
devino_cache, pkg_commit, files_skip, ovwmode,
|
||||
!self->enable_rofiles,
|
||||
cancellable, error))
|
||||
return glnx_prefix_error (error, "Checkout %s", dnf_package_get_nevra (pkg));
|
||||
|
||||
@ -2887,7 +2900,7 @@ relabel_in_thread_impl (RpmOstreeContext *self,
|
||||
g_autoptr(OstreeRepoDevInoCache) cache = ostree_repo_devino_cache_new ();
|
||||
|
||||
if (!checkout_package (repo, tmpdir_dfd, pkg_dirname, cache,
|
||||
commit_csum, NULL, OSTREE_REPO_CHECKOUT_OVERWRITE_NONE,
|
||||
commit_csum, NULL, OSTREE_REPO_CHECKOUT_OVERWRITE_NONE, FALSE,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
@ -3256,7 +3269,7 @@ run_script_sync (RpmOstreeContext *self,
|
||||
return FALSE;
|
||||
|
||||
if (!rpmostree_script_run_sync (pkg, hdr, kind, rootfs_dfd, var_lib_rpm_statedir,
|
||||
out_n_run, cancellable, error))
|
||||
self->enable_rofiles, out_n_run, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
@ -3530,7 +3543,8 @@ run_all_transfiletriggers (RpmOstreeContext *self,
|
||||
Header hdr;
|
||||
while ((hdr = rpmdbNextIterator (mi)) != NULL)
|
||||
{
|
||||
if (!rpmostree_transfiletriggers_run_sync (hdr, rootfs_dfd, out_n_run,
|
||||
if (!rpmostree_transfiletriggers_run_sync (hdr, rootfs_dfd, self->enable_rofiles,
|
||||
out_n_run,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
@ -3549,8 +3563,8 @@ run_all_transfiletriggers (RpmOstreeContext *self,
|
||||
if (!get_package_metainfo (self, path, &hdr, NULL, error))
|
||||
return FALSE;
|
||||
|
||||
if (!rpmostree_transfiletriggers_run_sync (hdr, rootfs_dfd, out_n_run,
|
||||
cancellable, error))
|
||||
if (!rpmostree_transfiletriggers_run_sync (hdr, rootfs_dfd, self->enable_rofiles,
|
||||
out_n_run, cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
|
@ -121,6 +121,7 @@ void rpmostree_context_set_repos (RpmOstreeContext *self,
|
||||
OstreeRepo *pkgcache_repo);
|
||||
void rpmostree_context_set_devino_cache (RpmOstreeContext *self,
|
||||
OstreeRepoDevInoCache *devino_cache);
|
||||
void rpmostree_context_disable_rofiles (RpmOstreeContext *self);
|
||||
void rpmostree_context_set_sepolicy (RpmOstreeContext *self,
|
||||
OstreeSePolicy *sepolicy);
|
||||
|
||||
|
@ -296,6 +296,7 @@ dump_buffered_output_noerr (const char *prefix,
|
||||
static gboolean
|
||||
run_script_in_bwrap_container (int rootfs_fd,
|
||||
GLnxTmpDir *var_lib_rpm_statedir,
|
||||
gboolean enable_fuse,
|
||||
const char *name,
|
||||
const char *scriptdesc,
|
||||
const char *interp,
|
||||
@ -354,8 +355,10 @@ run_script_in_bwrap_container (int rootfs_fd,
|
||||
* See above for why we special case glibc.
|
||||
*/
|
||||
const gboolean is_glibc_locales = strcmp (pkg_script, "glibc-all-langpacks.posttrans") == 0;
|
||||
RpmOstreeBwrapMutability mutability =
|
||||
(is_glibc_locales || !enable_fuse) ? RPMOSTREE_BWRAP_MUTATE_FREELY : RPMOSTREE_BWRAP_MUTATE_ROFILES;
|
||||
bwrap = rpmostree_bwrap_new (rootfs_fd,
|
||||
is_glibc_locales ? RPMOSTREE_BWRAP_MUTATE_FREELY : RPMOSTREE_BWRAP_MUTATE_ROFILES,
|
||||
mutability,
|
||||
error);
|
||||
if (!bwrap)
|
||||
goto out;
|
||||
@ -473,6 +476,7 @@ impl_run_rpm_script (const KnownRpmScriptKind *rpmscript,
|
||||
Header hdr,
|
||||
int rootfs_fd,
|
||||
GLnxTmpDir *var_lib_rpm_statedir,
|
||||
gboolean enable_fuse,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
@ -541,7 +545,8 @@ impl_run_rpm_script (const KnownRpmScriptKind *rpmscript,
|
||||
}
|
||||
|
||||
guint64 start_time_ms = g_get_monotonic_time () / 1000;
|
||||
if (!run_script_in_bwrap_container (rootfs_fd, var_lib_rpm_statedir, dnf_package_get_name (pkg),
|
||||
if (!run_script_in_bwrap_container (rootfs_fd, var_lib_rpm_statedir, enable_fuse,
|
||||
dnf_package_get_name (pkg),
|
||||
rpmscript->desc, interp, script, script_arg,
|
||||
-1, cancellable, error))
|
||||
return glnx_prefix_error (error, "Running %s for %s", rpmscript->desc, dnf_package_get_name (pkg));
|
||||
@ -567,6 +572,7 @@ run_script (const KnownRpmScriptKind *rpmscript,
|
||||
Header hdr,
|
||||
int rootfs_fd,
|
||||
GLnxTmpDir *var_lib_rpm_statedir,
|
||||
gboolean enable_fuse,
|
||||
gboolean *out_did_run,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
@ -595,7 +601,7 @@ run_script (const KnownRpmScriptKind *rpmscript,
|
||||
|
||||
*out_did_run = TRUE;
|
||||
return impl_run_rpm_script (rpmscript, pkg, hdr, rootfs_fd, var_lib_rpm_statedir,
|
||||
cancellable, error);
|
||||
enable_fuse, cancellable, error);
|
||||
}
|
||||
|
||||
#ifdef BUILDOPT_HAVE_RPM_FILETRIGGERS
|
||||
@ -715,6 +721,7 @@ rpmostree_script_run_sync (DnfPackage *pkg,
|
||||
RpmOstreeScriptKind kind,
|
||||
int rootfs_fd,
|
||||
GLnxTmpDir *var_lib_rpm_statedir,
|
||||
gboolean enable_fuse,
|
||||
guint *out_n_run,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
@ -737,7 +744,7 @@ rpmostree_script_run_sync (DnfPackage *pkg,
|
||||
|
||||
gboolean did_run = FALSE;
|
||||
if (!run_script (scriptkind, pkg, hdr, rootfs_fd,
|
||||
var_lib_rpm_statedir,
|
||||
var_lib_rpm_statedir, enable_fuse,
|
||||
&did_run, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
@ -752,6 +759,7 @@ rpmostree_script_run_sync (DnfPackage *pkg,
|
||||
gboolean
|
||||
rpmostree_transfiletriggers_run_sync (Header hdr,
|
||||
int rootfs_fd,
|
||||
gboolean enable_fuse,
|
||||
guint *out_n_run,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
@ -906,7 +914,7 @@ rpmostree_transfiletriggers_run_sync (Header hdr,
|
||||
|
||||
/* Run it, and log the result */
|
||||
guint64 start_time_ms = g_get_monotonic_time () / 1000;
|
||||
if (!run_script_in_bwrap_container (rootfs_fd, NULL, pkg_name,
|
||||
if (!run_script_in_bwrap_container (rootfs_fd, NULL, enable_fuse, pkg_name,
|
||||
"%transfiletriggerin", interp, script, NULL,
|
||||
fileno (tmpf_file), cancellable, error))
|
||||
return FALSE;
|
||||
|
@ -63,6 +63,7 @@ rpmostree_script_run_sync (DnfPackage *pkg,
|
||||
RpmOstreeScriptKind kind,
|
||||
int rootfs_fd,
|
||||
GLnxTmpDir *var_lib_rpm_statedir,
|
||||
gboolean enable_rofiles,
|
||||
guint *out_n_run,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
@ -70,6 +71,7 @@ rpmostree_script_run_sync (DnfPackage *pkg,
|
||||
gboolean
|
||||
rpmostree_transfiletriggers_run_sync (Header hdr,
|
||||
int rootfs_fd,
|
||||
gboolean enable_rofiles,
|
||||
guint *out_n_run,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
@ -549,3 +549,16 @@ EOF
|
||||
post "semodule -n -i ${install_dir}/${name}.pp" \
|
||||
files "${install_dir}/${name}.pp"
|
||||
}
|
||||
|
||||
files_are_hardlinked() {
|
||||
inode1=$(stat -c %i $1)
|
||||
inode2=$(stat -c %i $2)
|
||||
test -n "${inode1}" && test -n "${inode2}"
|
||||
[ "${inode1}" == "${inode2}" ]
|
||||
}
|
||||
|
||||
assert_files_hardlinked() {
|
||||
if ! files_are_hardlinked "$1" "$2"; then
|
||||
fatal "Files '$1' and '$2' are not hardlinked"
|
||||
fi
|
||||
}
|
||||
|
@ -35,6 +35,21 @@ if ostree --repo=${repobuild} cat ${treeref} /usr/lib/tmpfiles.d/pkg-rpm.conf >
|
||||
fi
|
||||
echo "ok autovar"
|
||||
|
||||
# And verify we're not hardlinking zero-sized files since this path isn't using
|
||||
# rofiles-fuse
|
||||
co=${repobuild}/tmp/usr-etc
|
||||
ostree --repo=${repobuild} checkout -UHz --subpath=/usr/etc ${treeref} ${co}
|
||||
# Verify the files exist and are zero-sized
|
||||
for f in ${co}/sub{u,g}id; do
|
||||
test -f "$f"
|
||||
test '!' -s "$f"
|
||||
done
|
||||
if files_are_hardlinked ${co}/sub{u,g}id; then
|
||||
fatal "Hardlinked zero-sized files without cachedir"
|
||||
fi
|
||||
rm ${co} -rf
|
||||
echo "ok no cachedir zero-sized hardlinks"
|
||||
|
||||
# And redo it to trigger relabeling
|
||||
origrev=$(ostree --repo=${repobuild} rev-parse ${treeref})
|
||||
runcompose --force-nocache --ex-unified-core
|
||||
|
Loading…
Reference in New Issue
Block a user