prepare-root: Support using composefs as root filesystem

This changes ostree-prepare-root to use the .ostree.cfs image as a
composefs filesystem, instead of the checkout.

By default, composefs is used if support is built in and the .ostree.cfs
file exists in the deploy dir, otherwise we fall back to the old
method. However, if the ot-composefs kernel option is specified this
can be tweaked as per:
 * off: Never use composefsz
 * maybe: Use if possible
 * on: Fail if not possible
 * signed: Fail if the cfs image is not fs-verity signed with
   a key in the keyring.
 * digest=....: Fail if the cfs image does not match the specified
   digest.

The final layout when composefs is active is:

 /        ro overlayfs mount for composefs
 /sysroot "real" root
 /etc     rw bind mount to $deploydir/etc
 /var     rw bind mount to $vardir

We also specify the $deploydir/.ostree-mnt directory as the (internal)
mountpoint for the erofs mount for composefs. This can be used to map
the root fs back to the deploy id/dir in use,

A further note: I didn't test the .usr-ovl-work overlayfs case, but a
comment mentions that you can't mount overlayfs on top of a readonly
mount. That seems incompatible with composefs. If this is needed we
have to merge that with the overlayfs that composefs itself sets up,
which is possible with the libcomposefs APIs.
This commit is contained in:
Alexander Larsson 2022-06-30 14:53:13 +02:00
parent bba3109fe2
commit 11d7587e40
2 changed files with 90 additions and 4 deletions

View File

@ -27,7 +27,9 @@ ostree_prepare_root_SOURCES = \
src/switchroot/ostree-mount-util.h \
src/switchroot/ostree-prepare-root.c \
$(NULL)
ostree_prepare_root_CFLAGS =
ostree_prepare_root_CPPFLAGS = $(AM_CPPFLAGS)
ostree_prepare_root_LDADD =
if BUILDOPT_USE_STATIC_COMPILER
# ostree-prepare-root can be used as init in a system without a populated /lib.
@ -43,10 +45,10 @@ if BUILDOPT_USE_STATIC_COMPILER
ostree_boot_SCRIPTS += ostree-prepare-root
ostree-prepare-root : $(ostree_prepare_root_SOURCES)
$(STATIC_COMPILER) -o $@ -static $(top_srcdir)/src/switchroot/ostree-prepare-root.c $(ostree_prepare_root_CPPFLAGS) $(AM_CFLAGS) $(DEFAULT_INCLUDES) -DOSTREE_PREPARE_ROOT_STATIC=1
$(STATIC_COMPILER) -o $@ -static $(top_srcdir)/src/switchroot/ostree-prepare-root.c $(ostree_prepare_root_CPPFLAGS) $(AM_CFLAGS) $(DEFAULT_INCLUDES) $(OT_DEP_COMPOSEFS_CFLAGS) $(OT_DEP_COMPOSEFS_LIBS) -DOSTREE_PREPARE_ROOT_STATIC=1
else
ostree_boot_PROGRAMS += ostree-prepare-root
ostree_prepare_root_CFLAGS = $(AM_CFLAGS) -Isrc/switchroot
ostree_prepare_root_CFLAGS += $(AM_CFLAGS) -Isrc/switchroot
endif
ostree_remount_SOURCES = \
@ -56,9 +58,14 @@ ostree_remount_SOURCES = \
ostree_remount_CPPFLAGS = $(AM_CPPFLAGS) $(OT_INTERNAL_GIO_UNIX_CFLAGS) -Isrc/switchroot -I$(srcdir)/libglnx
ostree_remount_LDADD = $(AM_LDFLAGS) $(OT_INTERNAL_GIO_UNIX_LIBS) libglnx.la
if USE_COMPOSEFS
ostree_prepare_root_CFLAGS += $(OT_DEP_COMPOSEFS_CFLAGS)
ostree_prepare_root_LDADD += $(OT_DEP_COMPOSEFS_LIBS)
endif
if BUILDOPT_SYSTEMD
ostree_prepare_root_CPPFLAGS += -DHAVE_SYSTEMD=1
ostree_prepare_root_LDADD = $(AM_LDFLAGS) $(LIBSYSTEMD_LIBS)
ostree_prepare_root_LDADD += $(AM_LDFLAGS) $(LIBSYSTEMD_LIBS)
endif
# This is the "new mode" of using a generator for /var; see

View File

@ -86,8 +86,21 @@
// A temporary mount point
#define TMP_SYSROOT "/sysroot.tmp"
#ifdef HAVE_COMPOSEFS
#include <libcomposefs/lcfs-mount.h>
#endif
#include "ostree-mount-util.h"
typedef enum
{
OSTREE_COMPOSEFS_MODE_OFF, /* Never use composefs */
OSTREE_COMPOSEFS_MODE_MAYBE, /* Use if supported and image exists in deploy */
OSTREE_COMPOSEFS_MODE_ON, /* Always use (and fail if not working) */
OSTREE_COMPOSEFS_MODE_SIGNED, /* Always use and require it to be signed */
OSTREE_COMPOSEFS_MODE_DIGEST, /* Always use and require specific digest */
} OstreeComposefsMode;
static inline bool
sysroot_is_configured_ro (const char *sysroot)
{
@ -227,6 +240,34 @@ main (int argc, char *argv[])
err (EXIT_FAILURE, "failed to umount proc from /proc");
}
OstreeComposefsMode composefs_mode = OSTREE_COMPOSEFS_MODE_MAYBE;
char *ot_composefs = read_proc_cmdline_key ("ot-composefs");
char *composefs_digest = NULL;
if (ot_composefs)
{
if (strcmp (ot_composefs, "off") == 0)
composefs_mode = OSTREE_COMPOSEFS_MODE_OFF;
else if (strcmp (ot_composefs, "maybe") == 0)
composefs_mode = OSTREE_COMPOSEFS_MODE_MAYBE;
else if (strcmp (ot_composefs, "on") == 0)
composefs_mode = OSTREE_COMPOSEFS_MODE_ON;
else if (strcmp (ot_composefs, "signed") == 0)
composefs_mode = OSTREE_COMPOSEFS_MODE_SIGNED;
else if (strncmp (ot_composefs, "digest=", strlen ("digest=")) == 0)
{
composefs_mode = OSTREE_COMPOSEFS_MODE_DIGEST;
composefs_digest = ot_composefs + strlen ("digest=");
}
else
err (EXIT_FAILURE, "Unsupported ot-composefs option: '%s'", ot_composefs);
}
#ifndef HAVE_COMPOSEFS
if (composefs_mode == OSTREE_COMPOSEFS_MODE_MAYBE)
composefs_mode = OSTREE_COMPOSEFS_MODE_OFF;
(void)composefs_digest;
#endif
/* Query the repository configuration - this is an operating system builder
* choice. More info: https://github.com/ostreedev/ostree/pull/1767
*/
@ -254,9 +295,47 @@ main (int argc, char *argv[])
if (chdir (deploy_path) < 0)
err (EXIT_FAILURE, "failed to chdir to deploy_path");
/* Currently always false */
bool using_composefs = false;
/* We construct the new sysroot in /sysroot.tmp, which is either the composfs
mount or a bind mount of the deploy-dir */
if (composefs_mode != OSTREE_COMPOSEFS_MODE_OFF)
{
#ifdef HAVE_COMPOSEFS
const char *objdirs[] = { "/sysroot/ostree/repo/objects" };
struct lcfs_mount_options_s cfs_options = {
objdirs,
1,
};
cfs_options.flags = LCFS_MOUNT_FLAGS_READONLY;
if (snprintf (srcpath, sizeof (srcpath), "%s/.ostree.mnt", deploy_path) < 0)
err (EXIT_FAILURE, "failed to assemble /boot/loader path");
cfs_options.image_mountdir = srcpath;
if (composefs_mode == OSTREE_COMPOSEFS_MODE_SIGNED)
{
cfs_options.flags |= LCFS_MOUNT_FLAGS_REQUIRE_SIGNATURE | LCFS_MOUNT_FLAGS_REQUIRE_VERITY;
}
else if (composefs_mode == OSTREE_COMPOSEFS_MODE_DIGEST)
{
cfs_options.flags |= LCFS_MOUNT_FLAGS_REQUIRE_VERITY;
cfs_options.expected_digest = composefs_digest;
}
if (lcfs_mount_image (".ostree.cfs", "/sysroot.tmp", &cfs_options) < 0)
{
if (composefs_mode > OSTREE_COMPOSEFS_MODE_MAYBE)
err (EXIT_FAILURE, "Failed to mount composefs");
}
else
using_composefs = 1;
#else
err (EXIT_FAILURE, "Composefs not supported");
#endif
}
if (!using_composefs)
{
/* The deploy root starts out bind mounted to sysroot.tmp */