From 95b13de17a0be05257923cbb45f88c9e9781cbc5 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Thu, 9 Jan 2025 10:55:27 -0500 Subject: [PATCH] Always generate composefs blob, don't enable runtime by default Followup to https://github.com/ostreedev/ostree/pull/3353/commits/9a0acd7249bb0c7f55c2bf56e5073902cd60038b Basically our composefs enablement flag has long had a tension between trying to do two things: - Enable generating the composefs blob (at deployment time) - Enable at runtime in prepare-root And we've hit issues in "ratcheting" enabling composefs across upgrades because of this. This change builds on the previous one, and now it's really simple to talk about: - If composefs is enabled at build time, we *always* generate a composefs blob at deplyment time - Configuring the prepare-root config now mostly only affects the runtime state. There is one detail though: in order to handle the verity requirement at deploy time, we do still parse the config then. But for the basic "is composefs enabled at all at runtime" that is now fully keyed off the config, not the build time or (worse) whether the deployment happened to have a composefs blob. For users who want composefs on, they need to do so in the base image configuration. Signed-off-by: Colin Walters --- docs/composefs.md | 22 ++++++------ man/ostree-prepare-root.xml | 7 +++- src/libostree/ostree-sysroot-deploy.c | 49 ++++++++++++--------------- src/libotcore/otcore-prepare-root.c | 2 +- tests/test-admin-deploy-composefs.sh | 9 ++--- 5 files changed, 44 insertions(+), 45 deletions(-) diff --git a/docs/composefs.md b/docs/composefs.md index 513fdb2193..f575a73d29 100644 --- a/docs/composefs.md +++ b/docs/composefs.md @@ -21,22 +21,20 @@ At the current time, integration of composefs and ostree is experimental. ### Enabling composefs (unsigned) -When building a disk image *or* to transition an existing system, run: +If ostree is compiled with composefs support, then a composefs file +corresponding to the deployment tree will be generated by default. + +The `ostree-prepare-root` binary will look for `ostree/prepare-root.conf` in `/etc` and +`/usr/lib` in the initramfs. Using that configuration file you can enable composefs. +This configuration will enable an "unsigned" mode, which does not require fsverity, +but does make the system more resilient to accidental mutation. ``` -ostree config --repo=/ostree/repo set ex-integrity.composefs true +[composefs] +enabled = yes ``` -This will ensure that any future deployments (e.g. created by `ostree admin upgrade`) -have a `.ostree.cfs` file in the deployment directory which is a mountable -composefs metadata file, with a "backing store" directory that is -shared with the current `/ostree/repo/objects`. - -### composefs configuration - -The `ostree-prepare-root` binary will look for `ostree/prepare-root.conf` in `/etc` and -`/usr/lib` in the initramfs. Using that configuration file you can enable composefs, -and specify an Ed25519 public key to validate the booted commit. +You can also specify an Ed25519 public key to validate the booted commit. See the manpage for `ostree-prepare-root` for details of how to configure it. diff --git a/man/ostree-prepare-root.xml b/man/ostree-prepare-root.xml index 4a84863e45..c1f39a8a26 100644 --- a/man/ostree-prepare-root.xml +++ b/man/ostree-prepare-root.xml @@ -151,7 +151,12 @@ License along with this library. If not, see . the integrity of its backing OSTree object is validated by the digest stored in the image. Additionally, if set to signed, boot will fail if the image cannot be validated by a public key. - Setting this to maybe is currently equivalent to no. + Setting this to maybe will cause composefs to be used at runtime only + if the deployment has a composefs generated, which causes unpredicable and confusing semantics + and is not recommended. In practice with the current version of ostree, + in the case where composefs is enabled at build time for both the version that made the + deployment (often an older OS version), this will be equivalent to yes. + But in general one either wants composefs or not, so choose an explicit value for that. diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c index 3d382a6fcf..2d8705d5c8 100644 --- a/src/libostree/ostree-sysroot-deploy.c +++ b/src/libostree/ostree-sysroot-deploy.c @@ -669,33 +669,28 @@ checkout_deployment_tree (OstreeSysroot *sysroot, OstreeRepo *repo, OstreeDeploy guint64 composefs_start_time = 0; guint64 composefs_end_time = 0; #ifdef HAVE_COMPOSEFS - if (composefs_enabled != OT_TRISTATE_NO) - { - composefs_start_time = g_get_monotonic_time (); - // TODO: Clean up our mess around composefs/fsverity...we have duplication - // between the repo config and the sysroot config, *and* we need to better - // handle skew between repo config and repo state (e.g. "post-copy" should - // support transitioning verity on and off in general). - // For now we configure things such that the fsverity digest is only added - // if present on disk in the unsigned case, and in the signed case unconditionally - // require it. - g_auto (GVariantBuilder) cfs_checkout_opts_builder - = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT); - guint32 composefs_requested = 1; - if (composefs_config->require_verity) - composefs_requested = 2; - g_variant_builder_add (&cfs_checkout_opts_builder, "{sv}", "verity", - g_variant_new_uint32 (composefs_requested)); - g_debug ("composefs requested: %u", composefs_requested); - g_autoptr (GVariant) cfs_checkout_opts - = g_variant_ref_sink (g_variant_builder_end (&cfs_checkout_opts_builder)); - if (!ostree_repo_checkout_composefs (repo, cfs_checkout_opts, ret_deployment_dfd, - OSTREE_COMPOSEFS_NAME, csum, cancellable, error)) - return FALSE; - composefs_end_time = g_get_monotonic_time (); - } - else - g_debug ("not using composefs"); + composefs_start_time = g_get_monotonic_time (); + // TODO: Clean up our mess around composefs/fsverity...we have duplication + // between the repo config and the sysroot config, *and* we need to better + // handle skew between repo config and repo state (e.g. "post-copy" should + // support transitioning verity on and off in general). + // For now we configure things such that the fsverity digest is only added + // if present on disk in the unsigned case, and in the signed case unconditionally + // require it. + g_auto (GVariantBuilder) cfs_checkout_opts_builder + = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT); + guint32 composefs_requested = 1; + if (composefs_config->require_verity) + composefs_requested = 2; + g_variant_builder_add (&cfs_checkout_opts_builder, "{sv}", "verity", + g_variant_new_uint32 (composefs_requested)); + g_debug ("composefs requested: %u", composefs_requested); + g_autoptr (GVariant) cfs_checkout_opts + = g_variant_ref_sink (g_variant_builder_end (&cfs_checkout_opts_builder)); + if (!ostree_repo_checkout_composefs (repo, cfs_checkout_opts, ret_deployment_dfd, + OSTREE_COMPOSEFS_NAME, csum, cancellable, error)) + return FALSE; + composefs_end_time = g_get_monotonic_time (); #else if (composefs_enabled == OT_TRISTATE_YES) return glnx_throw (error, "composefs: enabled at runtime, but support is not compiled in"); diff --git a/src/libotcore/otcore-prepare-root.c b/src/libotcore/otcore-prepare-root.c index 90b9905487..43fe1e9063 100644 --- a/src/libotcore/otcore-prepare-root.c +++ b/src/libotcore/otcore-prepare-root.c @@ -189,7 +189,7 @@ otcore_load_composefs_config (const char *cmdline, GKeyFile *config, gboolean lo } else if (!ot_keyfile_get_tristate_with_default (config, OTCORE_PREPARE_ROOT_COMPOSEFS_KEY, OTCORE_PREPARE_ROOT_ENABLED_KEY, - OT_TRISTATE_MAYBE, &ret->enabled, error)) + OT_TRISTATE_NO, &ret->enabled, error)) return NULL; // Look for a key - we default to the initramfs binding path. diff --git a/tests/test-admin-deploy-composefs.sh b/tests/test-admin-deploy-composefs.sh index ff20005d70..950e8da0a9 100755 --- a/tests/test-admin-deploy-composefs.sh +++ b/tests/test-admin-deploy-composefs.sh @@ -38,10 +38,10 @@ cd - ${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-string version=1.composefs -b testos/buildmain/x86_64-runtime osdata ${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmain/x86_64-runtime +# We generate the blob now, even if it's explicitly runtime disabled ${CMD_PREFIX} ostree admin deploy --os=testos --karg=root=LABEL=foo --karg=testkarg=1 testos:testos/buildmain/x86_64-runtime -if test -f sysroot/ostree/deploy/testos/deploy/*.0/.ostree.cfs; then - fatal "found composefs unexpectedly" -fi +cfs_count=$(ls sysroot/ostree/deploy/testos/deploy/*.0/.ostree.cfs | wc -l) +assert_streq "${cfs_count}" "1" # check explicit enablement cd osdata @@ -55,7 +55,8 @@ ${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-str ${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmain/x86_64-runtime ${CMD_PREFIX} ostree admin deploy --os=testos --karg=root=LABEL=foo --karg=testkarg=1 testos:testos/buildmain/x86_64-runtime -ls sysroot/ostree/deploy/testos/deploy/*.0/.ostree.cfs +cfs_count=$(ls sysroot/ostree/deploy/testos/deploy/*.0/.ostree.cfs | wc -l) +assert_streq "${cfs_count}" "2" tap_ok composefs