713 lines
31 KiB
Diff
713 lines
31 KiB
Diff
From 589e0ef3d72cb31d4e6905b464281c8a6139029e Mon Sep 17 00:00:00 2001
|
|
From: Colin Walters <walters@verbum.org>
|
|
Date: Wed, 16 Jul 2025 12:56:49 -0400
|
|
Subject: [PATCH 1/5] prepare-root: Rename rootfs loading functions
|
|
|
|
Prep for moving more functionality there, it's really about
|
|
the rootfs, not just composefs.
|
|
---
|
|
src/libostree/ostree-sysroot-deploy.c | 4 ++--
|
|
src/libotcore/otcore-prepare-root.c | 12 ++++++------
|
|
src/libotcore/otcore.h | 8 ++++----
|
|
src/switchroot/ostree-prepare-root.c | 4 ++--
|
|
4 files changed, 14 insertions(+), 14 deletions(-)
|
|
|
|
diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c
|
|
index 5d356d4d..fa2fd8cc 100644
|
|
--- a/src/libostree/ostree-sysroot-deploy.c
|
|
+++ b/src/libostree/ostree-sysroot-deploy.c
|
|
@@ -653,8 +653,8 @@ checkout_deployment_tree (OstreeSysroot *sysroot, OstreeRepo *repo, OstreeDeploy
|
|
// out if it's enabled, but not supported at compile time.
|
|
// However, we don't load the keys here, because they may not exist, such
|
|
// as in the initial deploy
|
|
- g_autoptr (ComposefsConfig) composefs_config
|
|
- = otcore_load_composefs_config ("", prepare_root_config, FALSE, error);
|
|
+ g_autoptr (RootConfig) composefs_config
|
|
+ = otcore_load_rootfs_config ("", prepare_root_config, FALSE, error);
|
|
if (!composefs_config)
|
|
return glnx_prefix_error (error, "Reading composefs config");
|
|
|
|
diff --git a/src/libotcore/otcore-prepare-root.c b/src/libotcore/otcore-prepare-root.c
|
|
index 18bdf43e..b778ec8d 100644
|
|
--- a/src/libotcore/otcore-prepare-root.c
|
|
+++ b/src/libotcore/otcore-prepare-root.c
|
|
@@ -154,24 +154,24 @@ otcore_load_config (int rootfs_fd, const char *filename, GError **error)
|
|
}
|
|
|
|
void
|
|
-otcore_free_composefs_config (ComposefsConfig *config)
|
|
+otcore_free_rootfs_config (RootConfig *config)
|
|
{
|
|
g_clear_pointer (&config->pubkeys, g_ptr_array_unref);
|
|
g_free (config->signature_pubkey);
|
|
g_free (config);
|
|
}
|
|
|
|
-// Parse the [composefs] section of the prepare-root.conf.
|
|
-ComposefsConfig *
|
|
-otcore_load_composefs_config (const char *cmdline, GKeyFile *config, gboolean load_keys,
|
|
+// Parse key bits of prepare-root.conf into a data structure.
|
|
+RootConfig *
|
|
+otcore_load_rootfs_config (const char *cmdline, GKeyFile *config, gboolean load_keys,
|
|
GError **error)
|
|
{
|
|
g_assert (cmdline);
|
|
g_assert (config);
|
|
|
|
- GLNX_AUTO_PREFIX_ERROR ("Loading composefs config", error);
|
|
+ GLNX_AUTO_PREFIX_ERROR ("Parsing rootfs config", error);
|
|
|
|
- g_autoptr (ComposefsConfig) ret = g_new0 (ComposefsConfig, 1);
|
|
+ g_autoptr (RootConfig) ret = g_new0 (RootConfig, 1);
|
|
|
|
g_autofree char *enabled = g_key_file_get_value (config, OTCORE_PREPARE_ROOT_COMPOSEFS_KEY,
|
|
OTCORE_PREPARE_ROOT_ENABLED_KEY, NULL);
|
|
diff --git a/src/libotcore/otcore.h b/src/libotcore/otcore.h
|
|
index ceeb1a92..3f1b5192 100644
|
|
--- a/src/libotcore/otcore.h
|
|
+++ b/src/libotcore/otcore.h
|
|
@@ -69,11 +69,11 @@ typedef struct
|
|
gboolean is_signed;
|
|
char *signature_pubkey;
|
|
GPtrArray *pubkeys;
|
|
-} ComposefsConfig;
|
|
-void otcore_free_composefs_config (ComposefsConfig *config);
|
|
-G_DEFINE_AUTOPTR_CLEANUP_FUNC (ComposefsConfig, otcore_free_composefs_config)
|
|
+} RootConfig;
|
|
+void otcore_free_rootfs_config (RootConfig *config);
|
|
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (RootConfig, otcore_free_rootfs_config)
|
|
|
|
-ComposefsConfig *otcore_load_composefs_config (const char *cmdline, GKeyFile *config,
|
|
+RootConfig *otcore_load_rootfs_config (const char *cmdline, GKeyFile *config,
|
|
gboolean load_keys, GError **error);
|
|
|
|
// Our directory with transient state (eventually /run/ostree-booted should be a link to
|
|
diff --git a/src/switchroot/ostree-prepare-root.c b/src/switchroot/ostree-prepare-root.c
|
|
index 4bf180c3..5d83a8ca 100644
|
|
--- a/src/switchroot/ostree-prepare-root.c
|
|
+++ b/src/switchroot/ostree-prepare-root.c
|
|
@@ -289,8 +289,8 @@ main (int argc, char *argv[])
|
|
|
|
// We always parse the composefs config, because we want to detect and error
|
|
// out if it's enabled, but not supported at compile time.
|
|
- g_autoptr (ComposefsConfig) composefs_config
|
|
- = otcore_load_composefs_config (kernel_cmdline, config, TRUE, &error);
|
|
+ g_autoptr (RootConfig) composefs_config
|
|
+ = otcore_load_rootfs_config (kernel_cmdline, config, TRUE, &error);
|
|
if (!composefs_config)
|
|
errx (EXIT_FAILURE, "%s", error->message);
|
|
|
|
--
|
|
2.50.1
|
|
|
|
|
|
From 2e7bca26eb69b1376526ec707cd6a4aa177c5fa3 Mon Sep 17 00:00:00 2001
|
|
From: Colin Walters <walters@verbum.org>
|
|
Date: Wed, 16 Jul 2025 12:56:49 -0400
|
|
Subject: [PATCH 2/5] prepare-root: Rename rootfs variables
|
|
|
|
Prep for moving more functionality there, it's really about
|
|
the rootfs, not just composefs.
|
|
|
|
Signed-off-by: Colin Walters <walters@verbum.org>
|
|
---
|
|
src/libostree/ostree-sysroot-deploy.c | 10 +++++-----
|
|
src/switchroot/ostree-prepare-root.c | 28 +++++++++++++--------------
|
|
2 files changed, 19 insertions(+), 19 deletions(-)
|
|
|
|
diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c
|
|
index fa2fd8cc..6a3f1712 100644
|
|
--- a/src/libostree/ostree-sysroot-deploy.c
|
|
+++ b/src/libostree/ostree-sysroot-deploy.c
|
|
@@ -653,12 +653,12 @@ checkout_deployment_tree (OstreeSysroot *sysroot, OstreeRepo *repo, OstreeDeploy
|
|
// out if it's enabled, but not supported at compile time.
|
|
// However, we don't load the keys here, because they may not exist, such
|
|
// as in the initial deploy
|
|
- g_autoptr (RootConfig) composefs_config
|
|
+ g_autoptr (RootConfig) rootfs_config
|
|
= otcore_load_rootfs_config ("", prepare_root_config, FALSE, error);
|
|
- if (!composefs_config)
|
|
- return glnx_prefix_error (error, "Reading composefs config");
|
|
+ if (!rootfs_config)
|
|
+ return glnx_prefix_error (error, "Reading rootfs config");
|
|
|
|
- OtTristate composefs_enabled = composefs_config->enabled;
|
|
+ OtTristate composefs_enabled = rootfs_config->enabled;
|
|
g_debug ("composefs enabled by config: %d repo: %d", composefs_enabled, repo->composefs_wanted);
|
|
if (repo->composefs_wanted == OT_TRISTATE_YES)
|
|
composefs_enabled = repo->composefs_wanted;
|
|
@@ -677,7 +677,7 @@ checkout_deployment_tree (OstreeSysroot *sysroot, OstreeRepo *repo, OstreeDeploy
|
|
g_auto (GVariantBuilder) cfs_checkout_opts_builder
|
|
= G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT);
|
|
guint32 composefs_requested = 1;
|
|
- if (composefs_config->require_verity)
|
|
+ if (rootfs_config->require_verity)
|
|
composefs_requested = 2;
|
|
g_variant_builder_add (&cfs_checkout_opts_builder, "{sv}", "verity",
|
|
g_variant_new_uint32 (composefs_requested));
|
|
diff --git a/src/switchroot/ostree-prepare-root.c b/src/switchroot/ostree-prepare-root.c
|
|
index 5d83a8ca..745bd902 100644
|
|
--- a/src/switchroot/ostree-prepare-root.c
|
|
+++ b/src/switchroot/ostree-prepare-root.c
|
|
@@ -289,14 +289,14 @@ main (int argc, char *argv[])
|
|
|
|
// We always parse the composefs config, because we want to detect and error
|
|
// out if it's enabled, but not supported at compile time.
|
|
- g_autoptr (RootConfig) composefs_config
|
|
+ g_autoptr (RootConfig) rootfs_config
|
|
= otcore_load_rootfs_config (kernel_cmdline, config, TRUE, &error);
|
|
- if (!composefs_config)
|
|
+ if (!rootfs_config)
|
|
errx (EXIT_FAILURE, "%s", error->message);
|
|
|
|
// If composefs is enabled, that also implies sysroot.readonly=true because it's
|
|
// the new default we want to use (not because it's actually required)
|
|
- const bool sysroot_readonly_default = composefs_config->enabled == OT_TRISTATE_YES;
|
|
+ const bool sysroot_readonly_default = rootfs_config->enabled == OT_TRISTATE_YES;
|
|
if (!ot_keyfile_get_boolean_with_default (config, SYSROOT_KEY, READONLY_KEY,
|
|
sysroot_readonly_default, &sysroot_readonly, &error))
|
|
errx (EXIT_FAILURE, "Failed to parse sysroot.readonly value: %s", error->message);
|
|
@@ -328,7 +328,7 @@ main (int argc, char *argv[])
|
|
* However, we only do this if composefs is not enabled, because we don't
|
|
* want to parse the target root filesystem before verifying its integrity.
|
|
*/
|
|
- if (!sysroot_readonly && composefs_config->enabled != OT_TRISTATE_YES)
|
|
+ if (!sysroot_readonly && rootfs_config->enabled != OT_TRISTATE_YES)
|
|
{
|
|
sysroot_readonly = sysroot_is_configured_ro (root_arg);
|
|
// Encourage porting to the new config file
|
|
@@ -373,7 +373,7 @@ main (int argc, char *argv[])
|
|
#ifdef HAVE_COMPOSEFS
|
|
/* We construct the new sysroot in /sysroot.tmp, which is either the composefs
|
|
mount or a bind mount of the deploy-dir */
|
|
- if (composefs_config->enabled != OT_TRISTATE_NO)
|
|
+ if (rootfs_config->enabled != OT_TRISTATE_NO)
|
|
{
|
|
const char *objdirs[] = { "/sysroot/ostree/repo/objects" };
|
|
g_autofree char *cfs_digest = NULL;
|
|
@@ -415,9 +415,9 @@ main (int argc, char *argv[])
|
|
cfs_options.flags = LCFS_MOUNT_FLAGS_READONLY;
|
|
}
|
|
|
|
- if (composefs_config->is_signed)
|
|
+ if (rootfs_config->is_signed)
|
|
{
|
|
- const char *composefs_pubkey = composefs_config->signature_pubkey;
|
|
+ const char *composefs_pubkey = rootfs_config->signature_pubkey;
|
|
g_autoptr (GError) local_error = NULL;
|
|
g_autoptr (GVariant) commit = NULL;
|
|
g_autoptr (GVariant) commitmeta = NULL;
|
|
@@ -432,7 +432,7 @@ main (int argc, char *argv[])
|
|
errx (EXIT_FAILURE, "Signature validation requested, but no signatures in commit");
|
|
|
|
g_autoptr (GBytes) commit_data = g_variant_get_data_as_bytes (commit);
|
|
- if (!validate_signature (commit_data, signatures, composefs_config->pubkeys))
|
|
+ if (!validate_signature (commit_data, signatures, rootfs_config->pubkeys))
|
|
errx (EXIT_FAILURE, "No valid signatures found for public key");
|
|
|
|
g_print ("composefs+ostree: Validated commit signature using '%s'\n", composefs_pubkey);
|
|
@@ -452,12 +452,12 @@ main (int argc, char *argv[])
|
|
expected_digest = g_malloc (OSTREE_SHA256_STRING_LEN + 1);
|
|
ot_bin2hex (expected_digest, cfs_digest_buf, g_variant_get_size (cfs_digest_v));
|
|
|
|
- g_assert (composefs_config->require_verity);
|
|
+ g_assert (rootfs_config->require_verity);
|
|
cfs_options.flags |= LCFS_MOUNT_FLAGS_REQUIRE_VERITY;
|
|
g_print ("composefs: Verifying digest: %s\n", expected_digest);
|
|
cfs_options.expected_fsverity_digest = expected_digest;
|
|
}
|
|
- else if (composefs_config->require_verity)
|
|
+ else if (rootfs_config->require_verity)
|
|
{
|
|
cfs_options.flags |= LCFS_MOUNT_FLAGS_REQUIRE_VERITY;
|
|
}
|
|
@@ -476,8 +476,8 @@ main (int argc, char *argv[])
|
|
else
|
|
{
|
|
int errsv = errno;
|
|
- g_assert (composefs_config->enabled != OT_TRISTATE_NO);
|
|
- if (composefs_config->enabled == OT_TRISTATE_MAYBE && errsv == ENOENT)
|
|
+ g_assert (rootfs_config->enabled != OT_TRISTATE_NO);
|
|
+ if (rootfs_config->enabled == OT_TRISTATE_MAYBE && errsv == ENOENT)
|
|
{
|
|
g_print ("composefs: No image present\n");
|
|
}
|
|
@@ -490,7 +490,7 @@ main (int argc, char *argv[])
|
|
}
|
|
#else
|
|
/* if composefs is configured as "maybe", we should continue */
|
|
- if (composefs_config->enabled == OT_TRISTATE_YES)
|
|
+ if (rootfs_config->enabled == OT_TRISTATE_YES)
|
|
errx (EXIT_FAILURE, "composefs: enabled at runtime, but support is not compiled in");
|
|
#endif
|
|
|
|
@@ -590,7 +590,7 @@ main (int argc, char *argv[])
|
|
* Also, hotfixes are incompatible with signed composefs use for security reasons.
|
|
*/
|
|
if (lstat (OTCORE_HOTFIX_USR_OVL_WORK, &stbuf) == 0
|
|
- && !(using_composefs && composefs_config->is_signed))
|
|
+ && !(using_composefs && rootfs_config->is_signed))
|
|
{
|
|
/* Do we have a persistent overlayfs for /usr? If so, mount it now. */
|
|
const char usr_ovl_options[]
|
|
--
|
|
2.50.1
|
|
|
|
|
|
From b329c9ea48a6a5633d95309979b9dcae5561d963 Mon Sep 17 00:00:00 2001
|
|
From: Colin Walters <walters@verbum.org>
|
|
Date: Wed, 16 Jul 2025 12:56:49 -0400
|
|
Subject: [PATCH 3/5] prepare-root: Rename `enabled` -> `composefs_enabled`
|
|
|
|
Prep for moving more functionality there, it's really about
|
|
the rootfs, not just composefs.
|
|
|
|
Signed-off-by: Colin Walters <walters@verbum.org>
|
|
---
|
|
src/libostree/ostree-sysroot-deploy.c | 2 +-
|
|
src/libotcore/otcore-prepare-root.c | 10 +++++-----
|
|
src/libotcore/otcore.h | 2 +-
|
|
src/switchroot/ostree-prepare-root.c | 12 ++++++------
|
|
4 files changed, 13 insertions(+), 13 deletions(-)
|
|
|
|
diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c
|
|
index 6a3f1712..7ac25b4d 100644
|
|
--- a/src/libostree/ostree-sysroot-deploy.c
|
|
+++ b/src/libostree/ostree-sysroot-deploy.c
|
|
@@ -658,7 +658,7 @@ checkout_deployment_tree (OstreeSysroot *sysroot, OstreeRepo *repo, OstreeDeploy
|
|
if (!rootfs_config)
|
|
return glnx_prefix_error (error, "Reading rootfs config");
|
|
|
|
- OtTristate composefs_enabled = rootfs_config->enabled;
|
|
+ OtTristate composefs_enabled = rootfs_config->composefs_enabled;
|
|
g_debug ("composefs enabled by config: %d repo: %d", composefs_enabled, repo->composefs_wanted);
|
|
if (repo->composefs_wanted == OT_TRISTATE_YES)
|
|
composefs_enabled = repo->composefs_wanted;
|
|
diff --git a/src/libotcore/otcore-prepare-root.c b/src/libotcore/otcore-prepare-root.c
|
|
index b778ec8d..4ffd63d2 100644
|
|
--- a/src/libotcore/otcore-prepare-root.c
|
|
+++ b/src/libotcore/otcore-prepare-root.c
|
|
@@ -177,19 +177,19 @@ otcore_load_rootfs_config (const char *cmdline, GKeyFile *config, gboolean load_
|
|
OTCORE_PREPARE_ROOT_ENABLED_KEY, NULL);
|
|
if (g_strcmp0 (enabled, "signed") == 0)
|
|
{
|
|
- ret->enabled = OT_TRISTATE_YES;
|
|
+ ret->composefs_enabled = OT_TRISTATE_YES;
|
|
ret->require_verity = true;
|
|
ret->is_signed = true;
|
|
}
|
|
else if (g_strcmp0 (enabled, "verity") == 0)
|
|
{
|
|
- ret->enabled = OT_TRISTATE_YES;
|
|
+ ret->composefs_enabled = OT_TRISTATE_YES;
|
|
ret->require_verity = true;
|
|
ret->is_signed = false;
|
|
}
|
|
else if (!ot_keyfile_get_tristate_with_default (config, OTCORE_PREPARE_ROOT_COMPOSEFS_KEY,
|
|
OTCORE_PREPARE_ROOT_ENABLED_KEY, OT_TRISTATE_NO,
|
|
- &ret->enabled, error))
|
|
+ &ret->composefs_enabled, error))
|
|
return NULL;
|
|
|
|
// Look for a key - we default to the initramfs binding path.
|
|
@@ -232,7 +232,7 @@ otcore_load_rootfs_config (const char *cmdline, GKeyFile *config, gboolean load_
|
|
{
|
|
if (g_strcmp0 (ostree_composefs, "signed") == 0)
|
|
{
|
|
- ret->enabled = OT_TRISTATE_YES;
|
|
+ ret->composefs_enabled = OT_TRISTATE_YES;
|
|
ret->is_signed = true;
|
|
ret->require_verity = true;
|
|
}
|
|
@@ -240,7 +240,7 @@ otcore_load_rootfs_config (const char *cmdline, GKeyFile *config, gboolean load_
|
|
{
|
|
// The other states force off signatures
|
|
ret->is_signed = false;
|
|
- if (!_ostree_parse_tristate (ostree_composefs, &ret->enabled, error))
|
|
+ if (!_ostree_parse_tristate (ostree_composefs, &ret->composefs_enabled, error))
|
|
return glnx_prefix_error (error, "handling karg " CMDLINE_KEY_COMPOSEFS), NULL;
|
|
}
|
|
}
|
|
diff --git a/src/libotcore/otcore.h b/src/libotcore/otcore.h
|
|
index 3f1b5192..ff4baa94 100644
|
|
--- a/src/libotcore/otcore.h
|
|
+++ b/src/libotcore/otcore.h
|
|
@@ -64,7 +64,7 @@ GKeyFile *otcore_load_config (int rootfs, const char *filename, GError **error);
|
|
|
|
typedef struct
|
|
{
|
|
- OtTristate enabled;
|
|
+ OtTristate composefs_enabled;
|
|
gboolean require_verity;
|
|
gboolean is_signed;
|
|
char *signature_pubkey;
|
|
diff --git a/src/switchroot/ostree-prepare-root.c b/src/switchroot/ostree-prepare-root.c
|
|
index 745bd902..d946bd8a 100644
|
|
--- a/src/switchroot/ostree-prepare-root.c
|
|
+++ b/src/switchroot/ostree-prepare-root.c
|
|
@@ -296,7 +296,7 @@ main (int argc, char *argv[])
|
|
|
|
// If composefs is enabled, that also implies sysroot.readonly=true because it's
|
|
// the new default we want to use (not because it's actually required)
|
|
- const bool sysroot_readonly_default = rootfs_config->enabled == OT_TRISTATE_YES;
|
|
+ const bool sysroot_readonly_default = rootfs_config->composefs_enabled == OT_TRISTATE_YES;
|
|
if (!ot_keyfile_get_boolean_with_default (config, SYSROOT_KEY, READONLY_KEY,
|
|
sysroot_readonly_default, &sysroot_readonly, &error))
|
|
errx (EXIT_FAILURE, "Failed to parse sysroot.readonly value: %s", error->message);
|
|
@@ -328,7 +328,7 @@ main (int argc, char *argv[])
|
|
* However, we only do this if composefs is not enabled, because we don't
|
|
* want to parse the target root filesystem before verifying its integrity.
|
|
*/
|
|
- if (!sysroot_readonly && rootfs_config->enabled != OT_TRISTATE_YES)
|
|
+ if (!sysroot_readonly && rootfs_config->composefs_enabled != OT_TRISTATE_YES)
|
|
{
|
|
sysroot_readonly = sysroot_is_configured_ro (root_arg);
|
|
// Encourage porting to the new config file
|
|
@@ -373,7 +373,7 @@ main (int argc, char *argv[])
|
|
#ifdef HAVE_COMPOSEFS
|
|
/* We construct the new sysroot in /sysroot.tmp, which is either the composefs
|
|
mount or a bind mount of the deploy-dir */
|
|
- if (rootfs_config->enabled != OT_TRISTATE_NO)
|
|
+ if (rootfs_config->composefs_enabled != OT_TRISTATE_NO)
|
|
{
|
|
const char *objdirs[] = { "/sysroot/ostree/repo/objects" };
|
|
g_autofree char *cfs_digest = NULL;
|
|
@@ -476,8 +476,8 @@ main (int argc, char *argv[])
|
|
else
|
|
{
|
|
int errsv = errno;
|
|
- g_assert (rootfs_config->enabled != OT_TRISTATE_NO);
|
|
- if (rootfs_config->enabled == OT_TRISTATE_MAYBE && errsv == ENOENT)
|
|
+ g_assert (rootfs_config->composefs_enabled != OT_TRISTATE_NO);
|
|
+ if (rootfs_config->composefs_enabled == OT_TRISTATE_MAYBE && errsv == ENOENT)
|
|
{
|
|
g_print ("composefs: No image present\n");
|
|
}
|
|
@@ -490,7 +490,7 @@ main (int argc, char *argv[])
|
|
}
|
|
#else
|
|
/* if composefs is configured as "maybe", we should continue */
|
|
- if (rootfs_config->enabled == OT_TRISTATE_YES)
|
|
+ if (rootfs_config->composefs_enabled == OT_TRISTATE_YES)
|
|
errx (EXIT_FAILURE, "composefs: enabled at runtime, but support is not compiled in");
|
|
#endif
|
|
|
|
--
|
|
2.50.1
|
|
|
|
|
|
From 8e52cc3f67f62225055ab294adb87728063744df Mon Sep 17 00:00:00 2001
|
|
From: Colin Walters <walters@verbum.org>
|
|
Date: Wed, 16 Jul 2025 13:18:58 -0400
|
|
Subject: [PATCH 4/5] prepare-root: Move root.transient parsing rootfs parsing
|
|
|
|
This deduplicates more code between main boot and soft reboot,
|
|
and is prep for supporting `rootfs.transient-ro = true`.
|
|
---
|
|
src/libotcore/otcore-prepare-root.c | 6 ++++++
|
|
src/libotcore/otcore.h | 2 ++
|
|
src/switchroot/ostree-prepare-root.c | 19 ++++++-------------
|
|
3 files changed, 14 insertions(+), 13 deletions(-)
|
|
|
|
diff --git a/src/libotcore/otcore-prepare-root.c b/src/libotcore/otcore-prepare-root.c
|
|
index 4ffd63d2..8a78ce28 100644
|
|
--- a/src/libotcore/otcore-prepare-root.c
|
|
+++ b/src/libotcore/otcore-prepare-root.c
|
|
@@ -26,6 +26,8 @@
|
|
#define BINDING_KEYPATH "/etc/ostree/initramfs-root-binding.key"
|
|
// The kernel argument to configure composefs
|
|
#define CMDLINE_KEY_COMPOSEFS "ostree.prepare-root.composefs"
|
|
+/* This key configures the / mount in the deployment root */
|
|
+#define ROOT_KEY "root"
|
|
|
|
static bool
|
|
proc_cmdline_has_key_starting_with (const char *cmdline, const char *key)
|
|
@@ -173,6 +175,10 @@ otcore_load_rootfs_config (const char *cmdline, GKeyFile *config, gboolean load_
|
|
|
|
g_autoptr (RootConfig) ret = g_new0 (RootConfig, 1);
|
|
|
|
+ if (!ot_keyfile_get_boolean_with_default (config, ROOT_KEY, OTCORE_PREPARE_ROOT_TRANSIENT_KEY,
|
|
+ FALSE, &ret->root_transient, error))
|
|
+ return NULL;
|
|
+
|
|
g_autofree char *enabled = g_key_file_get_value (config, OTCORE_PREPARE_ROOT_COMPOSEFS_KEY,
|
|
OTCORE_PREPARE_ROOT_ENABLED_KEY, NULL);
|
|
if (g_strcmp0 (enabled, "signed") == 0)
|
|
diff --git a/src/libotcore/otcore.h b/src/libotcore/otcore.h
|
|
index ff4baa94..e59651b0 100644
|
|
--- a/src/libotcore/otcore.h
|
|
+++ b/src/libotcore/otcore.h
|
|
@@ -65,6 +65,7 @@ GKeyFile *otcore_load_config (int rootfs, const char *filename, GError **error);
|
|
typedef struct
|
|
{
|
|
OtTristate composefs_enabled;
|
|
+ gboolean root_transient;
|
|
gboolean require_verity;
|
|
gboolean is_signed;
|
|
char *signature_pubkey;
|
|
@@ -103,6 +104,7 @@ RootConfig *otcore_load_rootfs_config (const char *cmdline, GKeyFile *config,
|
|
#define OTCORE_PREPARE_ROOT_COMPOSEFS_KEY "composefs"
|
|
#define OTCORE_PREPARE_ROOT_ENABLED_KEY "enabled"
|
|
#define OTCORE_PREPARE_ROOT_KEYPATH_KEY "keypath"
|
|
+#define OTCORE_PREPARE_ROOT_TRANSIENT_KEY "transient"
|
|
|
|
// The file written in the initramfs which contains an a{sv} of metadata
|
|
// from ostree-prepare-root.
|
|
diff --git a/src/switchroot/ostree-prepare-root.c b/src/switchroot/ostree-prepare-root.c
|
|
index d946bd8a..c6cf33c4 100644
|
|
--- a/src/switchroot/ostree-prepare-root.c
|
|
+++ b/src/switchroot/ostree-prepare-root.c
|
|
@@ -79,8 +79,6 @@
|
|
#define SYSROOT_KEY "sysroot"
|
|
#define READONLY_KEY "readonly"
|
|
|
|
-/* This key configures the / mount in the deployment root */
|
|
-#define ROOT_KEY "root"
|
|
#define ETC_KEY "etc"
|
|
#define TRANSIENT_KEY "transient"
|
|
|
|
@@ -281,11 +279,6 @@ main (int argc, char *argv[])
|
|
errx (EXIT_FAILURE, "Failed to parse config: %s", error->message);
|
|
|
|
gboolean sysroot_readonly = FALSE;
|
|
- gboolean root_transient = FALSE;
|
|
-
|
|
- if (!ot_keyfile_get_boolean_with_default (config, ROOT_KEY, TRANSIENT_KEY, FALSE, &root_transient,
|
|
- &error))
|
|
- return FALSE;
|
|
|
|
// We always parse the composefs config, because we want to detect and error
|
|
// out if it's enabled, but not supported at compile time.
|
|
@@ -394,13 +387,13 @@ main (int argc, char *argv[])
|
|
// https://github.com/systemd/systemd/blob/604b2001081adcbd64ee1fbe7de7a6d77c5209fe/src/basic/mountpoint-util.h#L36
|
|
// which bumps up these defaults for the rootfs a bit.
|
|
g_autofree char *root_upperdir
|
|
- = root_transient ? g_build_filename (OTCORE_RUN_OSTREE_PRIVATE, "root/upper", NULL)
|
|
+ = rootfs_config->root_transient ? g_build_filename (OTCORE_RUN_OSTREE_PRIVATE, "root/upper", NULL)
|
|
: NULL;
|
|
g_autofree char *root_workdir
|
|
- = root_transient ? g_build_filename (OTCORE_RUN_OSTREE_PRIVATE, "root/work", NULL) : NULL;
|
|
+ = rootfs_config->root_transient ? g_build_filename (OTCORE_RUN_OSTREE_PRIVATE, "root/work", NULL) : NULL;
|
|
|
|
// Propagate these options for transient root, if provided
|
|
- if (root_transient)
|
|
+ if (rootfs_config->root_transient)
|
|
{
|
|
if (!glnx_shutil_mkdir_p_at (AT_FDCWD, root_upperdir, 0755, NULL, &error))
|
|
errx (EXIT_FAILURE, "Failed to create %s: %s", root_upperdir, error->message);
|
|
@@ -496,7 +489,7 @@ main (int argc, char *argv[])
|
|
|
|
if (!using_composefs)
|
|
{
|
|
- if (root_transient)
|
|
+ if (rootfs_config->root_transient)
|
|
{
|
|
errx (EXIT_FAILURE, "Must enable composefs with root.transient");
|
|
}
|
|
@@ -508,7 +501,7 @@ main (int argc, char *argv[])
|
|
|
|
/* Pass on the state */
|
|
g_variant_builder_add (&metadata_builder, "{sv}", OTCORE_RUN_BOOTED_KEY_ROOT_TRANSIENT,
|
|
- g_variant_new_boolean (root_transient));
|
|
+ g_variant_new_boolean (rootfs_config->root_transient));
|
|
|
|
/* Pass on the state for use by ostree-prepare-root */
|
|
g_variant_builder_add (&metadata_builder, "{sv}", OTCORE_RUN_BOOTED_KEY_SYSROOT_RO,
|
|
@@ -533,7 +526,7 @@ main (int argc, char *argv[])
|
|
/* Prepare /etc.
|
|
* No action required if sysroot is writable. Otherwise, a bind-mount for
|
|
* the deployment needs to be created and remounted as read/write. */
|
|
- if (sysroot_readonly || using_composefs || root_transient)
|
|
+ if (sysroot_readonly || using_composefs || rootfs_config->root_transient)
|
|
{
|
|
gboolean etc_transient = FALSE;
|
|
if (!ot_keyfile_get_boolean_with_default (config, ETC_KEY, TRANSIENT_KEY, FALSE,
|
|
--
|
|
2.50.1
|
|
|
|
|
|
From c6d138cdf2756753566a26907bffbdb07ce8319b Mon Sep 17 00:00:00 2001
|
|
From: Colin Walters <walters@verbum.org>
|
|
Date: Wed, 16 Jul 2025 11:08:00 -0400
|
|
Subject: [PATCH 5/5] Add root.transient-ro
|
|
|
|
An example use case for this is having privileged code
|
|
add dynamic new toplevel mountpoints (that don't persist across
|
|
reboots/upgrades), while still keeping the rootfs readonly
|
|
for processes by default.
|
|
|
|
Closes: https://github.com/ostreedev/ostree/issues/3471
|
|
|
|
Signed-off-by: Colin Walters <walters@verbum.org>
|
|
---
|
|
man/ostree-prepare-root.xml | 9 ++++
|
|
src/libotcore/otcore-prepare-root.c | 14 ++++++
|
|
src/libotcore/otcore.h | 4 ++
|
|
src/switchroot/ostree-prepare-root.c | 10 +++++
|
|
.../kolainst/destructive/root-transient-ro.sh | 44 +++++++++++++++++++
|
|
5 files changed, 81 insertions(+)
|
|
create mode 100755 tests/kolainst/destructive/root-transient-ro.sh
|
|
|
|
diff --git a/man/ostree-prepare-root.xml b/man/ostree-prepare-root.xml
|
|
index c1f39a8a..fd46a357 100644
|
|
--- a/man/ostree-prepare-root.xml
|
|
+++ b/man/ostree-prepare-root.xml
|
|
@@ -140,6 +140,15 @@ License along with this library. If not, see <https://www.gnu.org/licenses/>.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
+ <varlistentry>
|
|
+ <term><varname>root.transient-ro</varname></term>
|
|
+ <listitem><para>A boolean value; the default is <literal>false</literal>.
|
|
+ This is like <literal>root.transient</literal>, but the overlayfs upper will be mounted
|
|
+ read-only by default. Use this when you want specific privileged components to be able to
|
|
+ write to the upper by temporarily mounting it writable in a new mount namespace.
|
|
+ </para>
|
|
+ </listitem>
|
|
+ </varlistentry>
|
|
<varlistentry>
|
|
<term><varname>composefs.enabled</varname></term>
|
|
<listitem><para>This can be <literal>yes</literal>, <literal>no</literal>, <literal>maybe</literal>,
|
|
diff --git a/src/libotcore/otcore-prepare-root.c b/src/libotcore/otcore-prepare-root.c
|
|
index 8a78ce28..42611105 100644
|
|
--- a/src/libotcore/otcore-prepare-root.c
|
|
+++ b/src/libotcore/otcore-prepare-root.c
|
|
@@ -179,6 +179,20 @@ otcore_load_rootfs_config (const char *cmdline, GKeyFile *config, gboolean load_
|
|
FALSE, &ret->root_transient, error))
|
|
return NULL;
|
|
|
|
+
|
|
+ if (!ot_keyfile_get_boolean_with_default (config, ROOT_KEY, OTCORE_PREPARE_ROOT_TRANSIENT_RO_KEY,
|
|
+ FALSE, &ret->root_transient_ro, error))
|
|
+ return NULL;
|
|
+ if (ret->root_transient && ret->root_transient_ro)
|
|
+ {
|
|
+ return glnx_null_throw (error, "Cannot set both root.transient and root.transient-ro");
|
|
+ }
|
|
+ // This way callers can test for just root_transient
|
|
+ else if (ret->root_transient_ro)
|
|
+ {
|
|
+ ret->root_transient = TRUE;
|
|
+ }
|
|
+
|
|
g_autofree char *enabled = g_key_file_get_value (config, OTCORE_PREPARE_ROOT_COMPOSEFS_KEY,
|
|
OTCORE_PREPARE_ROOT_ENABLED_KEY, NULL);
|
|
if (g_strcmp0 (enabled, "signed") == 0)
|
|
diff --git a/src/libotcore/otcore.h b/src/libotcore/otcore.h
|
|
index e59651b0..33ccd7bb 100644
|
|
--- a/src/libotcore/otcore.h
|
|
+++ b/src/libotcore/otcore.h
|
|
@@ -66,6 +66,7 @@ typedef struct
|
|
{
|
|
OtTristate composefs_enabled;
|
|
gboolean root_transient;
|
|
+ gboolean root_transient_ro;
|
|
gboolean require_verity;
|
|
gboolean is_signed;
|
|
char *signature_pubkey;
|
|
@@ -105,6 +106,7 @@ RootConfig *otcore_load_rootfs_config (const char *cmdline, GKeyFile *config,
|
|
#define OTCORE_PREPARE_ROOT_ENABLED_KEY "enabled"
|
|
#define OTCORE_PREPARE_ROOT_KEYPATH_KEY "keypath"
|
|
#define OTCORE_PREPARE_ROOT_TRANSIENT_KEY "transient"
|
|
+#define OTCORE_PREPARE_ROOT_TRANSIENT_RO_KEY "transient-ro"
|
|
|
|
// The file written in the initramfs which contains an a{sv} of metadata
|
|
// from ostree-prepare-root.
|
|
@@ -118,6 +120,8 @@ RootConfig *otcore_load_rootfs_config (const char *cmdline, GKeyFile *config,
|
|
#define OTCORE_RUN_BOOTED_KEY_COMPOSEFS_SIGNATURE "composefs.signed"
|
|
// This key will be present if the root is transient
|
|
#define OTCORE_RUN_BOOTED_KEY_ROOT_TRANSIENT "root.transient"
|
|
+// This key will be present if the root is transient readonly
|
|
+#define OTCORE_RUN_BOOTED_KEY_ROOT_TRANSIENT_RO "root.transient-ro"
|
|
// This key will be present if the sysroot-ro flag was found
|
|
#define OTCORE_RUN_BOOTED_KEY_SYSROOT_RO "sysroot-ro"
|
|
// Always holds the (device, inode) pair of the booted deployment
|
|
diff --git a/src/switchroot/ostree-prepare-root.c b/src/switchroot/ostree-prepare-root.c
|
|
index c6cf33c4..84c14703 100644
|
|
--- a/src/switchroot/ostree-prepare-root.c
|
|
+++ b/src/switchroot/ostree-prepare-root.c
|
|
@@ -332,6 +332,11 @@ main (int argc, char *argv[])
|
|
const bool sysroot_currently_writable = !path_is_on_readonly_fs (root_arg);
|
|
g_print ("sysroot.readonly configuration value: %d (fs writable: %d)\n", (int)sysroot_readonly,
|
|
(int)sysroot_currently_writable);
|
|
+ if (rootfs_config->root_transient)
|
|
+ {
|
|
+ g_print ("root.transient: %d (ro: %d)\n", (int)rootfs_config->root_transient,
|
|
+ (int)rootfs_config->root_transient_ro);
|
|
+ }
|
|
|
|
/* Remount root MS_PRIVATE here to avoid errors due to the kernel-enforced
|
|
* constraint that disallows MS_SHARED mounts to be moved.
|
|
@@ -402,6 +407,8 @@ main (int argc, char *argv[])
|
|
|
|
cfs_options.workdir = root_workdir;
|
|
cfs_options.upperdir = root_upperdir;
|
|
+ if (rootfs_config->root_transient_ro)
|
|
+ cfs_options.flags = LCFS_MOUNT_FLAGS_READONLY;
|
|
}
|
|
else
|
|
{
|
|
@@ -503,6 +510,9 @@ main (int argc, char *argv[])
|
|
g_variant_builder_add (&metadata_builder, "{sv}", OTCORE_RUN_BOOTED_KEY_ROOT_TRANSIENT,
|
|
g_variant_new_boolean (rootfs_config->root_transient));
|
|
|
|
+ g_variant_builder_add (&metadata_builder, "{sv}", OTCORE_RUN_BOOTED_KEY_ROOT_TRANSIENT_RO,
|
|
+ g_variant_new_boolean (rootfs_config->root_transient_ro));
|
|
+
|
|
/* Pass on the state for use by ostree-prepare-root */
|
|
g_variant_builder_add (&metadata_builder, "{sv}", OTCORE_RUN_BOOTED_KEY_SYSROOT_RO,
|
|
g_variant_new_boolean (sysroot_readonly));
|
|
diff --git a/tests/kolainst/destructive/root-transient-ro.sh b/tests/kolainst/destructive/root-transient-ro.sh
|
|
new file mode 100755
|
|
index 00000000..7a8ab54a
|
|
--- /dev/null
|
|
+++ b/tests/kolainst/destructive/root-transient-ro.sh
|
|
@@ -0,0 +1,44 @@
|
|
+#!/bin/bash
|
|
+set -xeuo pipefail
|
|
+
|
|
+. ${KOLA_EXT_DATA}/libinsttest.sh
|
|
+
|
|
+prepare_tmpdir
|
|
+
|
|
+echo "testing boot=${AUTOPKGTEST_REBOOT_MARK:-}"
|
|
+
|
|
+# Print this by default on each boot
|
|
+ostree admin status
|
|
+
|
|
+case "${AUTOPKGTEST_REBOOT_MARK:-}" in
|
|
+ "")
|
|
+ # xref https://github.com/coreos/coreos-assembler/pull/2814
|
|
+ systemctl mask --now zincati
|
|
+
|
|
+ test '!' -w /
|
|
+
|
|
+ cp /usr/lib/ostree/prepare-root.conf /etc/ostree/
|
|
+ cat >> /etc/ostree/prepare-root.conf <<'EOF'
|
|
+[root]
|
|
+transient-ro = true
|
|
+EOF
|
|
+
|
|
+ rpm-ostree initramfs-etc --track /etc/ostree/prepare-root.conf
|
|
+
|
|
+ /tmp/autopkgtest-reboot "2"
|
|
+ ;;
|
|
+ "2")
|
|
+
|
|
+ test '!' -w '/'
|
|
+
|
|
+ unshare -m /bin/sh -c 'env LIBMOUNT_FORCE_MOUNT2=always mount -o remount,rw / && mkdir /new-dir-in-root'
|
|
+ test -d /new-dir-in-root
|
|
+
|
|
+ test '!' -w '/'
|
|
+
|
|
+ echo "ok root transient-ro"
|
|
+ ;;
|
|
+ *)
|
|
+ fatal "Unexpected AUTOPKGTEST_REBOOT_MARK=${AUTOPKGTEST_REBOOT_MARK}"
|
|
+ ;;
|
|
+esac
|
|
--
|
|
2.50.1
|
|
|