From c3813e3e87744b240efdaf68ad334c70f304e1c9 Mon Sep 17 00:00:00 2001 From: Eric Curtin Date: Wed, 21 Feb 2024 16:02:08 +0000 Subject: [PATCH] generator: Fixes for Android Boot environment In Android Boot environment we do not parse ostree= karg to determine what directory to boot into, alternatively we do this based on the androidboot.slot_suffix= karg. But we do set ostree=true karg to denote that we are indeed booting an ostree environment (required for some systemd unit files). This change accounts for this approach in the systemd generator. In this case androidboot.slot_suffix= points you to /ostree/root.[a|b] and then that points you to the directory to boot into in /ostree/deploy... Here is what a cmdline may look like in this type of environment: androidboot.slot_suffix=_a androidboot.bootdevice=*.ufshc root=PARTLABEL=system_a root=UUID=76a22bf4-f153-4541-b6c7-0332c0dfaeac rw ostree=true loglevel=4 acpi=off console=ttyAMA0 systemd.show_status=auto libahci.ignore_sss=1 slub_debug=FPZ fsck.mode=skip rcupdate.rcu_normal_after_boot=0 rcupdate.rcu_expedited=1 Signed-off-by: Eric Curtin --- src/libostree/ostree-impl-system-generator.c | 17 ++++++----- src/libostree/ostree-sysroot-private.h | 9 ++++-- src/libostree/ostree-sysroot.c | 30 +++++++++++++++----- src/libotcore/otcore-prepare-root.c | 4 ++- src/libotcore/otcore.h | 3 +- src/switchroot/ostree-prepare-root.c | 3 +- tests/test-otcore.c | 22 +++++++------- 7 files changed, 58 insertions(+), 30 deletions(-) diff --git a/src/libostree/ostree-impl-system-generator.c b/src/libostree/ostree-impl-system-generator.c index e51584cda8..bfda2b138f 100644 --- a/src/libostree/ostree-impl-system-generator.c +++ b/src/libostree/ostree-impl-system-generator.c @@ -128,8 +128,8 @@ require_internal_units (const char *normal_dir, const char *early_dir, const cha /* Generate var.mount */ static gboolean -fstab_generator (const char *ostree_cmdline, const char *normal_dir, const char *early_dir, - const char *late_dir, GError **error) +fstab_generator (const char *ostree_target, const bool is_aboot, const char *normal_dir, + const char *early_dir, const char *late_dir, GError **error) { #ifdef HAVE_LIBMOUNT /* Not currently cancellable, but define a var in case we care later */ @@ -144,7 +144,8 @@ fstab_generator (const char *ostree_cmdline, const char *normal_dir, const char * mounted yet. */ g_autofree char *stateroot = NULL; - if (!_ostree_sysroot_parse_bootlink (ostree_cmdline, NULL, &stateroot, NULL, NULL, error)) + if (!_ostree_sysroot_parse_bootlink (ostree_target, is_aboot, NULL, &stateroot, NULL, NULL, + error)) return glnx_prefix_error (error, "Parsing stateroot"); /* Load /etc/fstab if it exists, and look for a /var mount */ @@ -261,17 +262,19 @@ _ostree_impl_system_generator (const char *normal_dir, const char *early_dir, co if (!cmdline) return glnx_throw (error, "Failed to read /proc/cmdline"); - g_autofree char *ostree_cmdline = otcore_find_proc_cmdline_key (cmdline, "ostree"); - + g_autoptr (GError) otcore_get_ostree_target_error = NULL; + g_autofree char *ostree_target = NULL; + bool is_aboot = false; /* This could happen in CoreOS live environments, where we hackily mock * the `ostree=` karg for `ostree-prepare-root.service` specifically, but * otherwise that karg doesn't exist on the real command-line. */ - if (!ostree_cmdline) + if (!otcore_get_ostree_target (cmdline, &is_aboot, &ostree_target, + &otcore_get_ostree_target_error)) return TRUE; if (!require_internal_units (normal_dir, early_dir, late_dir, error)) return FALSE; - if (!fstab_generator (ostree_cmdline, normal_dir, early_dir, late_dir, error)) + if (!fstab_generator (ostree_target, is_aboot, normal_dir, early_dir, late_dir, error)) return FALSE; return TRUE; diff --git a/src/libostree/ostree-sysroot-private.h b/src/libostree/ostree-sysroot-private.h index 297b3273a0..0e9f15bd16 100644 --- a/src/libostree/ostree-sysroot-private.h +++ b/src/libostree/ostree-sysroot-private.h @@ -19,6 +19,8 @@ #pragma once +#include + #include "libglnx.h" #include "ostree-bootloader.h" #include "ostree.h" @@ -177,8 +179,9 @@ gboolean _ostree_sysroot_parse_bootdir_name (const char *name, char **out_osname gboolean _ostree_sysroot_list_all_boot_directories (OstreeSysroot *self, char ***out_bootdirs, GCancellable *cancellable, GError **error); -gboolean _ostree_sysroot_parse_bootlink (const char *bootlink, int *out_entry_bootversion, - char **out_osname, char **out_bootcsum, - int *out_treebootserial, GError **error); +gboolean _ostree_sysroot_parse_bootlink (const char *bootlink, const bool is_aboot, + int *out_entry_bootversion, char **out_osname, + char **out_bootcsum, int *out_treebootserial, + GError **error); G_END_DECLS diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c index a19b049b32..6c712ef6f9 100644 --- a/src/libostree/ostree-sysroot.c +++ b/src/libostree/ostree-sysroot.c @@ -724,24 +724,37 @@ load_origin (OstreeSysroot *self, OstreeDeployment *deployment, GCancellable *ca // Parse the kernel argument ostree= gboolean -_ostree_sysroot_parse_bootlink (const char *bootlink, int *out_entry_bootversion, char **out_osname, - char **out_bootcsum, int *out_treebootserial, GError **error) +_ostree_sysroot_parse_bootlink (const char *bootlink, const bool is_aboot, + int *out_entry_bootversion, char **out_osname, char **out_bootcsum, + int *out_treebootserial, GError **error) { static gsize regex_initialized; static GRegex *regex; + const char *to_parse = bootlink; + g_autofree char *symlink_val = NULL; + if (is_aboot) + { + symlink_val = glnx_readlinkat_malloc (-1, bootlink, NULL, error); + if (!symlink_val) + return glnx_throw (error, "Failed to read '%s' symlink", bootlink); + + to_parse = symlink_val; + } + if (g_once_init_enter (®ex_initialized)) { - regex = g_regex_new ("^/ostree/boot.([01])/([^/]+)/([^/]+)/([0-9]+)$", 0, 0, NULL); + regex + = g_regex_new (is_aboot ? "^deploy/([^/]+)/" : "^/ostree/boot.[01]/([^/]+)/", 0, 0, NULL); g_assert (regex); g_once_init_leave (®ex_initialized, 1); } g_autoptr (GMatchInfo) match = NULL; - if (!g_regex_match (regex, bootlink, 0, &match)) + if (!g_regex_match (regex, to_parse, 0, &match)) return glnx_throw (error, "Invalid ostree= argument '%s', expected " - "ostree=/ostree/boot.BOOTVERSION/OSNAME/BOOTCSUM/TREESERIAL", - bootlink); + "ostree=/ostree/boot.BOOTVERSION/OSNAME/BOOTCSUM/TREESERIAL or aboot method", + to_parse); g_autofree char *bootversion_str = g_match_info_fetch (match, 1); g_autofree char *treebootserial_str = g_match_info_fetch (match, 4); @@ -775,7 +788,10 @@ parse_deployment (OstreeSysroot *self, const char *boot_link, OstreeDeployment * g_autofree char *osname = NULL; g_autofree char *bootcsum = NULL; int treebootserial = -1; - if (!_ostree_sysroot_parse_bootlink (boot_link, &entry_boot_version, &osname, &bootcsum, + + // Note is_boot should always be false here, this boot_link is taken from BLS file, not + // /proc/cmdline, BLS files are present in aboot images + if (!_ostree_sysroot_parse_bootlink (boot_link, false, &entry_boot_version, &osname, &bootcsum, &treebootserial, error)) return FALSE; diff --git a/src/libotcore/otcore-prepare-root.c b/src/libotcore/otcore-prepare-root.c index bb7cf4bec2..19f481c10e 100644 --- a/src/libotcore/otcore-prepare-root.c +++ b/src/libotcore/otcore-prepare-root.c @@ -75,7 +75,7 @@ otcore_find_proc_cmdline_key (const char *cmdline, const char *key) // // If invalid data is found, @error will be set. gboolean -otcore_get_ostree_target (const char *cmdline, char **out_target, GError **error) +otcore_get_ostree_target (const char *cmdline, bool *is_aboot, char **out_target, GError **error) { g_assert (cmdline); g_assert (out_target && *out_target == NULL); @@ -84,8 +84,10 @@ otcore_get_ostree_target (const char *cmdline, char **out_target, GError **error // First, handle the Android boot case g_autofree char *slot_suffix = otcore_find_proc_cmdline_key (cmdline, "androidboot.slot_suffix"); + *is_aboot = false; if (slot_suffix) { + *is_aboot = true; if (strcmp (slot_suffix, "_a") == 0) { *out_target = g_strdup (slot_a); diff --git a/src/libotcore/otcore.h b/src/libotcore/otcore.h index ab22034397..79a10f1568 100644 --- a/src/libotcore/otcore.h +++ b/src/libotcore/otcore.h @@ -44,7 +44,8 @@ gboolean otcore_validate_ed25519_signature (GBytes *data, GBytes *pubkey, GBytes bool *out_valid, GError **error); char *otcore_find_proc_cmdline_key (const char *cmdline, const char *key); -gboolean otcore_get_ostree_target (const char *cmdline, char **out_target, GError **error); +gboolean otcore_get_ostree_target (const char *cmdline, bool *is_aboot, char **out_target, + GError **error); GKeyFile *otcore_load_config (int rootfs, const char *filename, GError **error); diff --git a/src/switchroot/ostree-prepare-root.c b/src/switchroot/ostree-prepare-root.c index 34d277a020..14a98b45b1 100644 --- a/src/switchroot/ostree-prepare-root.c +++ b/src/switchroot/ostree-prepare-root.c @@ -124,7 +124,8 @@ resolve_deploy_path (const char *root_mountpoint) g_autoptr (GError) error = NULL; g_autofree char *ostree_target = NULL; - if (!otcore_get_ostree_target (kernel_cmdline, &ostree_target, &error)) + bool is_aboot = false; + if (!otcore_get_ostree_target (kernel_cmdline, &is_aboot, &ostree_target, &error)) errx (EXIT_FAILURE, "Failed to determine ostree target: %s", error->message); if (!ostree_target) errx (EXIT_FAILURE, "No ostree target found"); diff --git a/tests/test-otcore.c b/tests/test-otcore.c index 4af575bf23..bc2f5a95bc 100644 --- a/tests/test-otcore.c +++ b/tests/test-otcore.c @@ -36,46 +36,48 @@ test_prepare_root_cmdline (void) { g_autoptr (GError) error = NULL; g_autofree char *target = NULL; + bool is_aboot = false; static const char *notfound_cases[] = { "", "foo", "foo=bar baz sometest", "xostree foo", "xostree=blah bar", NULL }; for (const char **iter = notfound_cases; iter && *iter; iter++) { const char *tcase = *iter; - g_assert (otcore_get_ostree_target (tcase, &target, &error)); + g_assert (otcore_get_ostree_target (tcase, &is_aboot, &target, &error)); g_assert_no_error (error); g_assert (target == NULL); } // Test the default ostree= - g_assert (otcore_get_ostree_target ("blah baz=blah ostree=/foo/bar somearg", &target, &error)); + g_assert (otcore_get_ostree_target ("blah baz=blah ostree=/foo/bar somearg", &is_aboot, &target, + &error)); g_assert_no_error (error); g_assert_cmpstr (target, ==, "/foo/bar"); free (g_steal_pointer (&target)); // Test android boot - g_assert (otcore_get_ostree_target ("blah baz=blah androidboot.slot_suffix=_b somearg", &target, - &error)); + g_assert (otcore_get_ostree_target ("blah baz=blah androidboot.slot_suffix=_b somearg", &is_aboot, + &target, &error)); g_assert_no_error (error); g_assert_cmpstr (target, ==, "/ostree/root.b"); free (g_steal_pointer (&target)); - g_assert (otcore_get_ostree_target ("blah baz=blah androidboot.slot_suffix=_a somearg", &target, - &error)); + g_assert (otcore_get_ostree_target ("blah baz=blah androidboot.slot_suffix=_a somearg", &is_aboot, + &target, &error)); g_assert_no_error (error); g_assert_cmpstr (target, ==, "/ostree/root.a"); free (g_steal_pointer (&target)); // And an expected failure to parse a "c" suffix - g_assert (!otcore_get_ostree_target ("blah baz=blah androidboot.slot_suffix=_c somearg", &target, - &error)); + g_assert (!otcore_get_ostree_target ("blah baz=blah androidboot.slot_suffix=_c somearg", + &is_aboot, &target, &error)); g_assert (error); g_assert (target == NULL); g_clear_error (&error); // And non-A/B androidboot - g_assert (otcore_get_ostree_target ("blah baz=blah androidboot.somethingelse somearg", &target, - &error)); + g_assert (otcore_get_ostree_target ("blah baz=blah androidboot.somethingelse somearg", &is_aboot, + &target, &error)); g_assert_no_error (error); g_assert_cmpstr (target, ==, "/ostree/root.a"); free (g_steal_pointer (&target));