From a6f2d053c89657a4542286d13460a7ef3c632bb4 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Fri, 16 Jun 2023 15:35:50 -0400 Subject: [PATCH] lib: Rework composefs metadata, drop custom signatures We will be switching to handling signature verification of the target ostree commit. --- Makefile-libostree.am | 6 +- Makefile-tests.am | 1 + apidoc/ostree-sections.txt | 1 + src/libostree/libostree-devel.sym | 5 + src/libostree/ostree-repo-commit.c | 3 - src/libostree/ostree-repo-composefs.c | 107 +++++++-------------- src/libostree/ostree-repo-private.h | 12 +-- src/libostree/ostree-repo-verity.c | 128 ------------------------- src/libostree/ostree-repo.h | 5 + src/libostree/ostree-sysroot-deploy.c | 32 +------ src/ostree/ot-builtin-commit.c | 15 +++ src/switchroot/ostree-prepare-root.c | 130 +------------------------- tests/test-composefs.sh | 39 ++++++++ 13 files changed, 109 insertions(+), 375 deletions(-) create mode 100755 tests/test-composefs.sh diff --git a/Makefile-libostree.am b/Makefile-libostree.am index 8edd7f4d..438741de 100644 --- a/Makefile-libostree.am +++ b/Makefile-libostree.am @@ -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= diff --git a/Makefile-tests.am b/Makefile-tests.am index 32817704..dfed9c18 100644 --- a/Makefile-tests.am +++ b/Makefile-tests.am @@ -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 \ diff --git a/apidoc/ostree-sections.txt b/apidoc/ostree-sections.txt index a0db55c7..af57d7c9 100644 --- a/apidoc/ostree-sections.txt +++ b/apidoc/ostree-sections.txt @@ -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 diff --git a/src/libostree/libostree-devel.sym b/src/libostree/libostree-devel.sym index 9168db73..ec416c81 100644 --- a/src/libostree/libostree-devel.sym +++ b/src/libostree/libostree-devel.sym @@ -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 diff --git a/src/libostree/ostree-repo-commit.c b/src/libostree/ostree-repo-commit.c index d9ea2901..1bc3394b 100644 --- a/src/libostree/ostree-repo-commit.c +++ b/src/libostree/ostree-repo-commit.c @@ -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)); } diff --git a/src/libostree/ostree-repo-composefs.c b/src/libostree/ostree-repo-composefs.c index 330b0cf4..623a3fc9 100644 --- a/src/libostree/ostree-repo-composefs.c +++ b/src/libostree/ostree-repo-composefs.c @@ -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; } diff --git a/src/libostree/ostree-repo-private.h b/src/libostree/ostree-repo-private.h index 76f3152b..6d3f21e6 100644 --- a/src/libostree/ostree-repo-private.h +++ b/src/libostree/ostree-repo-private.h @@ -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 @@ -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); @@ -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 diff --git a/src/libostree/ostree-repo-verity.c b/src/libostree/ostree-repo-verity.c index 512386a9..6a7130c8 100644 --- a/src/libostree/ostree-repo-verity.c +++ b/src/libostree/ostree-repo-verity.c @@ -206,131 +206,3 @@ _ostree_tmpf_fsverity (OstreeRepo *self, GLnxTmpfile *tmpf, GBytes *signature, G #endif return TRUE; } - -#if defined(HAVE_OPENSSL) -static gboolean -read_pem_x509_certificate (const char *certfile, X509 **cert_ret, GError **error) -{ - g_autoptr (BIO) bio = NULL; - X509 *cert; - - errno = 0; - bio = BIO_new_file (certfile, "r"); - if (!bio) - return glnx_throw_errno_prefix (error, "Error loading composefs certfile '%s'", certfile); - - cert = PEM_read_bio_X509 (bio, NULL, NULL, NULL); - if (!cert) - return glnx_throw (error, "Error parsing composefs certfile '%s'", certfile); - - *cert_ret = cert; - return TRUE; -} - -static gboolean -read_pem_pkcs8_private_key (const char *keyfile, EVP_PKEY **pkey_ret, GError **error) -{ - g_autoptr (BIO) bio; - EVP_PKEY *pkey; - - errno = 0; - bio = BIO_new_file (keyfile, "r"); - if (!bio) - return glnx_throw_errno_prefix (error, "Error loading composefs keyfile '%s'", keyfile); - - pkey = PEM_read_bio_PrivateKey (bio, NULL, NULL, NULL); - if (!pkey) - return glnx_throw (error, "Error parsing composefs keyfile '%s'", keyfile); - - *pkey_ret = pkey; - return TRUE; -} - -static gboolean -sign_pkcs7 (const void *data_to_sign, size_t data_size, EVP_PKEY *pkey, X509 *cert, - const EVP_MD *md, BIO **res, GError **error) -{ - int pkcs7_flags = PKCS7_BINARY | PKCS7_DETACHED | PKCS7_NOATTR | PKCS7_NOCERTS | PKCS7_PARTIAL; - g_autoptr (BIO) bio = NULL; - g_autoptr (BIO) bio_res = NULL; - g_autoptr (PKCS7) p7 = NULL; - - bio = BIO_new_mem_buf ((void *)data_to_sign, data_size); - if (!bio) - return glnx_throw (error, "Can't allocate buffer"); - - p7 = PKCS7_sign (NULL, NULL, NULL, bio, pkcs7_flags); - if (!p7) - return glnx_throw (error, "Can't initialize PKCS#7"); - - if (!PKCS7_sign_add_signer (p7, cert, pkey, md, pkcs7_flags)) - return glnx_throw (error, "Can't add signer to PKCS#7"); - - if (PKCS7_final (p7, bio, pkcs7_flags) != 1) - return glnx_throw (error, "Can't finalize PKCS#7"); - - bio_res = BIO_new (BIO_s_mem ()); - if (!bio_res) - return glnx_throw (error, "Can't allocate buffer"); - - if (i2d_PKCS7_bio (bio_res, p7) != 1) - return glnx_throw (error, "Can't DER-encode PKCS#7 signature object"); - - *res = g_steal_pointer (&bio_res); - return TRUE; -} - -gboolean -_ostree_fsverity_sign (const char *certfile, const char *keyfile, const guchar *fsverity_digest, - GBytes **data_out, GCancellable *cancellable, GError **error) -{ - g_autofree struct fsverity_formatted_digest *d = NULL; - gsize d_size; - g_autoptr (X509) cert = NULL; - g_autoptr (EVP_PKEY) pkey = NULL; - g_autoptr (BIO) bio_sig = NULL; - const EVP_MD *md; - guchar *sig; - long sig_size; - - if (certfile == NULL) - return glnx_throw (error, "certfile not specified"); - - if (keyfile == NULL) - return glnx_throw (error, "keyfile not specified"); - - if (!read_pem_x509_certificate (certfile, &cert, error)) - return FALSE; - - if (!read_pem_pkcs8_private_key (keyfile, &pkey, error)) - return FALSE; - - md = EVP_sha256 (); - if (md == NULL) - return glnx_throw (error, "No sha256 support in openssl"); - - d_size = sizeof (struct fsverity_formatted_digest) + OSTREE_SHA256_DIGEST_LEN; - d = g_malloc0 (d_size); - - memcpy (d->magic, "FSVerity", 8); - d->digest_algorithm = GUINT16_TO_LE (FS_VERITY_HASH_ALG_SHA256); - d->digest_size = GUINT16_TO_LE (OSTREE_SHA256_DIGEST_LEN); - memcpy (d->digest, fsverity_digest, OSTREE_SHA256_DIGEST_LEN); - - if (!sign_pkcs7 (d, d_size, pkey, cert, md, &bio_sig, error)) - return FALSE; - - sig_size = BIO_get_mem_data (bio_sig, &sig); - - *data_out = g_bytes_new (sig, sig_size); - - return TRUE; -} -#else -gboolean -_ostree_fsverity_sign (const char *certfile, const char *keyfile, const guchar *fsverity_digest, - GBytes **data_out, GCancellable *cancellable, GError **error) -{ - return glnx_throw (error, "fsverity signature support not built"); -} -#endif diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h index 1e6b3202..2dea9092 100644 --- a/src/libostree/ostree-repo.h +++ b/src/libostree/ostree-repo.h @@ -690,6 +690,11 @@ _OSTREE_PUBLIC gboolean ostree_repo_write_mtree (OstreeRepo *self, OstreeMutableTree *mtree, GFile **out_file, GCancellable *cancellable, GError **error); +_OSTREE_PUBLIC +gboolean ostree_repo_commit_add_composefs_metadata (OstreeRepo *self, guint format_version, + GVariantDict *dict, OstreeRepoFile *repo_root, + GCancellable *cancellable, GError **error); + _OSTREE_PUBLIC gboolean ostree_repo_write_commit (OstreeRepo *self, const char *parent, const char *subject, const char *body, GVariant *metadata, OstreeRepoFile *root, diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c index 8920fd70..8fcd5e80 100644 --- a/src/libostree/ostree-sysroot-deploy.c +++ b/src/libostree/ostree-sysroot-deploy.c @@ -659,10 +659,8 @@ checkout_deployment_tree (OstreeSysroot *sysroot, OstreeRepo *repo, OstreeDeploy return FALSE; g_autoptr (GVariant) metadata = g_variant_get_child_value (commit_variant, 0); - g_autoptr (GVariant) metadata_composefs - = g_variant_lookup_value (metadata, "ostree.composefs", G_VARIANT_TYPE_BYTESTRING); - g_autoptr (GVariant) metadata_composefs_sig - = g_variant_lookup_value (metadata, "ostree.composefs-sig", G_VARIANT_TYPE_BYTESTRING); + g_autoptr (GVariant) metadata_composefs = g_variant_lookup_value ( + metadata, OSTREE_COMPOSEFS_DIGEST_KEY_V0, G_VARIANT_TYPE_BYTESTRING); /* Create a composefs image and put in deploy dir as .ostree.cfs */ g_autoptr (OstreeComposefsTarget) target = ostree_composefs_target_new (); @@ -695,32 +693,6 @@ checkout_deployment_tree (OstreeSysroot *sysroot, OstreeRepo *repo, OstreeDeploy if (!_ostree_tmpf_fsverity (repo, &tmpf, NULL, error)) return FALSE; - if (metadata_composefs && metadata_composefs_sig) - { - g_autofree char *composefs_digest_path - = g_strdup_printf ("%s/.ostree.cfs.digest", checkout_target_name); - g_autofree char *composefs_sig_path - = g_strdup_printf ("%s/.ostree.cfs.sig", checkout_target_name); - g_autoptr (GBytes) digest = g_variant_get_data_as_bytes (metadata_composefs); - g_autoptr (GBytes) sig = g_variant_get_data_as_bytes (metadata_composefs_sig); - - if (!glnx_file_replace_contents_at (osdeploy_dfd, composefs_digest_path, - g_bytes_get_data (digest, NULL), - g_bytes_get_size (digest), 0, cancellable, error)) - return FALSE; - - if (!glnx_file_replace_contents_at (osdeploy_dfd, composefs_sig_path, - g_bytes_get_data (sig, NULL), g_bytes_get_size (sig), - 0, cancellable, error)) - return FALSE; - - /* The signature should be applied as a fs-verity signature to the digest file. However - * we can't do that until boot, because we can't guarantee that the public key is - * loaded into the keyring until we boot the new initrd. So the signature is applied - * in ostree-prepare-root on first boot. - */ - } - if (!glnx_link_tmpfile_at (&tmpf, GLNX_LINK_TMPFILE_REPLACE, osdeploy_dfd, composefs_cfs_path, error)) return FALSE; diff --git a/src/ostree/ot-builtin-commit.c b/src/ostree/ot-builtin-commit.c index 8f56779f..76049671 100644 --- a/src/ostree/ot-builtin-commit.c +++ b/src/ostree/ot-builtin-commit.c @@ -70,6 +70,7 @@ static char *opt_gpg_homedir; static char **opt_key_ids; static char *opt_sign_name; static gboolean opt_generate_sizes; +static gboolean opt_composefs_metadata; static gboolean opt_disable_fsync; static char *opt_timestamp; @@ -161,6 +162,8 @@ static GOptionEntry options[] = { "Signature type to use (defaults to 'ed25519')", "NAME" }, { "generate-sizes", 0, 0, G_OPTION_ARG_NONE, &opt_generate_sizes, "Generate size information along with commit metadata", NULL }, + { "generate-composefs-metadata", 0, 0, G_OPTION_ARG_NONE, &opt_composefs_metadata, + "Generate composefs commit metadata", NULL }, { "disable-fsync", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL }, { "fsync", 0, 0, G_OPTION_ARG_CALLBACK, parse_fsync_cb, "Specify how to invoke fsync()", @@ -872,6 +875,18 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio metadata = g_variant_ref_sink (g_variant_dict_end (&bootmeta)); } + if (opt_composefs_metadata) + { + g_autoptr (GVariant) old_metadata = g_steal_pointer (&metadata); + g_auto (GVariantDict) newmeta; + g_variant_dict_init (&newmeta, old_metadata); + if (!ostree_repo_commit_add_composefs_metadata ( + repo, 0, &newmeta, OSTREE_REPO_FILE (root), cancellable, error)) + goto out; + + metadata = g_variant_ref_sink (g_variant_dict_end (&newmeta)); + } + if (!opt_timestamp) { if (!ostree_repo_write_commit (repo, parent, opt_subject, commit_body, metadata, diff --git a/src/switchroot/ostree-prepare-root.c b/src/switchroot/ostree-prepare-root.c index ca97244a..2bfc48f5 100644 --- a/src/switchroot/ostree-prepare-root.c +++ b/src/switchroot/ostree-prepare-root.c @@ -181,130 +181,6 @@ resolve_deploy_path (const char *root_mountpoint) return deploy_path; } -#ifdef HAVE_COMPOSEFS -static void -apply_digest_signature (const char *digestfile, const char *sigfile) -{ - unsigned char *signature; - size_t signature_len; - int digest_is_readonly; - int digest_fd; - - signature = read_file (sigfile, &signature_len); - if (signature == NULL) - err (EXIT_FAILURE, "Missing signaure file %s", sigfile); - - /* If we're read-only we temporarily make read-write bind mount to sign */ - digest_is_readonly = path_is_on_readonly_fs (digestfile); - if (digest_is_readonly) - { - if (mount (digestfile, digestfile, NULL, MS_BIND | MS_SILENT, NULL) < 0) - err (EXIT_FAILURE, "failed to bind mount %s (for signing)", digestfile); - if (mount (digestfile, digestfile, NULL, MS_REMOUNT | MS_SILENT, NULL) < 0) - err (EXIT_FAILURE, "failed to remount %s read-write (for signing)", digestfile); - } - - /* Ensure we re-open after any bindmounts */ - digest_fd = open (digestfile, O_RDONLY | O_CLOEXEC); - if (digest_fd < 0) - err (EXIT_FAILURE, "failed to open %s", digestfile); - - fsverity_sign (digest_fd, signature, signature_len); - - close (digest_fd); - - if (digest_is_readonly && umount2 (digestfile, MNT_DETACH) < 0) - err (EXIT_FAILURE, "failed to unmount %s (after signing)", digestfile); - - free (signature); - -#ifdef USE_LIBSYSTEMD - sd_journal_send ("MESSAGE=Applied fsverity signature %s to %s", sigfile, digestfile, NULL); -#endif -} - -static void -ensure_digest_fd_is_signed (int digest_fd) -{ - struct fsverity_read_metadata_arg read_metadata = { 0 }; - char sig_data[1]; - int res; - - /* We verify there is a signature by reading one byte of it. */ - - read_metadata.metadata_type = FS_VERITY_METADATA_TYPE_SIGNATURE; - read_metadata.offset = 0; - read_metadata.length = sizeof (sig_data); - read_metadata.buf_ptr = (size_t)&sig_data; - - res = ioctl (digest_fd, FS_IOC_READ_VERITY_METADATA, &read_metadata); - if (res == -1) - { - if (errno == ENODATA) - err (EXIT_FAILURE, "Digest file is unexpectedly not signed"); - else - err (EXIT_FAILURE, "Failed to get signature from digest file"); - } -} - -static char * -read_signed_digest (const char *digestfile, const char *sigfile) -{ - unsigned fd_flags; - int digest_fd; - unsigned char buf[LCFS_DIGEST_SIZE]; - char *digest; - ssize_t bytes_read; - - digest_fd = open (digestfile, O_RDONLY | O_CLOEXEC); - if (digest_fd < 0) - err (EXIT_FAILURE, "failed to open %s", digestfile); - - /* Check if file is already fsverity */ - if (ioctl (digest_fd, FS_IOC_GETFLAGS, &fd_flags) < 0) - err (EXIT_FAILURE, "failed to get fd flags for %s", digestfile); - - /* If it is not, apply signature */ - if ((fd_flags & FS_VERITY_FL) == 0) - { - close (digest_fd); - - apply_digest_signature (digestfile, sigfile); - - /* Reopen */ - digest_fd = open (digestfile, O_RDONLY | O_CLOEXEC); - if (digest_fd < 0) - err (EXIT_FAILURE, "failed to reopen %s", digestfile); - } - - /* By now we know its fs-verify enabled, also ensure it is signed - * with a key in the keyring */ - ensure_digest_fd_is_signed (digest_fd); - - /* Load the expected digest */ - do - bytes_read = read (digest_fd, buf, LCFS_DIGEST_SIZE); - while (bytes_read == -1 && errno == EINTR); - if (bytes_read == -1) - err (EXIT_FAILURE, "Failed to read digest file"); - - if (bytes_read != LCFS_DIGEST_SIZE) - err (EXIT_FAILURE, "Digest file has wrong size"); - - digest = malloc (LCFS_DIGEST_SIZE * 2 + 1); - if (digest == NULL) - err (EXIT_FAILURE, "Out of memory"); - - bin2hex (digest, buf, LCFS_DIGEST_SIZE); - -#ifdef USE_LIBSYSTEMD - sd_journal_send ("MESSAGE=Signed digest file found for root", NULL); -#endif - - return digest; -} -#endif - static int pivot_root (const char *new_root, const char *put_old) { @@ -439,11 +315,7 @@ main (int argc, char *argv[]) }; if (composefs_mode == OSTREE_COMPOSEFS_MODE_SIGNED) - { - composefs_digest - = read_signed_digest (OSTREE_COMPOSEFS_NAME ".digest", OSTREE_COMPOSEFS_NAME ".sig"); - composefs_mode = OSTREE_COMPOSEFS_MODE_DIGEST; - } + errx (EXIT_FAILURE, "composefs signature not supported"); cfs_options.flags = LCFS_MOUNT_FLAGS_READONLY; diff --git a/tests/test-composefs.sh b/tests/test-composefs.sh new file mode 100755 index 00000000..f76cbf22 --- /dev/null +++ b/tests/test-composefs.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see . + +set -euo pipefail + +if ! ostree --version | grep -q -e '- composefs'; then + echo "1..0 #SKIP no composefs support compiled in" + exit 0 +fi + +. $(dirname $0)/libtest.sh + +setup_test_repository "bare-user" + +cd ${test_tmpdir} +$OSTREE checkout test2 test2-co +$OSTREE commit ${COMMIT_ARGS} -b test-composefs --generate-composefs-metadata test2-co +orig_composefs_digest=$($OSTREE show --print-metadata-key ostree.composefs.v0 test-composefs) +assert_streq "${orig_composefs_digest}" '[byte 0x1f, 0x08, 0xe5, 0x8b, 0x14, 0x3b, 0x75, 0x34, 0x76, 0xb5, 0xef, 0x0c, 0x0c, 0x6e, 0xce, 0xbf, 0xde, 0xbb, 0x6d, 0x40, 0x30, 0x5e, 0x35, 0xbd, 0x6f, 0x8e, 0xc1, 0x9c, 0xd0, 0xd1, 0x5b, 0xae]' +$OSTREE commit ${COMMIT_ARGS} -b test-composefs2 --generate-composefs-metadata test2-co +new_composefs_digest=$($OSTREE show --print-metadata-key ostree.composefs.v0 test-composefs) +assert_streq "${orig_composefs_digest}" "${new_composefs_digest}" +tap_ok "composefs metadata" + +tap_end -- 2.30.2