Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package grub2 for openSUSE:Factory checked in at 2025-04-24 17:25:03 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/grub2 (Old) and /work/SRC/openSUSE:Factory/.grub2.new.30101 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "grub2" Thu Apr 24 17:25:03 2025 rev:359 rq:1272144 version:2.12 Changes: -------- --- /work/SRC/openSUSE:Factory/grub2/grub2.changes 2025-04-20 19:55:41.350190423 +0200 +++ /work/SRC/openSUSE:Factory/.grub2.new.30101/grub2.changes 2025-04-24 17:25:14.580653304 +0200 @@ -1,0 +2,13 @@ +Wed Apr 23 09:25:57 UTC 2025 - Michael Chang <mch...@suse.com> + +- Fix reading bls fragments in file-system dependent order that is not + predictable (bsc#1241046) + * 0001-blscfg-read-fragments-in-order.patch + +------------------------------------------------------------------- +Wed Apr 23 07:55:59 UTC 2025 - Michael Chang <mch...@suse.com> + +- Fix PPC CAS reboot failure work when initiated via submenu (bsc#1241132) + * 0001-Fix-PowerPC-CAS-reboot-to-evaluate-menu-context.patch + +------------------------------------------------------------------- New: ---- 0001-Fix-PowerPC-CAS-reboot-to-evaluate-menu-context.patch 0001-blscfg-read-fragments-in-order.patch BETA DEBUG BEGIN: New:- Fix PPC CAS reboot failure work when initiated via submenu (bsc#1241132) * 0001-Fix-PowerPC-CAS-reboot-to-evaluate-menu-context.patch New: predictable (bsc#1241046) * 0001-blscfg-read-fragments-in-order.patch BETA DEBUG END: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ grub2.spec ++++++ --- /var/tmp/diff_new_pack.x15BeN/_old 2025-04-24 17:25:18.396813439 +0200 +++ /var/tmp/diff_new_pack.x15BeN/_new 2025-04-24 17:25:18.396813439 +0200 @@ -464,6 +464,8 @@ Patch291: 0006-tpm2_key_protector-Support-NV-index-handles.patch Patch292: 0007-util-grub-protect-Support-NV-index-mode.patch Patch293: grub2-string-initializer.patch +Patch294: 0001-Fix-PowerPC-CAS-reboot-to-evaluate-menu-context.patch +Patch295: 0001-blscfg-read-fragments-in-order.patch %if 0%{?suse_version} < 1600 Requires: gettext-runtime ++++++ 0001-Fix-PowerPC-CAS-reboot-to-evaluate-menu-context.patch ++++++ >From cb72de6caff51b79c0e5ef13dbd7a79754e3de35 Mon Sep 17 00:00:00 2001 From: Michael Chang <mch...@suse.com> Date: Thu, 17 Apr 2025 22:13:43 +0800 Subject: [PATCH] Fix PowerPC CAS reboot to evaluate menu context The Client Architecture Support (CAS) negotiation between the firmware and the operating system kernel can result in a reboot, allowing the firmware to reinitialize itself to satisfy the request. In this case, grub is expected to resume from the previous session by booting the entry recorded in the boot-last-label OpenFirmware property. However, the current implementation fails when a CAS-triggered reboot originates from a menu entry within a submenu. For example, when booting into a Btrfs snapshot. The root cause is that the menu context is not evaluated. As a result, if the resumed boot entry relies on any evaluated variables, the behavior becomes undefined. This patch addresses the issue by storing both the entry ID and its content in the boot-last-label property. The ID is used to descend into the correct menu context, ensuring the entry is executed in the same environment it was originally selected from. A caret (^) is used to separate the entry ID from its content. The resulting format in boot-last-label looks like this: gnulinux-simple-2315b72a-17f2-4537-bc62-63da478ce1dd^setparams 'SLES 15-SP6' set gfxpayload=text insmod gzio insmod part_gpt insmod btrfs search --no-floppy --fs-uuid --set=root 2315b72a-17f2- ... echo 'Loading Linux 6.4.0-150600.23.25-default ...' linux /boot/vmlinux-6.4.0-150600.23.25-default root=UUID= ... echo 'Loading initial ramdisk ...' initrd /boot/initrd-6.4.0-150600.23.25-default Signed-off-by: Michael Chang <mch...@suse.com> --- grub-core/normal/main.c | 60 ++++++++++++++++++++++-------- grub-core/normal/menu.c | 45 +++++++++++++++++++++- grub-core/normal/menu_entry.c | 70 +++++++++++++++++++++++++++++++++-- grub-core/script/execute.c | 7 ---- 4 files changed, 154 insertions(+), 28 deletions(-) diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c index c9eda889ca..091450e53c 100644 --- a/grub-core/normal/main.c +++ b/grub-core/normal/main.c @@ -365,21 +365,6 @@ grub_normal_execute (const char *config, int nested, int batch) { menu = read_config_file (config); -#ifdef GRUB_MACHINE_IEEE1275 - int boot; - boot = 0; - char *script = NULL; - char *dummy[1] = { NULL }; - if (! grub_ieee1275_cas_reboot (&script) && script) - { - if (! grub_script_execute_new_scope (script, 0, dummy)) - boot = 1; - } - grub_free (script); - if (boot) - grub_command_execute ("boot", 0, 0); -#endif - /* Ignore any error. */ grub_errno = GRUB_ERR_NONE; } @@ -393,7 +378,50 @@ grub_normal_execute (const char *config, int nested, int batch) { if (menu && menu->size) { - +#ifdef GRUB_MACHINE_IEEE1275 + char *entry_id = NULL; + char *delim; + const char *chosen; + + if (grub_ieee1275_cas_reboot (&entry_id) != 0) + goto enter_menu; + + if ((delim = grub_strchr (entry_id, '^')) != NULL) + *delim = '\0'; + else + goto enter_menu; + + chosen = grub_env_get ("chosen") ? : ""; + if (! grub_strlen (chosen)) + { + grub_env_set ("default", entry_id); + grub_env_set ("timeout", "0"); + } + else + { + delim = entry_id; + while ((delim = grub_strchr (delim, '>')) != NULL) + { + if (delim[1] == '>') + { + delim += 2; + continue; + } + *delim = '\0'; + if (grub_strcmp (chosen, entry_id) == 0) + { + grub_env_set ("default", delim + 1); + grub_env_set ("timeout", "0"); + break; + } + *delim++ = '>'; + } + if (delim == NULL) + grub_dprintf ("normal", "CAS triggered but find no match: %s\n", entry_id); + } + enter_menu: + grub_free (entry_id); +#endif grub_boot_time ("Entering menu"); grub_show_menu (menu, nested, 0); if (nested) diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c index dfdf0c7268..897da6abac 100644 --- a/grub-core/normal/menu.c +++ b/grub-core/normal/menu.c @@ -33,6 +33,9 @@ #include <grub/gfxterm.h> #include <grub/dl.h> #include <grub/crypttab.h> +#ifdef GRUB_MACHINE_IEEE1275 +#include <grub/ieee1275/ieee1275.h> +#endif /* Time to delay after displaying an error message about a default/fallback entry failing to boot. */ @@ -318,8 +321,31 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) grub_env_set ("default", ptr + 1); else grub_env_unset ("default"); +#ifdef GRUB_MACHINE_IEEE1275 + char *cas_entry_id = NULL; + char *cas_entry_source; + const char *id; + const char *sourcecode = entry->sourcecode; + id = grub_env_get ("chosen") ? : ""; + + if (grub_ieee1275_cas_reboot (&cas_entry_id) != 0) + goto exec_new_scope; + + if ((cas_entry_source = grub_strchr (cas_entry_id, '^')) != NULL) + *cas_entry_source++ = '\0'; + else + goto exec_new_scope; + + if (grub_strcmp (id, cas_entry_id) == 0) + sourcecode = cas_entry_source; + + exec_new_scope: + grub_script_execute_new_scope (sourcecode, entry->argc, entry->args); + grub_free (cas_entry_id); +#else grub_script_execute_new_scope (entry->sourcecode, entry->argc, entry->args); +#endif if (errs_before != grub_err_printed_errors) grub_wait_after_message (); @@ -327,8 +353,23 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) errs_before = grub_err_printed_errors; if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ()) - /* Implicit execution of boot, only if something is loaded. */ - grub_command_execute ("boot", 0, 0); + { +#ifdef GRUB_MACHINE_IEEE1275 + char *entry_data; + + entry_data = grub_xasprintf ("%s^%s", id, sourcecode); + if (entry_data) + grub_ieee1275_set_boot_last_label (entry_data); + else + grub_print_error (); + grub_free (entry_data); +#endif + /* Implicit execution of boot, only if something is loaded. */ + grub_command_execute ("boot", 0, 0); +#ifdef GRUB_MACHINE_IEEE1275 + grub_ieee1275_set_boot_last_label (""); +#endif + } if (errs_before != grub_err_printed_errors) grub_wait_after_message (); diff --git a/grub-core/normal/menu_entry.c b/grub-core/normal/menu_entry.c index 06682a396d..bbd05e5638 100644 --- a/grub-core/normal/menu_entry.c +++ b/grub-core/normal/menu_entry.c @@ -29,6 +29,9 @@ #include <grub/charset.h> #include <grub/safemath.h> #include <grub/crypttab.h> +#ifdef GRUB_MACHINE_IEEE1275 +#include <grub/ieee1275/ieee1275.h> +#endif enum update_mode { @@ -78,6 +81,9 @@ struct screen int completion_shown; int submenu; +#ifdef GRUB_MACHINE_IEEE1275 + char *id; +#endif struct per_term_screen *terms; unsigned nterms; @@ -578,6 +584,9 @@ destroy_screen (struct screen *screen) grub_free (screen->killed_text); grub_free (screen->lines); grub_free (screen->terms); +#ifdef GRUB_MACHINE_IEEE1275 + grub_free (screen->id); +#endif grub_free (screen); } @@ -599,6 +608,11 @@ make_screen (grub_menu_entry_t entry) screen->lines = grub_malloc (sizeof (struct line)); if (! screen->lines) goto fail; +#ifdef GRUB_MACHINE_IEEE1275 + screen->id = grub_strdup (entry->id); + if (! screen->id) + goto fail; +#endif /* Initialize the first line which must be always present. */ if (! init_line (screen, screen->lines)) @@ -1215,14 +1229,64 @@ run (struct screen *screen) script[size] = '\0'; } grub_script_execute_new_scope (script, 0, dummy); - grub_free (script); if (errs_before != grub_err_printed_errors) grub_wait_after_message (); if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ()) - /* Implicit execution of boot, only if something is loaded. */ - grub_command_execute ("boot", 0, 0); + { +#ifdef GRUB_MACHINE_IEEE1275 + char *entry_data = NULL; + const char *chosen; + const char *ptr; + grub_size_t sz = 0; + char *buf = NULL; + char *optr; + + chosen = grub_env_get ("chosen") ? : ""; + for (ptr = screen->id; *ptr; ptr++) + sz += (*ptr == '>') ? 2 : 1; + sz++; + sz += grub_strlen (chosen); + sz++; + buf = grub_malloc (sz); + if (!buf) + { + grub_print_error (); + goto exec_boot; + } + optr = buf; + if (*chosen != '\0') + { + optr = grub_stpcpy (optr, chosen); + *optr++ = '>'; + } + for (ptr = screen->id; *ptr; ptr++) + { + if (*ptr == '>') + *optr++ = '>'; + *optr++ = *ptr; + } + *optr = 0; + entry_data = grub_xasprintf ("%s^%s", buf, script); + if (entry_data) + grub_ieee1275_set_boot_last_label (entry_data); + else + grub_print_error (); + grub_free (entry_data); + grub_free (buf); + grub_free (script); + script = NULL; + exec_boot: +#endif + /* Implicit execution of boot, only if something is loaded. */ + grub_command_execute ("boot", 0, 0); +#ifdef GRUB_MACHINE_IEEE1275 + grub_ieee1275_set_boot_last_label (""); +#endif + } + + grub_free (script); if (screen->submenu) { diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c index dab8fd2aeb..14ff09094f 100644 --- a/grub-core/script/execute.c +++ b/grub-core/script/execute.c @@ -28,9 +28,6 @@ #include <grub/extcmd.h> #include <grub/i18n.h> #include <grub/verify.h> -#ifdef GRUB_MACHINE_IEEE1275 -#include <grub/ieee1275/ieee1275.h> -#endif /* Max digits for a char is 3 (0xFF is 255), similarly for an int it is sizeof (int) * 3, and one extra for a possible -ve sign. */ @@ -886,10 +883,6 @@ grub_script_execute_sourcecode (const char *source) grub_err_t ret = 0; struct grub_script *parsed_script; -#ifdef GRUB_MACHINE_IEEE1275 - grub_ieee1275_set_boot_last_label (source); -#endif - while (source) { char *line; -- 2.49.0 ++++++ 0001-blscfg-read-fragments-in-order.patch ++++++ >From 434b014e20ebb7930599fe30e09441af6b449fef Mon Sep 17 00:00:00 2001 From: Michael Chang <mch...@suse.com> Date: Mon, 14 Apr 2025 08:52:26 +0800 Subject: [PATCH] blscfg: read fragments in order The PCR 9 measurements of BLS entry files made by blscfg module are performed in "readdir" order, which depends on the filesystem and is therefore inherently unpredictable and unreliable. To make future PCR values more predictable, the entries should be processed in a deterministic order, such as alphabetically by filename. Signed-off-by: Michael Chang <mch...@suse.com> --- grub-core/commands/blscfg.c | 164 ++++++++++++++++++++++-------------- 1 file changed, 103 insertions(+), 61 deletions(-) diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c index 343c7ae989..10996722cf 100644 --- a/grub-core/commands/blscfg.c +++ b/grub-core/commands/blscfg.c @@ -55,6 +55,15 @@ struct keyval static struct bls_entry *entries = NULL; +struct bls_fragment +{ + struct bls_fragment *next; + struct bls_fragment *prev; + char *filename; +}; +typedef struct bls_fragment *bls_fragment_t; +static bls_fragment_t fragments; + #define FOR_BLS_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries) /* BLS appears to make paths relative to the filesystem that snippets are @@ -466,69 +475,41 @@ struct read_entry_info { grub_file_t file; }; -static int read_entry ( - const char *filename, - const struct grub_dirhook_info *dirhook_info UNUSED, - void *data) +static int +read_entry (const char *filename) { grub_size_t m = 0, n, clip = 0; int rc = 0; char *p = NULL; grub_file_t f = NULL; struct bls_entry *entry; - struct read_entry_info *info = (struct read_entry_info *)data; - - grub_dprintf ("blscfg", "filename: \"%s\"\n", filename); + char *slash; - n = grub_strlen (filename); + grub_dprintf ("blscfg", "read_entry: \"%s\"\n", filename); - if (info->file) - { - f = info->file; - } - else - { - if (filename[0] == '.') - return 0; + f = grub_file_open (filename, GRUB_FILE_TYPE_CONFIG); - if (n <= 5) - return 0; - - if (grub_strcmp (filename + n - 5, ".conf") != 0) - return 0; - - p = grub_xasprintf ("(%s)%s/%s", info->devid, info->dirname, filename); - - f = grub_file_open (p, GRUB_FILE_TYPE_CONFIG); - if (!f) - goto finish; - } + if (!f) + goto finish; entry = grub_zalloc (sizeof (*entry)); if (!entry) goto finish; - if (info->file) - { - char *slash; + /* Strip .conf */ + n = grub_strlen (filename); - if (n > 5 && !grub_strcmp (filename + n - 5, ".conf") == 0) - clip = 5; + if (n > 5 && !grub_strcmp (filename + n - 5, ".conf") == 0) + clip = 5; - slash = grub_strrchr (filename, '/'); - if (!slash) - slash = grub_strrchr (filename, '\\'); + slash = grub_strrchr (filename, '/'); + if (!slash) + slash = grub_strrchr (filename, '\\'); - while (*slash == '/' || *slash == '\\') - slash++; + while (*slash == '/' || *slash == '\\') + slash++; - m = slash ? slash - filename : 0; - } - else - { - m = 0; - clip = 5; - } + m = slash ? slash - filename : 0; n -= m; entry->filename = grub_strndup(filename + m, n - clip); @@ -573,10 +554,7 @@ static int read_entry ( if (rc < 0) break; } - - if (info->devid) - entry->devid = grub_strdup(info->devid); - + entry->devid = grub_file_get_device_name (filename); if (!rc) bls_add_entry(entry); @@ -590,6 +568,73 @@ finish: return 0; } +static int +collect_fragments ( + const char *filename, + const struct grub_dirhook_info *dirhook_info UNUSED, + void *data) +{ + grub_size_t n; + char *p = NULL; + struct read_entry_info *info = (struct read_entry_info *)data; + bls_fragment_t fragment, f, last; + + if (filename[0] == '.') + return 0; + + n = grub_strlen (filename); + if (n <= 5) + return 0; + + if (grub_strcmp (filename + n - 5, ".conf") != 0) + return 0; + + p = grub_xasprintf ("(%s)%s/%s", info->devid, info->dirname, filename); + + fragment = grub_zalloc (sizeof (*fragment)); + fragment->filename = grub_strdup (p); + + if (!fragments) + { + fragments = fragment; + return 0; + } + + FOR_LIST_ELEMENTS (f, fragments) + { + int rc; + rc = grub_strcmp(fragment->filename, f->filename); + if (!rc) + { + grub_free (fragment); + return 0; + } + if (rc < 0) + { + fragment->next = f; + if (f->prev) + f->prev->next = fragment; + fragment->prev = f->prev; + f->prev = fragment; + if (f == fragments) + { + fragments = fragment; + fragment->prev = NULL; + } + return 0; + } + last = f; + } + + if (last) + { + last->next = fragment; + fragment->prev = last; + } + + return 0; +} + static grub_envblk_t saved_env = NULL; static int UNUSED @@ -1007,6 +1052,7 @@ static int find_entry (struct find_entry_info *info) const char *blsdir = info->dirname; int fallback = 0; int r = 0; + bls_fragment_t fragment; if (!blsdir) { blsdir = grub_env_get ("blsdir"); @@ -1024,8 +1070,14 @@ static int find_entry (struct find_entry_info *info) read_entry_info.devid = info->devid; read_fallback: - r = blsdir_fs->fs_dir (blsdir_dev, read_entry_info.dirname, read_entry, + r = blsdir_fs->fs_dir (blsdir_dev, read_entry_info.dirname, collect_fragments, &read_entry_info); + FOR_LIST_ELEMENTS (fragment, fragments) + { + grub_dprintf ("blscfg", "read_entry: %s\n", fragment->filename); + read_entry (fragment->filename); + } + if (r != 0) { grub_dprintf ("blscfg", "read_entry returned error\n"); grub_err_t e; @@ -1060,21 +1112,11 @@ bls_load_entries (const char *path) .fs = NULL, .dirname = NULL, }; - struct read_entry_info rei = { - .devid = NULL, - .dirname = NULL, - }; if (path) { len = grub_strlen (path); if (grub_strcmp (path + len - 5, ".conf") == 0) { - rei.file = grub_file_open (path, GRUB_FILE_TYPE_CONFIG); - if (!rei.file) - return grub_errno; - /* - * read_entry() closes the file - */ - return read_entry(path, NULL, &rei); + return read_entry (path); } else if (path[0] == '(') { devid = path + 1; -- 2.49.0