290 lines
8.1 KiB
Diff
290 lines
8.1 KiB
Diff
From 71575829c303fe8522b46fc96b1f99f1aa4178e7 Mon Sep 17 00:00:00 2001
|
|
From: Michael Chang <mchang@suse.com>
|
|
Date: Fri, 19 Mar 2021 22:58:45 +0800
|
|
Subject: [PATCH] Workaround volatile efi boot variable
|
|
|
|
The efi variable in Microsoft Azure virtual machine is volatile that it cannot
|
|
persist across power cycling. If we use efi variable to communicate with efi
|
|
boot manager for booting a distribution, the process would silently fail as the
|
|
default loader in the efi system partition will start to take over the process
|
|
whenever the efi variable evaporated.
|
|
|
|
That will lead to undefined symbol error one day as the default path didn't
|
|
receive any grub update so it cannot keep up with new ABI requirement by
|
|
updated grub modules.
|
|
|
|
The patch will try to workaround the problem by providing grub update to the
|
|
default path along with the distribution specific one. To avoid negative side
|
|
effects of inadvertently overwritting other loader intended in default path,
|
|
care must be taken to ensure that:
|
|
|
|
1. The workaround only takes place on detected Azure virtual machine
|
|
2. The default path is not in use by shim for the secure boot
|
|
---
|
|
Makefile.util.def | 1 +
|
|
.../osdep/basic/efi_removable_fallback.c | 26 +++
|
|
grub-core/osdep/efi_removable_fallback.c | 5 +
|
|
.../osdep/linux/efi_removable_fallback.c | 151 ++++++++++++++++++
|
|
include/grub/util/install.h | 3 +
|
|
util/grub-install.c | 19 +++
|
|
6 files changed, 205 insertions(+)
|
|
create mode 100644 grub-core/osdep/basic/efi_removable_fallback.c
|
|
create mode 100644 grub-core/osdep/efi_removable_fallback.c
|
|
create mode 100644 grub-core/osdep/linux/efi_removable_fallback.c
|
|
|
|
--- a/Makefile.util.def
|
|
+++ b/Makefile.util.def
|
|
@@ -681,6 +681,9 @@
|
|
common = grub-core/osdep/journaled_fs.c;
|
|
extra_dist = grub-core/osdep/basic/journaled_fs.c;
|
|
extra_dist = grub-core/osdep/linux/journaled_fs.c;
|
|
+ common = grub-core/osdep/efi_removable_fallback.c;
|
|
+ extra_dist = grub-core/osdep/basic/efi_removable_fallback.c;
|
|
+ extra_dist = grub-core/osdep/linux/efi_removable_fallback.c;
|
|
|
|
ldadd = '$(LIBLZMA)';
|
|
ldadd = libgrubmods.a;
|
|
--- /dev/null
|
|
+++ b/grub-core/osdep/basic/efi_removable_fallback.c
|
|
@@ -0,0 +1,26 @@
|
|
+/*
|
|
+ * GRUB -- GRand Unified Bootloader
|
|
+ * Copyright (C) 2013 Free Software Foundation, Inc.
|
|
+ *
|
|
+ * GRUB is free software: you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation, either version 3 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * GRUB 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 General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
|
+ */
|
|
+
|
|
+#include <grub/util/install.h>
|
|
+
|
|
+const char *
|
|
+grub_install_efi_removable_fallback (const char *efidir, enum grub_install_plat platform)
|
|
+{
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
--- /dev/null
|
|
+++ b/grub-core/osdep/efi_removable_fallback.c
|
|
@@ -0,0 +1,5 @@
|
|
+#ifdef __linux__
|
|
+#include "linux/efi_removable_fallback.c"
|
|
+#else
|
|
+#include "basic/efi_removable_fallback.c"
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/grub-core/osdep/linux/efi_removable_fallback.c
|
|
@@ -0,0 +1,151 @@
|
|
+/*
|
|
+ * GRUB -- GRand Unified Bootloader
|
|
+ * Copyright (C) 2013 Free Software Foundation, Inc.
|
|
+ *
|
|
+ * GRUB is free software: you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation, either version 3 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * GRUB 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 General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
|
+ */
|
|
+
|
|
+#include <config.h>
|
|
+
|
|
+#include <grub/util/install.h>
|
|
+#include <grub/emu/exec.h>
|
|
+#include <grub/emu/misc.h>
|
|
+#include <string.h>
|
|
+
|
|
+static char *
|
|
+get_dmi_id (const char *id)
|
|
+{
|
|
+ FILE *fp;
|
|
+ char *buf = NULL;
|
|
+ size_t len = 0;
|
|
+
|
|
+ char *dmi_entry;
|
|
+
|
|
+ dmi_entry = grub_util_path_concat (2, "/sys/class/dmi/id", id);
|
|
+
|
|
+ fp = grub_util_fopen (dmi_entry, "r");
|
|
+ if (!fp)
|
|
+ {
|
|
+ free (dmi_entry);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (getline (&buf, &len, fp) == -1)
|
|
+ {
|
|
+ fclose (fp);
|
|
+ free (dmi_entry);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ fclose (fp);
|
|
+ free (dmi_entry);
|
|
+ return buf;
|
|
+}
|
|
+
|
|
+
|
|
+static struct dmi {
|
|
+ const char *id;
|
|
+ const char *val;
|
|
+} azure_dmi [3] = {
|
|
+ {"bios_vendor", "Microsoft Corporation"},
|
|
+ {"product_name", "Virtual Machine"},
|
|
+ {"sys_vendor", "Microsoft Corporation"},
|
|
+};
|
|
+
|
|
+static int
|
|
+is_azure (void)
|
|
+{
|
|
+ int i;
|
|
+ int n = sizeof (azure_dmi) / sizeof (struct dmi);
|
|
+
|
|
+ for (i = 0; i < n; ++i)
|
|
+ {
|
|
+ char *val;
|
|
+
|
|
+ val = get_dmi_id (azure_dmi[i].id);
|
|
+ if (!val)
|
|
+ break;
|
|
+ if (strncmp (val, azure_dmi[i].val, strlen (azure_dmi[i].val)) != 0)
|
|
+ {
|
|
+ free (val);
|
|
+ break;
|
|
+ }
|
|
+ free (val);
|
|
+ }
|
|
+
|
|
+ return (i == n) ? 1 : 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+guess_shim_installed (const char *instdir)
|
|
+{
|
|
+ const char *shim[] = {"fallback.efi", "MokManager.efi", NULL};
|
|
+ const char **s;
|
|
+
|
|
+ for (s = shim; *s ; ++s)
|
|
+ {
|
|
+ char *p = grub_util_path_concat (2, instdir, *s);
|
|
+
|
|
+ if (access (p, F_OK) == 0)
|
|
+ {
|
|
+ free (p);
|
|
+ return 1;
|
|
+ }
|
|
+ free (p);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+const char *
|
|
+grub_install_efi_removable_fallback (const char *efidir, enum grub_install_plat platform)
|
|
+{
|
|
+ char *instdir;
|
|
+
|
|
+ if (!is_azure ())
|
|
+ return NULL;
|
|
+
|
|
+ instdir = grub_util_path_concat (3, efidir, "EFI", "BOOT");
|
|
+
|
|
+ if (guess_shim_installed (instdir))
|
|
+ {
|
|
+ grub_util_info ("skip removable fallback occupied by shim");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ free (instdir);
|
|
+
|
|
+ switch (platform)
|
|
+ {
|
|
+ case GRUB_INSTALL_PLATFORM_I386_EFI:
|
|
+ return "BOOTIA32.EFI";
|
|
+ case GRUB_INSTALL_PLATFORM_X86_64_EFI:
|
|
+ return "BOOTX64.EFI";
|
|
+ case GRUB_INSTALL_PLATFORM_IA64_EFI:
|
|
+ return "BOOTIA64.EFI";
|
|
+ case GRUB_INSTALL_PLATFORM_ARM_EFI:
|
|
+ return "BOOTARM.EFI";
|
|
+ case GRUB_INSTALL_PLATFORM_ARM64_EFI:
|
|
+ return "BOOTAA64.EFI";
|
|
+ case GRUB_INSTALL_PLATFORM_RISCV32_EFI:
|
|
+ return "BOOTRISCV32.EFI";
|
|
+ case GRUB_INSTALL_PLATFORM_RISCV64_EFI:
|
|
+ return "BOOTRISCV64.EFI";
|
|
+ default:
|
|
+ grub_util_error ("%s", _("You've found a bug"));
|
|
+ break;
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
--- a/include/grub/util/install.h
|
|
+++ b/include/grub/util/install.h
|
|
@@ -303,4 +303,7 @@
|
|
|
|
int
|
|
grub_install_sync_fs_journal (const char *path);
|
|
+
|
|
+const char *
|
|
+grub_install_efi_removable_fallback (const char *efidir, enum grub_install_plat platform);
|
|
#endif
|
|
--- a/util/grub-install.c
|
|
+++ b/util/grub-install.c
|
|
@@ -901,6 +901,7 @@
|
|
const char *pkgdatadir;
|
|
char *rootdir_path;
|
|
char **rootdir_devices;
|
|
+ char *efidir_root;
|
|
|
|
grub_util_host_init (&argc, &argv);
|
|
product_version = xstrdup (PACKAGE_VERSION);
|
|
@@ -1175,6 +1176,7 @@
|
|
}
|
|
if (!efidir)
|
|
grub_util_error ("%s", _("cannot find EFI directory"));
|
|
+ efidir_root = grub_strdup (efidir);
|
|
efidir_device_names = grub_guess_root_devices (efidir);
|
|
if (!efidir_device_names || !efidir_device_names[0])
|
|
grub_util_error (_("cannot find a device for %s (is /dev mounted?)"),
|
|
@@ -2217,6 +2219,23 @@
|
|
free (grub_efi_cfg);
|
|
}
|
|
}
|
|
+ if (!removable)
|
|
+ {
|
|
+ const char *f;
|
|
+
|
|
+ f = grub_install_efi_removable_fallback (efidir_root, platform);
|
|
+ if (f)
|
|
+ {
|
|
+ char *t = grub_util_path_concat (3, efidir_root, "EFI", "BOOT");
|
|
+ char *dst = grub_util_path_concat (2, t, f);
|
|
+
|
|
+ grub_install_mkdir_p (t);
|
|
+ fprintf (stderr, _("Install to %s as fallback.\n"), dst);
|
|
+ grub_install_copy_file (imgfile, dst, 1);
|
|
+ grub_free (t);
|
|
+ grub_free (dst);
|
|
+ }
|
|
+ }
|
|
if (!removable && update_nvram)
|
|
{
|
|
char * efifile_path;
|