Skip to content

Commit 92f6d8e

Browse files
committed
Support using composefs signatures also with bootc commits
When using bootc, if you convert a signed ostree commit into an OCI image `rpm-ostree compose container-encapsulate` you end up with a new commit that isn't signed. However, the base commit object, and its commitmeta are still in the image and will end up the repo, and since bootc-dev/bootc#1600 the base commit id is available as the parent commit. So, we change ostree-prepare-root to fall back to using the base commit+commitmeta to find the expected composefs digest if the main commit is not signed. Note: This will only work with ostree-only commits. If you have any layered data, then the content will change, and the composefs digest in the base commit will not match the deployed one. This is expected with such sealed commits though. If you want to layer, either disable sealing, or create a new sealed ostree commit for the new image.
1 parent c69bd1d commit 92f6d8e

File tree

1 file changed

+75
-7
lines changed

1 file changed

+75
-7
lines changed

src/libotcore/otcore-prepare-root.c

Lines changed: 75 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -305,11 +305,41 @@ load_variant (const char *root_mountpoint, const char *digest, const char *exten
305305
return TRUE;
306306
}
307307

308+
/* For local bootc commit, return the base ostree commit that was used to generate the commit.
309+
*/
310+
static char *
311+
get_base_digest_for_bootc_commit (GVariant *commit)
312+
{
313+
g_autoptr (GVariant) metadata = g_variant_get_child_value (commit, 0);
314+
315+
/* Check for ostree.container.image-config to determine if this is a bootc commit */
316+
const char *image_config = NULL;
317+
if (!g_variant_lookup (metadata, "ostree.container.image-config", "s", &image_config))
318+
return NULL;
319+
320+
/* If so, since https://github.com/bootc-dev/bootc/pull/1600, the
321+
* parent commit will be the base ostree commit. */
322+
323+
g_autoptr (GVariant) parent_commit_v = g_variant_get_child_value (commit, 1);
324+
if (g_variant_n_children (parent_commit_v) != OSTREE_SHA256_DIGEST_LEN)
325+
return NULL;
326+
327+
const guint8 *parent_commit_bin = ot_variant_get_data (parent_commit_v, NULL);
328+
if (parent_commit_bin == NULL)
329+
return NULL;
330+
331+
char *basecommit_digest = g_malloc (OSTREE_SHA256_STRING_LEN + 1);
332+
ot_bin2hex (basecommit_digest, parent_commit_bin, OSTREE_SHA256_DIGEST_LEN);
333+
334+
return basecommit_digest;
335+
}
336+
308337
// Given a mount point, directly load the .commit object. At the current time this tool
309338
// doesn't link to libostree.
310339
static gboolean
311340
load_commit_for_deploy (const char *root_mountpoint, const char *deploy_path, GVariant **commit_out,
312-
GVariant **commitmeta_out, GError **error)
341+
GVariant **commitmeta_out, GVariant **basecommit_out,
342+
GVariant **basecommitmeta_out, GError **error)
313343
{
314344
g_autofree char *digest = g_path_get_basename (deploy_path);
315345
char *dot = strchr (digest, '.');
@@ -318,6 +348,8 @@ load_commit_for_deploy (const char *root_mountpoint, const char *deploy_path, GV
318348

319349
g_autoptr (GVariant) commit_v = NULL;
320350
g_autoptr (GVariant) commitmeta_v = NULL;
351+
g_autoptr (GVariant) basecommit_v = NULL;
352+
g_autoptr (GVariant) basecommitmeta_v = NULL;
321353

322354
if (!load_variant (root_mountpoint, digest, "commit", OSTREE_COMMIT_GVARIANT_FORMAT, FALSE,
323355
&commit_v, error))
@@ -327,8 +359,28 @@ load_commit_for_deploy (const char *root_mountpoint, const char *deploy_path, GV
327359
&commitmeta_v, error))
328360
return FALSE;
329361

362+
/* In case the commit is one created by bootc when importing a container, it will not
363+
* be signed. However, we can still look at the base commit which may be signed.
364+
*/
365+
g_autofree char *basecommit_digest = get_base_digest_for_bootc_commit (commit_v);
366+
if (basecommit_digest)
367+
{
368+
if (!load_variant (root_mountpoint, basecommit_digest, "commit",
369+
OSTREE_COMMIT_GVARIANT_FORMAT, TRUE, &basecommit_v, error))
370+
return FALSE;
371+
372+
if (basecommit_v != NULL)
373+
{
374+
if (!load_variant (root_mountpoint, basecommit_digest, "commitmeta",
375+
G_VARIANT_TYPE ("a{sv}"), TRUE, &basecommitmeta_v, error))
376+
return FALSE;
377+
}
378+
}
379+
330380
*commit_out = g_steal_pointer (&commit_v);
331381
*commitmeta_out = g_steal_pointer (&commitmeta_v);
382+
*basecommit_out = g_steal_pointer (&basecommit_v);
383+
*basecommitmeta_out = g_steal_pointer (&basecommitmeta_v);
332384

333385
return TRUE;
334386
}
@@ -556,14 +608,30 @@ otcore_mount_rootfs (RootConfig *rootfs_config, GVariantBuilder *metadata_builde
556608
if (rootfs_config->is_signed)
557609
{
558610
const char *composefs_pubkey = rootfs_config->signature_pubkey;
559-
g_autoptr (GVariant) commit = NULL;
560-
g_autoptr (GVariant) commitmeta = NULL;
561-
562-
if (!load_commit_for_deploy (root_mountpoint, deploy_path, &commit, &commitmeta,
563-
error))
611+
g_autoptr (GVariant) main_commit = NULL;
612+
g_autoptr (GVariant) main_commitmeta = NULL;
613+
g_autoptr (GVariant) base_commit = NULL;
614+
g_autoptr (GVariant) base_commitmeta = NULL;
615+
GVariant *commit = NULL;
616+
GVariant *commitmeta = NULL;
617+
618+
if (!load_commit_for_deploy (root_mountpoint, deploy_path, &main_commit, &main_commitmeta,
619+
&base_commit, &base_commitmeta, error))
564620
return glnx_prefix_error (error, "Error loading signatures from repo");
565621

566-
if (commitmeta == NULL)
622+
if (main_commitmeta != NULL)
623+
{
624+
commit = main_commit;
625+
commitmeta = main_commitmeta;
626+
}
627+
else if (base_commitmeta != NULL)
628+
{
629+
ot_journal_print (LOG_INFO,
630+
"composefs+ostree: Validating composefs using bootc base commit");
631+
commit = base_commit;
632+
commitmeta = base_commitmeta;
633+
}
634+
else
567635
return glnx_throw (error, "No commitmeta for deploy %s", deploy_path);
568636

569637
g_autoptr (GVariant) signatures = g_variant_lookup_value (

0 commit comments

Comments
 (0)