Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lib: Rework composefs metadata, drop custom signatures #2891

Merged
merged 2 commits into from
Jun 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Makefile-libostree.am
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,9 @@ endif # USE_GPGME
symbol_files = $(top_srcdir)/src/libostree/libostree-released.sym

# Uncomment this include when adding new development symbols.
#if BUILDOPT_IS_DEVEL_BUILD
#symbol_files += $(top_srcdir)/src/libostree/libostree-devel.sym
#endif
if BUILDOPT_IS_DEVEL_BUILD
symbol_files += $(top_srcdir)/src/libostree/libostree-devel.sym
endif

# http://blog.jgc.org/2007/06/escaping-comma-and-space-in-gnu-make.html
wl_versionscript_arg = -Wl,--version-script=
Expand Down
1 change: 1 addition & 0 deletions Makefile-tests.am
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ _installed_or_uninstalled_test_scripts = \
tests/test-remote-add.sh \
tests/test-remote-headers.sh \
tests/test-remote-refs.sh \
tests/test-composefs.sh \
tests/test-commit-sign.sh \
tests/test-commit-timestamp.sh \
tests/test-export.sh \
Expand Down
1 change: 1 addition & 0 deletions apidoc/ostree-sections.txt
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,7 @@ ostree_repo_write_commit
ostree_repo_write_commit_with_time
ostree_repo_read_commit_detached_metadata
ostree_repo_write_commit_detached_metadata
ostree_repo_commit_add_composefs_metadata
OstreeRepoCheckoutAtOptions
ostree_repo_checkout_at_options_set_devino
OstreeRepoCheckoutMode
Expand Down
49 changes: 45 additions & 4 deletions docs/composefs.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ nav_order: 10

## composefs

The [composefs](github.com/containers/composefs) project is a new
The [composefs](https://github.com/containers/composefs) project is a new
hybrid Linux stacking filesystem that provides many benefits when
used for bootable host systems, such as a strong story for integrity.

Expand All @@ -22,12 +22,53 @@ At the current time, integration of composefs and ostree is experimental.
When building a disk image *or* to transition an existing system, run:

```
ostree config --repo=/ostree/repo set ex-integrity.composefs yes
ostree config --repo=/ostree/repo set ex-integrity.composefs true
```

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 also shared with the current `/ostree/repo/objects`.
composefs metadata file, with a "backing store" directory that is
shared with the current `/ostree/repo/objects`.

### Kernel argument ot-composefs

The `ostree-prepare-root` binary will look for a kernel argument called `ot-composefs`.

The default value is `maybe` (this will likely become a build and initramfs-configurable option)
in the future too.

The possible values are:

- `off`: Never use composefs
- `maybe`: Use composefs if supported and there is a composefs image in the deployment directory
- `on`: Require composefs
- `digest=<sha256>`: Require the mounted composefs image to have a particular digest
- `signed`: This option will be documented in the future; don't use it right now

### Injecting composefs digests

When generating an OSTree commit, there is a CLI switch `--generate-composefs-metadata`
and a corresponding C API `ostree_repo_commit_add_composefs_metadata`. This will
inject the composefs digest as metadata into the ostree commit under a metadata
key `ostree.composefs.v0`. Because an OSTree commit can be signed, this allows
covering the composefs fsverity digest with a signature.

At the current time, ostree does not directly support verifying the signature on
the commit object before mounting, but that is in progress.

## Requirements

The current default composefs integration in ostree does not have any requirements
from the underlying kernel and filesystem other than having the following
kernel options set:

- `CONFIG_OVERLAY_FS`
- `CONFIG_BLK_DEV_LOOP`
- `CONFIG_EROFS_FS`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need config for fs-verity too

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not technically a requirement right now is what I was getting at. (Hmm, we should probably have this in upstream composefs actually)


At the current time, there are no additional userspace runtime requirements.

## Status

**IMPORTANT** The integration with composefs is experimental and subject to change. Please
try it and report issues but do not deploy to production systems yet.
Expand All @@ -39,7 +80,7 @@ provides much stronger and more efficient integrity:

- composefs validates an entire filesystem tree, not just individual files
- composefs makes files actually read-only, whereas IMA does not by default
- composefs uses fs-verity which does on-demand verification
- composefs uses fs-verity which does on-demand verification (IMA by default does a full readahead of every file accessed, though IMA can also use fs-verity as a backend)

## Further references

Expand Down
5 changes: 5 additions & 0 deletions src/libostree/libostree-devel.sym
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
- uncomment the include in Makefile-libostree.am
*/

LIBOSTREE_2023.4 {
global:
ostree_repo_commit_add_composefs_metadata;
} LIBOSTREE_2023.1;

/* Stub section for the stable release *after* this development one; don't
* edit this other than to update the year. This is just a copy/paste
* source. Replace $LASTSTABLE with the last stable version, and $NEWVERSION
Expand Down
3 changes: 0 additions & 3 deletions src/libostree/ostree-repo-commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -2916,9 +2916,6 @@ add_auto_metadata (OstreeRepo *self, GVariant *original_metadata, OstreeRepoFile

add_size_index_to_metadata (self, builder);

if (!ostree_repo_commit_add_composefs_metadata (self, builder, repo_root, cancellable, error))
return NULL;

return g_variant_ref_sink (g_variant_builder_end (builder));
}

Expand Down
107 changes: 32 additions & 75 deletions src/libostree/ostree-repo-composefs.c
Original file line number Diff line number Diff line change
Expand Up @@ -566,89 +566,46 @@ ostree_repo_checkout_composefs (OstreeRepo *self, OstreeComposefsTarget *target,
#endif
}

#ifdef HAVE_COMPOSEFS
static gboolean
ostree_repo_commit_add_composefs_sig (OstreeRepo *self, GVariantBuilder *builder,
guchar *fsverity_digest, GCancellable *cancellable,
GError **error)
/**
* ostree_repo_commit_add_composefs_metadata:
* @self: Repo
* @format_version: Must be zero
* @dict: A GVariant builder of type a{sv}
* @repo_root: the target filesystem tree
* @cancellable: Cancellable
* @error: Error
*
* Compute the composefs digest for a filesystem tree
* and insert it into metadata for a commit object. The composefs
* digest covers the entire filesystem tree and can be verified by
* the composefs mount tooling.
*/
_OSTREE_PUBLIC
gboolean
ostree_repo_commit_add_composefs_metadata (OstreeRepo *self, guint format_version,
GVariantDict *dict, OstreeRepoFile *repo_root,
GCancellable *cancellable, GError **error)
{
g_autofree char *certfile = NULL;
g_autofree char *keyfile = NULL;
g_autoptr (GBytes) sig = NULL;
guchar digest_digest[LCFS_DIGEST_SIZE];

certfile
= g_key_file_get_string (self->config, _OSTREE_INTEGRITY_SECTION, "composefs-certfile", NULL);
keyfile
= g_key_file_get_string (self->config, _OSTREE_INTEGRITY_SECTION, "composefs-keyfile", NULL);

if (certfile == NULL && keyfile == NULL)
return TRUE;

if (certfile == NULL)
return glnx_throw (error, "Error signing compoosefs: keyfile specified but certfile is not");

if (keyfile == NULL)
return glnx_throw (error, "Error signing compoosefs: certfile specified but keyfile is not");

/* We sign not the fs-verity of the image file itself, but rather we sign a file containing
* the fs-verity digest. This may seem weird, but disconnecting the signature from the
* actual image itself has two major advantages:
* * We can read/mount the image (non-verified) even without the public key in
* the keyring.
* * We can apply fs-verity to the image during deploy without the public key in
* the keyring.
*
* This is important because during an update we don't have the public key loaded until
* we boot into the new initrd.
*/
#ifdef HAVE_COMPOSEFS
/* For now */
g_assert (format_version == 0);

if (lcfs_compute_fsverity_from_data (digest_digest, fsverity_digest, LCFS_DIGEST_SIZE) < 0)
return glnx_throw_errno (error);
/* Create a composefs image and put in deploy dir as .ostree.cfs */
g_autoptr (OstreeComposefsTarget) target = ostree_composefs_target_new ();

if (!_ostree_fsverity_sign (certfile, keyfile, digest_digest, &sig, cancellable, error))
if (!ostree_repo_checkout_composefs (self, target, repo_root, cancellable, error))
return FALSE;

g_variant_builder_add (builder, "{sv}", "ostree.composefs-sig", ot_gvariant_new_ay_bytes (sig));

return TRUE;
}
#endif

gboolean
ostree_repo_commit_add_composefs_metadata (OstreeRepo *self, GVariantBuilder *builder,
OstreeRepoFile *repo_root, GCancellable *cancellable,
GError **error)
{
gboolean add_metadata;

if (!ot_keyfile_get_boolean_with_default (self->config, _OSTREE_INTEGRITY_SECTION,
"composefs-add-metadata", FALSE, &add_metadata, error))
g_autofree guchar *fsverity_digest = NULL;
if (!ostree_composefs_target_write (target, -1, &fsverity_digest, cancellable, error))
return FALSE;

if (add_metadata)
{
#ifdef HAVE_COMPOSEFS
/* Create a composefs image and put in deploy dir as .ostree.cfs */
g_autoptr (OstreeComposefsTarget) target = ostree_composefs_target_new ();

if (!ostree_repo_checkout_composefs (self, target, repo_root, cancellable, error))
return FALSE;
g_variant_dict_insert_value (
dict, OSTREE_COMPOSEFS_DIGEST_KEY_V0,
ot_gvariant_new_bytearray (fsverity_digest, OSTREE_SHA256_DIGEST_LEN));

g_autofree guchar *fsverity_digest = NULL;
if (!ostree_composefs_target_write (target, -1, &fsverity_digest, cancellable, error))
return FALSE;

g_variant_builder_add (builder, "{sv}", "ostree.composefs",
ot_gvariant_new_bytearray (fsverity_digest, OSTREE_SHA256_DIGEST_LEN));

if (!ostree_repo_commit_add_composefs_sig (self, builder, fsverity_digest, cancellable,
error))
return FALSE;
return TRUE;
#else
return composefs_not_supported (error);
return composefs_not_supported (error);
#endif
}

return TRUE;
}
12 changes: 5 additions & 7 deletions src/libostree/ostree-repo-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ G_BEGIN_DECLS
#define OSTREE_COMMIT_TIMESTAMP "ostree.commit.timestamp"
#define OSTREE_COMMIT_VERSION "ostree.commit.version"

// The metadata key for composefs
#define OSTREE_COMPOSEFS_META_PREFIX "ostree.composefs"
// The fs-verity digest of the composefs, version 0
#define OSTREE_COMPOSEFS_DIGEST_KEY_V0 OSTREE_COMPOSEFS_META_PREFIX ".digest.v0"

#define _OSTREE_INTEGRITY_SECTION "ex-integrity"

typedef enum
Expand Down Expand Up @@ -399,9 +404,6 @@ gboolean _ostree_tmpf_fsverity_core (GLnxTmpfile *tmpf, _OstreeFeatureSupport fs

gboolean _ostree_tmpf_fsverity (OstreeRepo *self, GLnxTmpfile *tmpf, GBytes *signature,
GError **error);
gboolean _ostree_fsverity_sign (const char *certfile, const char *keyfile,
const guchar *fsverity_digest, GBytes **data_out,
GCancellable *cancellable, GError **error);

gboolean _ostree_repo_verify_bindings (const char *collection_id, const char *ref_name,
GVariant *commit, GError **error);
Expand Down Expand Up @@ -465,10 +467,6 @@ gboolean ostree_repo_checkout_composefs (OstreeRepo *self, OstreeComposefsTarget
OstreeRepoFile *source, GCancellable *cancellable,
GError **error);

gboolean ostree_repo_commit_add_composefs_metadata (OstreeRepo *self, GVariantBuilder *builder,
OstreeRepoFile *repo_root,
GCancellable *cancellable, GError **error);

G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeComposefsTarget, ostree_composefs_target_unref)

G_END_DECLS
Loading