commit 689da84e7c0abf82a2ada0276372cdcc5f90e25f Author: zyppe <210hcl@gmail.com> Date: Mon Feb 5 14:40:06 2024 +0800 Initialize for grub2 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..03e9828 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +grub-2.06.tar.xz diff --git a/.grub2.metadata b/.grub2.metadata new file mode 100644 index 0000000..234dcfe --- /dev/null +++ b/.grub2.metadata @@ -0,0 +1 @@ +8315e0a0205e3a7ee3d0580cbe97c88b3029f6b1e40a0934e7e80756dd36f85e grub-2.06.tar.xz diff --git a/0001-30_uefi-firmware-fix-printf-format-with-null-byte.patch b/0001-30_uefi-firmware-fix-printf-format-with-null-byte.patch new file mode 100644 index 0000000..642b7d2 --- /dev/null +++ b/0001-30_uefi-firmware-fix-printf-format-with-null-byte.patch @@ -0,0 +1,88 @@ +From 47eddcfc6859f269bb3cfaf95d5b33502cafd9ec Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Mon, 21 Jun 2021 05:11:18 +0000 +Subject: [PATCH] 30_uefi-firmware: fix printf format with null byte +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +On a Raspberry Pi 4, the OsIndications variable is set as following + + $ od -An -t u1 /sys/firmware/efi/efivars/OsIndicationsSupported-8be4df61-93ca-11d2-aa0d-00e098032b8c + 6 0 0 0 0 0 0 0 0 0 0 0 + +The fifth byte indicates there's no boot to uefi firmware support as no +bit is set. However the /etc/grub.d/30_uefi-firmware mistakenly detects +that from the grub-mkconfig output. + + /etc/grub.d/30_uefi-firmware: line 34: warning: command substitution: ignored null byte in input + Adding boot menu entry for UEFI Firmware Settings ... + +The warning has dictated that the null byte is ignored from the printf +input arguments so that the expression of + + rintf 0x%x \'"$(cat $OS_INDICATIONS | cut -b5)"\') + +becomes + + printf 0x%x \'""\' + 0x27 + +The numeric value of trailing character \' is outputted instead of the +null byte. + +From the printf manual, there's description to the synax of formatting +the numeric value ouput of a character. + +"If the leading character of a numeric argument is ‘"’ or ‘'’ then its +value is the numeric value of the immediately following character. Any +remaining characters are silently ignored if the POSIXLY_CORRECT +environment variable is set; otherwise, a warning is printed. For +example, ‘printf "%d" "'a"’ outputs ‘97’ on hosts that use the ASCII +character set, since ‘a’ has the numeric value 97 in ASCII." + +From the descrption the trailing \' appears to be superfluous and should +get removed to have correct output. + + printf 0x%x \'"" + 0x0 + +In additon to suppress the warning message of ignored null byte in +input, we can delete it so an empty string is used. + +To illustrate the problem using echo as example + + printf 0x%x \'"$(echo -e '\x00')" + -bash: warning: command substitution: ignored null byte in input + 0x0 + +And here using tr to delete the null character + + printf 0x%x \'"$(echo -e '\x00'| tr -d '\000')" + +The expression above is substituted to + + printf 0x%x \'"" + 0x0 + +Signed-off-by: Michael Chang +--- + util/grub.d/30_uefi-firmware.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/util/grub.d/30_uefi-firmware.in b/util/grub.d/30_uefi-firmware.in +index d344d3883..d069f2727 100644 +--- a/util/grub.d/30_uefi-firmware.in ++++ b/util/grub.d/30_uefi-firmware.in +@@ -31,7 +31,7 @@ EFI_GLOBAL_VARIABLE=8be4df61-93ca-11d2-aa0d-00e098032b8c + OS_INDICATIONS="$EFI_VARS_DIR/OsIndicationsSupported-$EFI_GLOBAL_VARIABLE" + + if [ -e "$OS_INDICATIONS" ] && \ +- [ "$(( $(printf 0x%x \'"$(cat $OS_INDICATIONS | cut -b5)"\') & 1 ))" = 1 ]; then ++ [ "$(( $(printf 0x%x \'"$(cat $OS_INDICATIONS | cut -b5 | tr -d '\000')") & 1 ))" = 1 ]; then + LABEL="UEFI Firmware Settings" + + gettext_printf "Adding boot menu entry for UEFI Firmware Settings ...\n" >&2 +-- +2.26.2 + diff --git a/0001-Add-grub_envblk_buf-helper-function.patch b/0001-Add-grub_envblk_buf-helper-function.patch new file mode 100644 index 0000000..4b994d5 --- /dev/null +++ b/0001-Add-grub_envblk_buf-helper-function.patch @@ -0,0 +1,68 @@ +From a326e486bdcf99e6be973ba54c0abfb6d2d95b73 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Mon, 17 Jan 2022 17:45:00 +0800 +Subject: [PATCH 1/5] Add grub_envblk_buf helper function + +This helps in creation and initialization of memory buffer for +environment block of given size. + +Signed-off-by: Michael Chang +--- + grub-core/lib/envblk.c | 12 ++++++++++++ + include/grub/lib/envblk.h | 1 + + util/grub-editenv.c | 4 +--- + 3 files changed, 14 insertions(+), 3 deletions(-) + +diff --git a/grub-core/lib/envblk.c b/grub-core/lib/envblk.c +index 2e4e78b132..24efbe7ffa 100644 +--- a/grub-core/lib/envblk.c ++++ b/grub-core/lib/envblk.c +@@ -23,6 +23,18 @@ + #include + #include + ++char * ++grub_envblk_buf (grub_size_t size) ++{ ++ char *buf; ++ ++ buf = grub_malloc (size); ++ grub_memcpy (buf, GRUB_ENVBLK_SIGNATURE, sizeof (GRUB_ENVBLK_SIGNATURE) - 1); ++ grub_memset (buf + sizeof (GRUB_ENVBLK_SIGNATURE) - 1, '#', size - sizeof (GRUB_ENVBLK_SIGNATURE) + 1); ++ ++ return buf; ++} ++ + grub_envblk_t + grub_envblk_open (char *buf, grub_size_t size) + { +diff --git a/include/grub/lib/envblk.h b/include/grub/lib/envblk.h +index c3e6559217..83f3fcf841 100644 +--- a/include/grub/lib/envblk.h ++++ b/include/grub/lib/envblk.h +@@ -31,6 +31,7 @@ struct grub_envblk + }; + typedef struct grub_envblk *grub_envblk_t; + ++char *grub_envblk_buf (grub_size_t size); + grub_envblk_t grub_envblk_open (char *buf, grub_size_t size); + int grub_envblk_set (grub_envblk_t envblk, const char *name, const char *value); + void grub_envblk_delete (grub_envblk_t envblk, const char *name); +diff --git a/util/grub-editenv.c b/util/grub-editenv.c +index b8219335f7..a02d3f2a63 100644 +--- a/util/grub-editenv.c ++++ b/util/grub-editenv.c +@@ -210,9 +210,7 @@ create_envblk_fs (void) + if (! fp) + grub_util_error (_("cannot open `%s': %s"), device, strerror (errno)); + +- buf = xmalloc (size); +- memcpy (buf, GRUB_ENVBLK_SIGNATURE, sizeof (GRUB_ENVBLK_SIGNATURE) - 1); +- memset (buf + sizeof (GRUB_ENVBLK_SIGNATURE) - 1, '#', size - sizeof (GRUB_ENVBLK_SIGNATURE) + 1); ++ buf = grub_envblk_buf (size); + + if (fseek (fp, offset, SEEK_SET) < 0) + grub_util_error (_("cannot seek `%s': %s"), device, strerror (errno)); +-- +2.34.1 + diff --git a/0001-Add-support-for-Linux-EFI-stub-loading-on-aarch64.patch b/0001-Add-support-for-Linux-EFI-stub-loading-on-aarch64.patch new file mode 100644 index 0000000..316fc57 --- /dev/null +++ b/0001-Add-support-for-Linux-EFI-stub-loading-on-aarch64.patch @@ -0,0 +1,523 @@ +From db4da8095b5ba722d22502c8d090e66816a5577d Mon Sep 17 00:00:00 2001 +From: Matthew Garrett +Date: Fri, 6 Nov 2020 08:36:36 +0000 +Subject: [PATCH 1/9] Add support for Linux EFI stub loading on aarch64. + +Add support for Linux EFI stub loading on aarch64. + +v1: +Make efi handoff the default loader for arm64 platform. + +v2: +The efi shim_lock verifier has been moved to grub core so local +shim_lock protocol is no longer needed here for aarch64 efi to verify +the loaded kernel image. From now on the framework will take care the +verificaion, consolidating the integration of various security verifiers +like secure boot, gpg and tpm. + +--- + grub-core/Makefile.core.def | 4 +- + grub-core/loader/arm64/efi/linux.c | 443 +++++++++++++++++++++++++++++ + include/grub/arm/linux.h | 9 + + include/grub/arm64/linux.h | 10 + + 4 files changed, 465 insertions(+), 1 deletion(-) + create mode 100644 grub-core/loader/arm64/efi/linux.c + +Index: grub-2.06~rc1/grub-core/Makefile.core.def +=================================================================== +--- grub-2.06~rc1.orig/grub-core/Makefile.core.def ++++ grub-2.06~rc1/grub-core/Makefile.core.def +@@ -1812,7 +1812,7 @@ module = { + arm_coreboot = loader/arm/linux.c; + arm_efi = loader/arm64/linux.c; + arm_uboot = loader/arm/linux.c; +- arm64 = loader/arm64/linux.c; ++ arm64 = loader/arm64/efi/linux.c; + riscv32 = loader/riscv/linux.c; + riscv64 = loader/riscv/linux.c; + emu = loader/emu/linux.c; +@@ -1879,7 +1879,7 @@ module = { + + module = { + name = linuxefi; +- efi = lib/fake_module.c; ++ x86 = lib/fake_module.c; + enable = i386_efi; + enable = x86_64_efi; + }; +Index: grub-2.06~rc1/grub-core/loader/arm64/efi/linux.c +=================================================================== +--- /dev/null ++++ grub-2.06~rc1/grub-core/loader/arm64/efi/linux.c +@@ -0,0 +1,411 @@ ++/* ++ * 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 . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static grub_dl_t my_mod; ++static int loaded; ++ ++static void *kernel_addr; ++static grub_uint64_t kernel_size; ++static grub_uint32_t handover_offset; ++ ++static char *linux_args; ++static grub_uint32_t cmdline_size; ++ ++static grub_addr_t initrd_start; ++static grub_addr_t initrd_end; ++ ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-align" ++ ++typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *); ++ ++static grub_err_t ++grub_efi_linux_boot (void *kernel_address, grub_off_t offset, ++ void *kernel_params) ++{ ++ handover_func hf; ++ ++ hf = (handover_func)((char *)kernel_address + offset); ++ hf (grub_efi_image_handle, grub_efi_system_table, kernel_params); ++ ++ return GRUB_ERR_BUG; ++} ++ ++#pragma GCC diagnostic pop ++ ++grub_err_t ++grub_arch_efi_linux_check_image (struct linux_arch_kernel_header * lh) ++{ ++ if (lh->magic != GRUB_LINUX_ARMXX_MAGIC_SIGNATURE) ++ return grub_error(GRUB_ERR_BAD_OS, "invalid magic number"); ++ ++ if ((lh->code0 & 0xffff) != GRUB_PE32_MAGIC) ++ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ N_("plain image kernel not supported - rebuild with CONFIG_(U)EFI_STUB enabled")); ++ ++ grub_dprintf ("linux", "UEFI stub kernel:\n"); ++ grub_dprintf ("linux", "PE/COFF header @ %08x\n", lh->hdr_offset); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++finalize_params_linux (void) ++{ ++ grub_efi_loaded_image_t *loaded_image = NULL; ++ int node, retval, len; ++ ++ void *fdt; ++ ++ fdt = grub_fdt_load (GRUB_EFI_LINUX_FDT_EXTRA_SPACE); ++ ++ if (!fdt) ++ goto failure; ++ ++ node = grub_fdt_find_subnode (fdt, 0, "chosen"); ++ if (node < 0) ++ node = grub_fdt_add_subnode (fdt, 0, "chosen"); ++ ++ if (node < 1) ++ goto failure; ++ ++ /* Set initrd info */ ++ if (initrd_start && initrd_end > initrd_start) ++ { ++ grub_dprintf ("linux", "Initrd @ %p-%p\n", ++ (void *) initrd_start, (void *) initrd_end); ++ ++ retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-start", ++ initrd_start); ++ if (retval) ++ goto failure; ++ retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-end", ++ initrd_end); ++ if (retval) ++ goto failure; ++ } ++ ++ if (grub_fdt_install() != GRUB_ERR_NONE) ++ goto failure; ++ ++ grub_dprintf ("linux", "Installed/updated FDT configuration table @ %p\n", ++ fdt); ++ ++ /* Convert command line to UCS-2 */ ++ loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); ++ if (!loaded_image) ++ goto failure; ++ ++ loaded_image->load_options_size = len = ++ (grub_strlen (linux_args) + 1) * sizeof (grub_efi_char16_t); ++ loaded_image->load_options = ++ grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size)); ++ if (!loaded_image->load_options) ++ return grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters"); ++ ++ loaded_image->load_options_size = ++ 2 * grub_utf8_to_utf16 (loaded_image->load_options, len, ++ (grub_uint8_t *) linux_args, len, NULL); ++ ++ return GRUB_ERR_NONE; ++ ++failure: ++ grub_fdt_unload(); ++ return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT"); ++} ++ ++static void ++free_params (void) ++{ ++ grub_efi_loaded_image_t *loaded_image = NULL; ++ ++ loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); ++ if (loaded_image) ++ { ++ if (loaded_image->load_options) ++ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_efi_uintn_t)loaded_image->load_options, ++ GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size)); ++ loaded_image->load_options = NULL; ++ loaded_image->load_options_size = 0; ++ } ++} ++ ++grub_err_t ++grub_arch_efi_linux_boot_image (grub_addr_t addr, ++ grub_size_t size __attribute__ ((unused)), ++ char *args) ++{ ++ grub_err_t retval; ++ ++ retval = finalize_params_linux (); ++ if (retval != GRUB_ERR_NONE) ++ return grub_errno; ++ ++ grub_dprintf ("linux", "linux command line: '%s'\n", args); ++ ++ retval = grub_efi_linux_boot ((char *)addr, handover_offset, (void *)addr); ++ ++ /* Never reached... */ ++ free_params(); ++ return retval; ++} ++ ++static grub_err_t ++grub_linux_boot (void) ++{ ++ return (grub_arch_efi_linux_boot_image ((grub_addr_t)kernel_addr, kernel_size, linux_args)); ++} ++ ++static grub_err_t ++grub_linux_unload (void) ++{ ++ grub_dl_unref (my_mod); ++ loaded = 0; ++ if (initrd_start) ++ grub_efi_free_pages ((grub_efi_physical_address_t) initrd_start, ++ GRUB_EFI_BYTES_TO_PAGES (initrd_end - initrd_start)); ++ initrd_start = initrd_end = 0; ++ grub_free (linux_args); ++ if (kernel_addr) ++ grub_efi_free_pages ((grub_addr_t) kernel_addr, ++ GRUB_EFI_BYTES_TO_PAGES (kernel_size)); ++ grub_fdt_unload (); ++ return GRUB_ERR_NONE; ++} ++ ++/* ++ * As per linux/Documentation/arm/Booting ++ * ARM initrd needs to be covered by kernel linear mapping, ++ * so place it in the first 512MB of DRAM. ++ * ++ * As per linux/Documentation/arm64/booting.txt ++ * ARM64 initrd needs to be contained entirely within a 1GB aligned window ++ * of up to 32GB of size that covers the kernel image as well. ++ * Since the EFI stub loader will attempt to load the kernel near start of ++ * RAM, place the buffer in the first 32GB of RAM. ++ */ ++#ifdef __arm__ ++#define INITRD_MAX_ADDRESS_OFFSET (512U * 1024 * 1024) ++#else /* __aarch64__ */ ++#define INITRD_MAX_ADDRESS_OFFSET (32ULL * 1024 * 1024 * 1024) ++#endif ++ ++/* ++ * This function returns a pointer to a legally allocated initrd buffer, ++ * or NULL if unsuccessful ++ */ ++static void * ++allocate_initrd_mem (int initrd_pages) ++{ ++ grub_addr_t max_addr; ++ ++ if (grub_efi_get_ram_base (&max_addr) != GRUB_ERR_NONE) ++ return NULL; ++ ++ max_addr += INITRD_MAX_ADDRESS_OFFSET - 1; ++ ++ return grub_efi_allocate_pages_real (max_addr, initrd_pages, ++ GRUB_EFI_ALLOCATE_MAX_ADDRESS, ++ GRUB_EFI_LOADER_DATA); ++} ++ ++static grub_err_t ++grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), ++ int argc, char *argv[]) ++{ ++ struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 }; ++ int initrd_size, initrd_pages; ++ void *initrd_mem = NULL; ++ ++ if (argc == 0) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); ++ goto fail; ++ } ++ ++ if (!loaded) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("you need to load the kernel first")); ++ goto fail; ++ } ++ ++ if (grub_initrd_init (argc, argv, &initrd_ctx)) ++ goto fail; ++ ++ initrd_size = grub_get_initrd_size (&initrd_ctx); ++ grub_dprintf ("linux", "Loading initrd\n"); ++ ++ initrd_pages = (GRUB_EFI_BYTES_TO_PAGES (initrd_size)); ++ initrd_mem = allocate_initrd_mem (initrd_pages); ++ ++ if (!initrd_mem) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ goto fail; ++ } ++ ++ if (grub_initrd_load (&initrd_ctx, argv, initrd_mem)) ++ goto fail; ++ ++ initrd_start = (grub_addr_t) initrd_mem; ++ initrd_end = initrd_start + initrd_size; ++ grub_dprintf ("linux", "[addr=%p, size=0x%x]\n", ++ (void *) initrd_start, initrd_size); ++ ++ fail: ++ grub_initrd_close (&initrd_ctx); ++ if (initrd_mem && !initrd_start) ++ grub_efi_free_pages ((grub_addr_t) initrd_mem, initrd_pages); ++ ++ return grub_errno; ++} ++ ++static grub_err_t ++grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), ++ int argc, char *argv[]) ++{ ++ grub_file_t file = 0; ++ struct linux_arch_kernel_header lh; ++ struct grub_armxx_linux_pe_header *pe; ++ grub_err_t err; ++ ++ grub_dl_ref (my_mod); ++ ++ if (argc == 0) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); ++ goto fail; ++ } ++ ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); ++ if (!file) ++ goto fail; ++ ++ kernel_size = grub_file_size (file); ++ ++ if (grub_file_read (file, &lh, sizeof (lh)) < (long) sizeof (lh)) ++ return grub_errno; ++ ++ if (grub_arch_efi_linux_check_image (&lh) != GRUB_ERR_NONE) ++ goto fail; ++ ++ grub_loader_unset(); ++ ++ grub_dprintf ("linux", "kernel file size: %lld\n", (long long) kernel_size); ++ kernel_addr = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (kernel_size)); ++ grub_dprintf ("linux", "kernel numpages: %lld\n", ++ (long long) GRUB_EFI_BYTES_TO_PAGES (kernel_size)); ++ if (!kernel_addr) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ goto fail; ++ } ++ ++ grub_file_seek (file, 0); ++ if (grub_file_read (file, kernel_addr, kernel_size) ++ < (grub_int64_t) kernel_size) ++ { ++ if (!grub_errno) ++ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), argv[0]); ++ goto fail; ++ } ++ ++ grub_dprintf ("linux", "kernel @ %p\n", kernel_addr); ++ ++ pe = (void *)((unsigned long)kernel_addr + lh.hdr_offset); ++ handover_offset = pe->opt.entry_addr; ++ ++ cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE); ++ linux_args = grub_malloc (cmdline_size); ++ if (!linux_args) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ goto fail; ++ } ++ grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE)); ++ err = grub_create_loader_cmdline (argc, argv, ++ linux_args + sizeof (LINUX_IMAGE) - 1, ++ cmdline_size, ++ GRUB_VERIFY_KERNEL_CMDLINE); ++ if (err) ++ goto fail; ++ ++ if (grub_errno == GRUB_ERR_NONE) ++ { ++ grub_loader_set (grub_linux_boot, grub_linux_unload, 0); ++ loaded = 1; ++ } ++ ++fail: ++ if (file) ++ grub_file_close (file); ++ ++ if (grub_errno != GRUB_ERR_NONE) ++ { ++ grub_dl_unref (my_mod); ++ loaded = 0; ++ } ++ ++ if (linux_args && !loaded) ++ grub_free (linux_args); ++ ++ if (kernel_addr && !loaded) ++ grub_efi_free_pages ((grub_addr_t) kernel_addr, ++ GRUB_EFI_BYTES_TO_PAGES (kernel_size)); ++ ++ return grub_errno; ++} ++ ++ ++static grub_command_t cmd_linux, cmd_initrd; ++ ++GRUB_MOD_INIT (linux) ++{ ++ cmd_linux = grub_register_command ("linux", grub_cmd_linux, 0, ++ N_("Load Linux.")); ++ cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, 0, ++ N_("Load initrd.")); ++ my_mod = mod; ++} ++ ++GRUB_MOD_FINI (linux) ++{ ++ grub_unregister_command (cmd_linux); ++ grub_unregister_command (cmd_initrd); ++} +Index: grub-2.06~rc1/include/grub/arm/linux.h +=================================================================== +--- grub-2.06~rc1.orig/include/grub/arm/linux.h ++++ grub-2.06~rc1/include/grub/arm/linux.h +@@ -20,6 +20,7 @@ + #ifndef GRUB_ARM_LINUX_HEADER + #define GRUB_ARM_LINUX_HEADER 1 + ++#include + #include "system.h" + + #define GRUB_LINUX_ARM_MAGIC_SIGNATURE 0x016f2818 +@@ -34,9 +35,17 @@ struct linux_arm_kernel_header { + grub_uint32_t hdr_offset; + }; + ++struct grub_arm_linux_pe_header ++{ ++ grub_uint32_t magic; ++ struct grub_pe32_coff_header coff; ++ struct grub_pe32_optional_header opt; ++}; ++ + #if defined(__arm__) + # define GRUB_LINUX_ARMXX_MAGIC_SIGNATURE GRUB_LINUX_ARM_MAGIC_SIGNATURE + # define linux_arch_kernel_header linux_arm_kernel_header ++# define grub_armxx_linux_pe_header grub_arm_linux_pe_header + #endif + + #if defined GRUB_MACHINE_UBOOT +Index: grub-2.06~rc1/include/grub/arm64/linux.h +=================================================================== +--- grub-2.06~rc1.orig/include/grub/arm64/linux.h ++++ grub-2.06~rc1/include/grub/arm64/linux.h +@@ -20,6 +20,7 @@ + #define GRUB_ARM64_LINUX_HEADER 1 + + #include ++#include + + #define GRUB_LINUX_ARM64_MAGIC_SIGNATURE 0x644d5241 /* 'ARM\x64' */ + +@@ -38,9 +39,17 @@ struct linux_arm64_kernel_header + grub_uint32_t hdr_offset; /* Offset of PE/COFF header */ + }; + ++struct grub_arm64_linux_pe_header ++{ ++ grub_uint32_t magic; ++ struct grub_pe32_coff_header coff; ++ struct grub_pe64_optional_header opt; ++}; ++ + #if defined(__aarch64__) + # define GRUB_LINUX_ARMXX_MAGIC_SIGNATURE GRUB_LINUX_ARM64_MAGIC_SIGNATURE + # define linux_arch_kernel_header linux_arm64_kernel_header ++# define grub_armxx_linux_pe_header grub_arm64_linux_pe_header + #endif + + #endif /* ! GRUB_ARM64_LINUX_HEADER */ diff --git a/0001-Factor-out-grub_efi_linux_boot.patch b/0001-Factor-out-grub_efi_linux_boot.patch new file mode 100644 index 0000000..62c1cc9 --- /dev/null +++ b/0001-Factor-out-grub_efi_linux_boot.patch @@ -0,0 +1,228 @@ +From 82d95254ca0496c8843113665bb9a99876101025 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Fri, 8 Oct 2021 13:36:45 +0800 +Subject: [PATCH 01/11] Factor out grub_efi_linux_boot + +Both x86 and arm64 on efi are using handover protocol to boot linux +kernel. To enable better code reuse, factor out grub_efi_linux_boot from +arm64 so that it can be shared with x86 platform for the common fixes. + +Signed-off-by: Michael Chang +--- + grub-core/Makefile.core.def | 1 + + grub-core/loader/arm64/efi/linux.c | 35 +----------------- + grub-core/loader/efi/linux.c | 58 ++++++++++++++++++++++++++++++ + grub-core/loader/i386/efi/linux.c | 13 ++----- + include/grub/efi/linux.h | 29 +++++++++++++++ + 5 files changed, 92 insertions(+), 44 deletions(-) + create mode 100644 grub-core/loader/efi/linux.c + create mode 100644 include/grub/efi/linux.h + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index b5328d7a0..46a488131 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -1834,6 +1834,7 @@ module = { + riscv64 = loader/riscv/linux.c; + emu = loader/emu/linux.c; + common = loader/linux.c; ++ efi = loader/efi/linux.c; + }; + + module = { +diff --git a/grub-core/loader/arm64/efi/linux.c b/grub-core/loader/arm64/efi/linux.c +index 87cb2f97c..0ebdc48b7 100644 +--- a/grub-core/loader/arm64/efi/linux.c ++++ b/grub-core/loader/arm64/efi/linux.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -51,40 +52,6 @@ static grub_uint32_t cmdline_size; + static grub_addr_t initrd_start; + static grub_addr_t initrd_end; + +-#pragma GCC diagnostic push +-#pragma GCC diagnostic ignored "-Wcast-align" +- +-typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *); +- +-static grub_err_t +-grub_efi_linux_boot (void *kernel_address, grub_off_t offset, +- void *kernel_params) +-{ +- grub_efi_loaded_image_t *loaded_image = NULL; +- handover_func hf; +- +- /* +- * Since the EFI loader is not calling the LoadImage() and StartImage() +- * services for loading the kernel and booting respectively, it has to +- * set the Loaded Image base address. +- */ +- loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); +- if (loaded_image) +- loaded_image->image_base = kernel_addr; +- else +- grub_dprintf ("linux", "Loaded Image base address could not be set\n"); +- +- grub_dprintf ("linux", "kernel_addr: %p handover_offset: %p params: %p\n", +- kernel_address, (void *)(grub_efi_uintn_t)offset, kernel_params); +- hf = (handover_func)((char *)kernel_address + offset); +- grub_dprintf ("linux", "handover_func() = %p\n", hf); +- hf (grub_efi_image_handle, grub_efi_system_table, kernel_params); +- +- return GRUB_ERR_BUG; +-} +- +-#pragma GCC diagnostic pop +- + grub_err_t + grub_arch_efi_linux_check_image (struct linux_arch_kernel_header * lh) + { +diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c +new file mode 100644 +index 000000000..442627dc2 +--- /dev/null ++++ b/grub-core/loader/efi/linux.c +@@ -0,0 +1,58 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2014 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 . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-align" ++ ++typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *); ++ ++grub_err_t ++grub_efi_linux_boot (void *kernel_addr, grub_off_t offset, ++ void *kernel_params) ++{ ++ grub_efi_loaded_image_t *loaded_image = NULL; ++ handover_func hf; ++ ++ /* ++ * Since the EFI loader is not calling the LoadImage() and StartImage() ++ * services for loading the kernel and booting respectively, it has to ++ * set the Loaded Image base address. ++ */ ++ loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); ++ if (loaded_image) ++ loaded_image->image_base = kernel_addr; ++ else ++ grub_dprintf ("linux", "Loaded Image base address could not be set\n"); ++ ++ grub_dprintf ("linux", "kernel_addr: %p handover_offset: %p params: %p\n", ++ kernel_addr, (void *)(grub_efi_uintn_t)offset, kernel_params); ++ hf = (handover_func)((char *)kernel_addr + offset); ++ hf (grub_efi_image_handle, grub_efi_system_table, kernel_params); ++ ++ return GRUB_ERR_BUG; ++} ++ ++#pragma GCC diagnostic pop +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 355ecc9b9..06814cae3 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -40,26 +41,18 @@ static char *linux_cmdline; + + #define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) + +-typedef void(*handover_func)(void *, grub_efi_system_table_t *, struct linux_kernel_params *); +- + static grub_err_t + grub_linuxefi_boot (void) + { +- handover_func hf; + int offset = 0; + + #ifdef __x86_64__ + offset = 512; + #endif +- +- hf = (handover_func)((char *)kernel_mem + handover_offset + offset); +- + asm volatile ("cli"); + +- hf (grub_efi_image_handle, grub_efi_system_table, params); +- +- /* Not reached */ +- return GRUB_ERR_NONE; ++ return grub_efi_linux_boot ((char *)kernel_mem, handover_offset + offset, ++ params); + } + + static grub_err_t +diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h +new file mode 100644 +index 000000000..887b02fd9 +--- /dev/null ++++ b/include/grub/efi/linux.h +@@ -0,0 +1,29 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2014 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 . ++ */ ++#ifndef GRUB_EFI_LINUX_HEADER ++#define GRUB_EFI_LINUX_HEADER 1 ++ ++#include ++#include ++#include ++ ++grub_err_t ++EXPORT_FUNC(grub_efi_linux_boot) (void *kernel_address, grub_off_t offset, ++ void *kernel_param); ++ ++#endif /* ! GRUB_EFI_LINUX_HEADER */ +-- +2.31.1 + diff --git a/0001-Filter-out-POSIX-locale-for-translation.patch b/0001-Filter-out-POSIX-locale-for-translation.patch new file mode 100644 index 0000000..92069b0 --- /dev/null +++ b/0001-Filter-out-POSIX-locale-for-translation.patch @@ -0,0 +1,36 @@ +From 87b01d35b4db56778e2d9f99d18656026f818bab Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Tue, 26 Oct 2021 13:31:24 +0800 +Subject: [PATCH] Filter out POSIX locale for translation + +The POSIX locale is default or native operating system's locale +identical to the C locale, so no translation to human speaking languages +provided. + +For this reason we should filter out LANG=POSIX as well as LANG=C upon +generating grub.cfg to avoid looking up for it's gettext's message +catalogs that will consequently result in the unpleasant message. + +error: file `/boot/grub/locale/POSIX.gmo' not found + +Signed-off-by: Michael Chang +--- + util/grub.d/00_header.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in +index 57a35a14a..b21caa4bc 100644 +--- a/util/grub.d/00_header.in ++++ b/util/grub.d/00_header.in +@@ -250,7 +250,7 @@ EOF + EOF + + # Gettext variables and module +-if [ "x${LANG}" != "xC" ] && [ "x${LANG}" != "x" ]; then ++if [ "x${LANG}" != "xC" ] && [ "x${LANG}" != "xPOSIX" ] && [ "x${LANG}" != "x" ]; then + cat << EOF + set locale_dir=\$prefix/locale + set lang=${grub_lang} +-- +2.31.1 + diff --git a/0001-Fix-build-error-in-binutils-2.36.patch b/0001-Fix-build-error-in-binutils-2.36.patch new file mode 100644 index 0000000..72ce7a7 --- /dev/null +++ b/0001-Fix-build-error-in-binutils-2.36.patch @@ -0,0 +1,47 @@ +From 7801d671905329d28e789082225570fc54fe5784 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Fri, 19 Feb 2021 17:40:43 +0800 +Subject: [PATCH] Fix build error in binutils 2.36 + +The build fails in binutils 2.36 + +[ 520s] cat kernel_syms.lst > syminfo.lst.new +[ 520s] /usr/lib64/gcc/x86_64-suse-linux/10/../../../../x86_64-suse-linux/bin/ld: section .note.gnu.property VMA [0000000000400158,0000000000400187] overlaps section .bss VMA [000000000000f000,000000000041e1af] + +It is caused by assembler now generates the GNU property notes section +by default. Use the assmbler option -mx86-used-note=no to disable the +section from being generated to workaround the ensuing linker issue. + +Signed-off-by: Michael Chang +--- + configure.ac | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/configure.ac b/configure.ac +index c39e8379f..a3fb713ad 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -827,6 +827,20 @@ if ( test "x$target_cpu" = xi386 || test "x$target_cpu" = xx86_64 ) && test "x$p + TARGET_CFLAGS="$TARGET_CFLAGS -mno-mmx -mno-sse -mno-sse2 -mno-sse3 -mno-3dnow" + fi + ++if ( test "x$target_cpu" = xi386 || test "x$target_cpu" = xx86_64 ); then ++ AC_CACHE_CHECK([whether -Wa,-mx86-used-note works], [grub_cv_cc_mx86_used_note], [ ++ CFLAGS="$TARGET_CFLAGS -Wa,-mx86-used-note=no -Werror" ++ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], ++ [grub_cv_cc_mx86_used_note=yes], ++ [grub_cv_cc_mx86_used_note=no]) ++ ]) ++ ++ if test "x$grub_cv_cc_mx86_used_note" = xyes; then ++ TARGET_CFLAGS="$TARGET_CFLAGS -Wa,-mx86-used-note=no" ++ TARGET_CCASFLAGS="$TARGET_CCASFLAGS -Wa,-mx86-used-note=no" ++ fi ++fi ++ + # GRUB doesn't use float or doubles at all. Yet some toolchains may decide + # that floats are a good fit to run instead of what's written in the code. + # Given that floating point unit is disabled (if present to begin with) +-- +2.30.0 + diff --git a/0001-Fix-infinite-boot-loop-on-headless-system-in-qemu.patch b/0001-Fix-infinite-boot-loop-on-headless-system-in-qemu.patch new file mode 100644 index 0000000..41f119f --- /dev/null +++ b/0001-Fix-infinite-boot-loop-on-headless-system-in-qemu.patch @@ -0,0 +1,73 @@ +From f76317d9dc35dbc576820ba6c2a6a8e41f5338b5 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Thu, 19 May 2022 13:08:12 +0800 +Subject: [PATCH] Fix infinite boot loop on headless system in qemu + +After finishing headless virtual machine installation via serial +console, the reboot fails in grub with infinte boot loop and also +keyboard input for serial console is unresponsive. + +The cause of infinte loop boils down to legacy vga driver in grub +crashes when '-dispaly none' is used as qemu's display type described in +the manual as: + +"Do not display video output. The guest will still see an emulated +graphics card, but its output will not be displayed tothe QEMU user. +This option differs from the -nographic option in that it only affects +what is done with video output; -nographic also changes the destination +of the serial and parallel port data." + +Given there's no sensible way found to skip the emulated device from the +legacy vga module, we ended up removing it from all_video dependency so +it wouldn't be loaded by default. In any case, the vbe module remain +loaded and should fulfill the requirement of most hardwares even twenty +years old or more. + +The unresponsive serial input is also fixed by ensuring that console +input is loaded via appended so that they won't fail altogether with +errors by other console device if specifying on the same list. + +Signed-off-by: Michael Chang +--- + grub-core/genmoddep.awk | 3 +++ + util/grub.d/00_header.in | 10 +++++++++- + 2 files changed, 12 insertions(+), 1 deletion(-) + +diff --git a/grub-core/genmoddep.awk b/grub-core/genmoddep.awk +index 04c2863e5a..9b64f3ca93 100644 +--- a/grub-core/genmoddep.awk ++++ b/grub-core/genmoddep.awk +@@ -96,6 +96,9 @@ END { + } + modlist = "" + while (getline <"video.lst") { ++ if ($1 == "vga") { ++ continue; ++ } + modlist = modlist " " $1; + } + printf "all_video:%s\n", modlist; +diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in +index b21caa4bcb..23671838e9 100644 +--- a/util/grub.d/00_header.in ++++ b/util/grub.d/00_header.in +@@ -280,7 +280,15 @@ case x${GRUB_TERMINAL_OUTPUT} in + ;; + x*) + cat << EOF +-terminal_output ${GRUB_TERMINAL_OUTPUT} ++ ++for i in ${GRUB_TERMINAL_OUTPUT}; do ++ if [ x\${use_append} = xtrue ]; then ++ terminal_output --append \$i ++ elif terminal_output \$i; then ++ use_append=true; ++ fi ++done ++ + EOF + ;; + esac +-- +2.34.1 + diff --git a/0001-RISC-V-Adjust-march-flags-for-binutils-2.38.patch b/0001-RISC-V-Adjust-march-flags-for-binutils-2.38.patch new file mode 100644 index 0000000..e6a5c21 --- /dev/null +++ b/0001-RISC-V-Adjust-march-flags-for-binutils-2.38.patch @@ -0,0 +1,47 @@ +From 4e7de0959f3e99824d4a688398958ea022a1d023 Mon Sep 17 00:00:00 2001 +From: Heinrich Schuchardt +Date: Sat, 29 Jan 2022 13:36:55 +0100 +Subject: [PATCH] RISC-V: Adjust -march flags for binutils 2.38 + +As of version 2.38 binutils defaults to ISA specification version +2019-12-13. This version of the specification has has separated the +the csr read/write (csrr*/csrw*) instructions and the fence.i from +the I extension and put them into separate Zicsr and Zifencei +extensions. + +This implies that we have to adjust the -march flag passed to the +compiler accordingly. + +Signed-off-by: Heinrich Schuchardt +Reviewed-by: Daniel Kiper +--- + configure.ac | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/configure.ac b/configure.ac +index af8e2615ce..906eb1cedc 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -866,11 +866,19 @@ if test x"$platform" != xemu ; then + CFLAGS="$TARGET_CFLAGS -march=rv32imac -mabi=ilp32 -Werror" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [grub_cv_target_cc_soft_float="-march=rv32imac -mabi=ilp32"], []) ++ # ISA spec version 20191213 factored out extensions Zicsr and Zifencei ++ CFLAGS="$TARGET_CFLAGS -march=rv32imac_zicsr_zifencei -mabi=ilp32 -Werror" ++ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], ++ [grub_cv_target_cc_soft_float="-march=rv32imac_zicsr_zifencei -mabi=ilp32"], []) + fi + if test "x$target_cpu" = xriscv64; then + CFLAGS="$TARGET_CFLAGS -march=rv64imac -mabi=lp64 -Werror" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [grub_cv_target_cc_soft_float="-march=rv64imac -mabi=lp64"], []) ++ # ISA spec version 20191213 factored out extensions Zicsr and Zifencei ++ CFLAGS="$TARGET_CFLAGS -march=rv64imac_zicsr_zifencei -mabi=lp64 -Werror" ++ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], ++ [grub_cv_target_cc_soft_float="-march=rv64imac_zicsr_zifencei -mabi=lp64"], []) + fi + if test "x$target_cpu" = xia64; then + CFLAGS="$TARGET_CFLAGS -mno-inline-float-divide -mno-inline-sqrt -Werror" +-- +2.34.1 + diff --git a/0001-Unify-the-check-to-enable-btrfs-relative-path.patch b/0001-Unify-the-check-to-enable-btrfs-relative-path.patch new file mode 100644 index 0000000..e650ce6 --- /dev/null +++ b/0001-Unify-the-check-to-enable-btrfs-relative-path.patch @@ -0,0 +1,156 @@ +From 80bb1b17b3f596dbd7331cf9cb20a46c8ef9800b Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Sat, 22 Aug 2020 02:32:43 +0800 +Subject: [PATCH] Unify the check to enable btrfs relative path + +This unified the test in grub-install and grub-mkconfig that the path to +default or selected btrfs subvolume/snapshot is used if the root file +system is btrfs and the config has enabled btrfs snapshot booting. + +Signed-off-by: Michael Chang +--- + util/grub-install.c | 67 +++++++++++++++++++++++++++------------ + util/grub-mkconfig_lib.in | 3 +- + 2 files changed, 48 insertions(+), 22 deletions(-) + +diff --git a/util/grub-install.c b/util/grub-install.c +index 746a42a04..8d18f2530 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -870,6 +870,7 @@ main (int argc, char *argv[]) + const char *efi_file = NULL; + char **grub_devices; + grub_fs_t grub_fs; ++ grub_fs_t root_fs; + grub_device_t grub_dev = NULL; + enum grub_install_plat platform; + char *grubdir, *device_map; +@@ -882,6 +883,8 @@ main (int argc, char *argv[]) + int efidir_is_mac = 0; + int is_prep = 0; + const char *pkgdatadir; ++ char *rootdir_path; ++ char **rootdir_devices; + + grub_util_host_init (&argc, &argv); + product_version = xstrdup (PACKAGE_VERSION); +@@ -895,9 +898,6 @@ main (int argc, char *argv[]) + + grub_util_load_config (&config); + +- if (config.is_suse_btrfs_snapshot_enabled) +- use_relative_path_on_btrfs = 1; +- + if (!bootloader_id && config.grub_distributor) + { + char *ptr; +@@ -1046,6 +1046,45 @@ main (int argc, char *argv[]) + grub_hostfs_init (); + grub_host_init (); + ++ { ++ char *rootdir_grub_devname; ++ grub_device_t rootdir_grub_dev; ++ char *t = grub_util_path_concat (2, "/", rootdir); ++ ++ rootdir_path = grub_canonicalize_file_name (t); ++ if (!rootdir_path) ++ grub_util_error (_("failed to get canonical path of `%s'"), t); ++ ++ rootdir_devices = grub_guess_root_devices (rootdir_path); ++ if (!rootdir_devices || !rootdir_devices[0]) ++ grub_util_error (_("cannot find a device for %s (is /dev mounted?)"), ++ rootdir_path); ++ ++ for (curdev = rootdir_devices; *curdev; curdev++) ++ grub_util_pull_device (*curdev); ++ ++ rootdir_grub_devname = grub_util_get_grub_dev (rootdir_devices[0]); ++ if (!rootdir_grub_devname) ++ grub_util_error (_("cannot find a GRUB drive for %s. Check your device.map"), ++ rootdir_devices[0]); ++ ++ rootdir_grub_dev = grub_device_open (rootdir_grub_devname); ++ if (! rootdir_grub_dev) ++ grub_util_error ("%s", grub_errmsg); ++ ++ root_fs = grub_fs_probe (rootdir_grub_dev); ++ if (!root_fs) ++ grub_util_error ("%s", grub_errmsg); ++ ++ if (config.is_suse_btrfs_snapshot_enabled ++ && grub_strncmp(root_fs->name, "btrfs", sizeof ("btrfs") - 1) == 0) ++ use_relative_path_on_btrfs = 1; ++ ++ free (t); ++ free (rootdir_grub_devname); ++ grub_device_close (rootdir_grub_dev); ++ } ++ + switch (platform) + { + case GRUB_INSTALL_PLATFORM_I386_EFI: +@@ -1410,8 +1449,7 @@ main (int argc, char *argv[]) + debug_image); + } + +- if (config.is_suse_btrfs_snapshot_enabled +- && grub_strncmp(grub_fs->name, "btrfs", sizeof ("btrfs") - 1) == 0) ++ if (use_relative_path_on_btrfs) + { + if (!load_cfg_f) + load_cfg_f = grub_util_fopen (load_cfg, "wb"); +@@ -1624,21 +1662,13 @@ main (int argc, char *argv[]) + + #ifdef __linux__ + +- if (config.is_suse_btrfs_snapshot_enabled +- && grub_strncmp(grub_fs->name, "btrfs", sizeof ("btrfs") - 1) == 0) ++ if (use_relative_path_on_btrfs) + { + char *subvol = NULL; + char *mount_path = NULL; +- char **rootdir_devices = NULL; +- char *t = grub_util_path_concat (2, "/", rootdir); +- char *rootdir_path = grub_canonicalize_file_name (t); +- +- if (rootdir_path && grub_util_is_directory (rootdir_path)) +- rootdir_devices = grub_guess_root_devices (rootdir_path); + +- if (rootdir_devices && rootdir_devices[0]) +- if (grub_strcmp (rootdir_devices[0], grub_devices[0]) == 0) +- subvol = grub_util_get_btrfs_subvol (platdir, &mount_path); ++ if (grub_strcmp (rootdir_devices[0], grub_devices[0]) == 0) ++ subvol = grub_util_get_btrfs_subvol (platdir, &mount_path); + + if (subvol && mount_path) + { +@@ -1663,11 +1693,6 @@ main (int argc, char *argv[]) + } + } + +- free (t); +- free (rootdir_path); +- for (curdev = rootdir_devices; *curdev; curdev++) +- free (*curdev); +- free (rootdir_devices); + free (subvol); + free (mount_path); + } +diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in +index 023f54a2d..eab46773b 100644 +--- a/util/grub-mkconfig_lib.in ++++ b/util/grub-mkconfig_lib.in +@@ -49,7 +49,8 @@ grub_warn () + + make_system_path_relative_to_its_root () + { +- if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ] ; then ++ if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ] && ++ [ "x${GRUB_FS}" = "xbtrfs" ] ; then + "${grub_mkrelpath}" -r "$1" + else + "${grub_mkrelpath}" "$1" +-- +2.28.0 + diff --git a/0001-Workaround-volatile-efi-boot-variable.patch b/0001-Workaround-volatile-efi-boot-variable.patch new file mode 100644 index 0000000..d6786cf --- /dev/null +++ b/0001-Workaround-volatile-efi-boot-variable.patch @@ -0,0 +1,305 @@ +From 71575829c303fe8522b46fc96b1f99f1aa4178e7 Mon Sep 17 00:00:00 2001 +From: Michael Chang +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 + +diff --git a/Makefile.util.def b/Makefile.util.def +index 2eaa3ff68..018874ab5 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -652,6 +652,7 @@ program = { + common = grub-core/kern/emu/argp_common.c; + common = grub-core/osdep/init.c; + common = grub-core/osdep/journaled_fs.c; ++ common = grub-core/osdep/efi_removable_fallback.c; + + ldadd = '$(LIBLZMA)'; + ldadd = libgrubmods.a; +diff --git a/grub-core/osdep/basic/efi_removable_fallback.c b/grub-core/osdep/basic/efi_removable_fallback.c +new file mode 100644 +index 000000000..3f782f764 +--- /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 . ++ */ ++ ++#include ++ ++const char * ++grub_install_efi_removable_fallback (const char *efidir, enum grub_install_plat platform) ++{ ++ return NULL; ++} ++ +diff --git a/grub-core/osdep/efi_removable_fallback.c b/grub-core/osdep/efi_removable_fallback.c +new file mode 100644 +index 000000000..615a60831 +--- /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 +diff --git a/grub-core/osdep/linux/efi_removable_fallback.c b/grub-core/osdep/linux/efi_removable_fallback.c +new file mode 100644 +index 000000000..7375fb0c2 +--- /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 . ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++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; ++} ++ +diff --git a/include/grub/util/install.h b/include/grub/util/install.h +index 1541ee233..cedc5f856 100644 +--- a/include/grub/util/install.h ++++ b/include/grub/util/install.h +@@ -274,4 +274,7 @@ grub_install_is_short_mbrgap_supported(void); + + 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 +diff --git a/util/grub-install.c b/util/grub-install.c +index b37f3ca26..e20b3c6b9 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -885,6 +885,7 @@ main (int argc, char *argv[]) + const char *pkgdatadir; + char *rootdir_path; + char **rootdir_devices; ++ char *efidir_root; + + grub_util_host_init (&argc, &argv); + product_version = xstrdup (PACKAGE_VERSION); +@@ -1142,6 +1143,7 @@ main (int argc, char *argv[]) + } + 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?)"), +@@ -2159,6 +2161,23 @@ main (int argc, char *argv[]) + 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; +-- +2.26.2 + diff --git a/0001-add-support-for-UEFI-network-protocols.patch b/0001-add-support-for-UEFI-network-protocols.patch new file mode 100644 index 0000000..47396d1 --- /dev/null +++ b/0001-add-support-for-UEFI-network-protocols.patch @@ -0,0 +1,4937 @@ +From 5d6111790e1cd07d1156f47bca0733f6d715337f Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Wed, 22 Feb 2017 14:27:50 +0800 +Subject: [PATCH] Support UEFI networking protocols + +References: fate#320130, bsc#1015589, bsc#1076132 +Patch-Mainline: no + +V1: + * Add preliminary support of UEFI networking protocols + * Support UEFI HTTPS Boot + +V2: + * Workaround http data access in firmware + * Fix DNS device path parsing for efinet device + * Relaxed UEFI Protocol requirement + * Support Intel OPA (Omni-Path Architecture) PXE Boot + +V3: + * Fix bufio in calculating address of next_buf + * Check HTTP respond code + * Use HEAD request method to test before GET + * Finish HTTP transaction in one go + * Fix bsc#1076132 + +V4: + * Add fs_ prefix with upstream commit + ad4bfeec5 Change fs functions to add fs_ prefix + +V5: + * Use overflow checking primitives where the arithmetic expression for + buffer allocations may include unvalidated data + * Use grub_calloc for overflow check and return NULL when it would + occur. + +V6: + * Don't force grub_print_error if no best route found as boot process + could be interrupted by logged error. The default interface will be + used as fallback in this case + +--- + grub-core/Makefile.core.def | 18 + + grub-core/io/bufio.c | 2 +- + grub-core/kern/efi/efi.c | 96 ++- + grub-core/net/drivers/efi/efinet.c | 27 + + grub-core/net/efi/dhcp.c | 397 ++++++++++ + grub-core/net/efi/efi_netfs.c | 57 ++ + grub-core/net/efi/http.c | 419 +++++++++++ + grub-core/net/efi/ip4_config.c | 398 ++++++++++ + grub-core/net/efi/ip6_config.c | 422 +++++++++++ + grub-core/net/efi/net.c | 1428 ++++++++++++++++++++++++++++++++++++ + grub-core/net/efi/pxe.c | 424 +++++++++++ + grub-core/net/net.c | 74 ++ + include/grub/efi/api.h | 181 ++++- + include/grub/efi/dhcp.h | 343 +++++++++ + include/grub/efi/http.h | 215 ++++++ + include/grub/net/efi.h | 144 ++++ + util/grub-mknetdir.c | 23 +- + 17 files changed, 4627 insertions(+), 41 deletions(-) + create mode 100644 grub-core/net/efi/dhcp.c + create mode 100644 grub-core/net/efi/efi_netfs.c + create mode 100644 grub-core/net/efi/http.c + create mode 100644 grub-core/net/efi/ip4_config.c + create mode 100644 grub-core/net/efi/ip6_config.c + create mode 100644 grub-core/net/efi/net.c + create mode 100644 grub-core/net/efi/pxe.c + create mode 100644 include/grub/efi/dhcp.h + create mode 100644 include/grub/efi/http.h + create mode 100644 include/grub/net/efi.h + +Index: grub-2.06/grub-core/Makefile.core.def +=================================================================== +--- grub-2.06.orig/grub-core/Makefile.core.def ++++ grub-2.06/grub-core/Makefile.core.def +@@ -2306,6 +2306,12 @@ module = { + common = net/ethernet.c; + common = net/arp.c; + common = net/netbuff.c; ++ efi = net/efi/net.c; ++ efi = net/efi/http.c; ++ efi = net/efi/pxe.c; ++ efi = net/efi/ip4_config.c; ++ efi = net/efi/ip6_config.c; ++ efi = net/efi/dhcp.c; + }; + + module = { +Index: grub-2.06/grub-core/io/bufio.c +=================================================================== +--- grub-2.06.orig/grub-core/io/bufio.c ++++ grub-2.06/grub-core/io/bufio.c +@@ -139,7 +139,7 @@ grub_bufio_read (grub_file_t file, char + return res; + + /* Need to read some more. */ +- next_buf = (file->offset + res + len - 1) & ~((grub_off_t) bufio->block_size - 1); ++ next_buf = (grub_divmod64 (file->offset + res + len - 1, bufio->block_size, NULL)) * bufio->block_size; + /* Now read between file->offset + res and bufio->buffer_at. */ + if (file->offset + res < next_buf) + { +Index: grub-2.06/grub-core/kern/efi/efi.c +=================================================================== +--- grub-2.06.orig/grub-core/kern/efi/efi.c ++++ grub-2.06/grub-core/kern/efi/efi.c +@@ -750,7 +750,7 @@ grub_efi_print_device_path (grub_efi_dev + { + grub_efi_ipv4_device_path_t *ipv4 + = (grub_efi_ipv4_device_path_t *) dp; +- grub_printf ("/IPv4(%u.%u.%u.%u,%u.%u.%u.%u,%u,%u,%x,%x)", ++ grub_printf ("/IPv4(%u.%u.%u.%u,%u.%u.%u.%u,%u,%u,%x,%x", + (unsigned) ipv4->local_ip_address[0], + (unsigned) ipv4->local_ip_address[1], + (unsigned) ipv4->local_ip_address[2], +@@ -763,33 +763,60 @@ grub_efi_print_device_path (grub_efi_dev + (unsigned) ipv4->remote_port, + (unsigned) ipv4->protocol, + (unsigned) ipv4->static_ip_address); ++ if (len == sizeof (*ipv4)) ++ { ++ grub_printf (",%u.%u.%u.%u,%u.%u.%u.%u", ++ (unsigned) ipv4->gateway_ip_address[0], ++ (unsigned) ipv4->gateway_ip_address[1], ++ (unsigned) ipv4->gateway_ip_address[2], ++ (unsigned) ipv4->gateway_ip_address[3], ++ (unsigned) ipv4->subnet_mask[0], ++ (unsigned) ipv4->subnet_mask[1], ++ (unsigned) ipv4->subnet_mask[2], ++ (unsigned) ipv4->subnet_mask[3]); ++ } ++ grub_printf (")"); + } + break; + case GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE: + { + grub_efi_ipv6_device_path_t *ipv6 + = (grub_efi_ipv6_device_path_t *) dp; +- grub_printf ("/IPv6(%x:%x:%x:%x:%x:%x:%x:%x,%x:%x:%x:%x:%x:%x:%x:%x,%u,%u,%x,%x)", +- (unsigned) ipv6->local_ip_address[0], +- (unsigned) ipv6->local_ip_address[1], +- (unsigned) ipv6->local_ip_address[2], +- (unsigned) ipv6->local_ip_address[3], +- (unsigned) ipv6->local_ip_address[4], +- (unsigned) ipv6->local_ip_address[5], +- (unsigned) ipv6->local_ip_address[6], +- (unsigned) ipv6->local_ip_address[7], +- (unsigned) ipv6->remote_ip_address[0], +- (unsigned) ipv6->remote_ip_address[1], +- (unsigned) ipv6->remote_ip_address[2], +- (unsigned) ipv6->remote_ip_address[3], +- (unsigned) ipv6->remote_ip_address[4], +- (unsigned) ipv6->remote_ip_address[5], +- (unsigned) ipv6->remote_ip_address[6], +- (unsigned) ipv6->remote_ip_address[7], ++ grub_printf ("/IPv6(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x,%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x,%u,%u,%x,%x", ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[0]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[1]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[2]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[3]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[4]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[5]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[6]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[7]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[0]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[1]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[2]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[3]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[4]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[5]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[6]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[7]), + (unsigned) ipv6->local_port, + (unsigned) ipv6->remote_port, + (unsigned) ipv6->protocol, + (unsigned) ipv6->static_ip_address); ++ if (len == sizeof (*ipv6)) ++ { ++ grub_printf (",%u,%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", ++ (unsigned) ipv6->prefix_length, ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[0]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[1]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[2]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[3]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[4]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[5]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[6]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[7])); ++ } ++ grub_printf (")"); + } + break; + case GRUB_EFI_INFINIBAND_DEVICE_PATH_SUBTYPE: +@@ -829,6 +856,39 @@ grub_efi_print_device_path (grub_efi_dev + dump_vendor_path ("Messaging", + (grub_efi_vendor_device_path_t *) dp); + break; ++ case GRUB_EFI_URI_DEVICE_PATH_SUBTYPE: ++ { ++ grub_efi_uri_device_path_t *uri ++ = (grub_efi_uri_device_path_t *) dp; ++ grub_printf ("/URI(%s)", uri->uri); ++ } ++ break; ++ case GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE: ++ { ++ grub_efi_dns_device_path_t *dns ++ = (grub_efi_dns_device_path_t *) dp; ++ if (dns->is_ipv6) ++ { ++ grub_printf ("/DNS(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x)", ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[0]) >> 16), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[0])), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[1]) >> 16), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[1])), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[2]) >> 16), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[2])), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[3]) >> 16), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[3]))); ++ } ++ else ++ { ++ grub_printf ("/DNS(%d.%d.%d.%d)", ++ dns->dns_server_ip[0].v4.addr[0], ++ dns->dns_server_ip[0].v4.addr[1], ++ dns->dns_server_ip[0].v4.addr[2], ++ dns->dns_server_ip[0].v4.addr[3]); ++ } ++ } ++ break; + default: + grub_printf ("/UnknownMessaging(%x)", (unsigned) subtype); + break; +Index: grub-2.06/grub-core/net/drivers/efi/efinet.c +=================================================================== +--- grub-2.06.orig/grub-core/net/drivers/efi/efinet.c ++++ grub-2.06/grub-core/net/drivers/efi/efinet.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -481,6 +482,17 @@ grub_efinet_create_dhcp_ack_from_device_ + + ldp = grub_efi_find_last_device_path (ddp); + ++ /* Skip the DNS Device */ ++ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE ++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE) ++ { ++ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ ldp->length = sizeof (*ldp); ++ ++ ldp = grub_efi_find_last_device_path (ddp); ++ } ++ + if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE + || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE + && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)) +@@ -744,6 +756,7 @@ grub_efi_net_config_real (grub_efi_handl + if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE + || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE + && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE ++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE + && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)) + continue; + dup_dp = grub_efi_duplicate_device_path (dp); +@@ -759,6 +772,15 @@ grub_efi_net_config_real (grub_efi_handl + } + + dup_ldp = grub_efi_find_last_device_path (dup_dp); ++ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (dup_ldp) == GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE) ++ { ++ dup_ldp = grub_efi_find_last_device_path (dup_dp); ++ dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ dup_ldp->length = sizeof (*dup_ldp); ++ } ++ ++ dup_ldp = grub_efi_find_last_device_path (dup_dp); + dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; + dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; + dup_ldp->length = sizeof (*dup_ldp); +@@ -816,6 +838,9 @@ grub_efi_net_config_real (grub_efi_handl + + GRUB_MOD_INIT(efinet) + { ++ if (grub_efi_net_config) ++ return; ++ + grub_efinet_findcards (); + grub_efi_net_config = grub_efi_net_config_real; + } +@@ -827,5 +852,7 @@ GRUB_MOD_FINI(efinet) + FOR_NET_CARDS_SAFE (card, next) + if (card->driver == &efidriver) + grub_net_card_unregister (card); ++ ++ grub_efi_net_config = NULL; + } + +Index: grub-2.06/grub-core/net/efi/dhcp.c +=================================================================== +--- /dev/null ++++ grub-2.06/grub-core/net/efi/dhcp.c +@@ -0,0 +1,399 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef GRUB_EFI_NET_DEBUG ++static void ++dhcp4_mode_print (grub_efi_dhcp4_mode_data_t *mode) ++{ ++ switch (mode->state) ++ { ++ case GRUB_EFI_DHCP4_STOPPED: ++ grub_printf ("STATE: STOPPED\n"); ++ break; ++ case GRUB_EFI_DHCP4_INIT: ++ grub_printf ("STATE: INIT\n"); ++ break; ++ case GRUB_EFI_DHCP4_SELECTING: ++ grub_printf ("STATE: SELECTING\n"); ++ break; ++ case GRUB_EFI_DHCP4_REQUESTING: ++ grub_printf ("STATE: REQUESTING\n"); ++ break; ++ case GRUB_EFI_DHCP4_BOUND: ++ grub_printf ("STATE: BOUND\n"); ++ break; ++ case GRUB_EFI_DHCP4_RENEWING: ++ grub_printf ("STATE: RENEWING\n"); ++ break; ++ case GRUB_EFI_DHCP4_REBINDING: ++ grub_printf ("STATE: REBINDING\n"); ++ break; ++ case GRUB_EFI_DHCP4_INIT_REBOOT: ++ grub_printf ("STATE: INIT_REBOOT\n"); ++ break; ++ case GRUB_EFI_DHCP4_REBOOTING: ++ grub_printf ("STATE: REBOOTING\n"); ++ break; ++ default: ++ grub_printf ("STATE: UNKNOWN\n"); ++ break; ++ } ++ ++ grub_printf ("CLIENT_ADDRESS: %u.%u.%u.%u\n", ++ mode->client_address[0], ++ mode->client_address[1], ++ mode->client_address[2], ++ mode->client_address[3]); ++ grub_printf ("SERVER_ADDRESS: %u.%u.%u.%u\n", ++ mode->server_address[0], ++ mode->server_address[1], ++ mode->server_address[2], ++ mode->server_address[3]); ++ grub_printf ("SUBNET_MASK: %u.%u.%u.%u\n", ++ mode->subnet_mask[0], ++ mode->subnet_mask[1], ++ mode->subnet_mask[2], ++ mode->subnet_mask[3]); ++ grub_printf ("ROUTER_ADDRESS: %u.%u.%u.%u\n", ++ mode->router_address[0], ++ mode->router_address[1], ++ mode->router_address[2], ++ mode->router_address[3]); ++} ++#endif ++ ++static grub_efi_ipv4_address_t * ++grub_efi_dhcp4_parse_dns (grub_efi_dhcp4_protocol_t *dhcp4, grub_efi_dhcp4_packet_t *reply_packet) ++{ ++ grub_efi_dhcp4_packet_option_t **option_list; ++ grub_efi_status_t status; ++ grub_efi_uint32_t option_count = 0; ++ grub_efi_uint32_t i; ++ ++ status = efi_call_4 (dhcp4->parse, dhcp4, reply_packet, &option_count, NULL); ++ ++ if (status != GRUB_EFI_BUFFER_TOO_SMALL) ++ return NULL; ++ ++ option_list = grub_calloc (option_count, sizeof(*option_list)); ++ if (!option_list) ++ return NULL; ++ ++ status = efi_call_4 (dhcp4->parse, dhcp4, reply_packet, &option_count, option_list); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (option_list); ++ return NULL; ++ } ++ ++ for (i = 0; i < option_count; ++i) ++ { ++ if (option_list[i]->op_code == 6) ++ { ++ grub_efi_ipv4_address_t *dns_address; ++ ++ if (((option_list[i]->length & 0x3) != 0) || (option_list[i]->length == 0)) ++ continue; ++ ++ /* We only contact primary dns */ ++ dns_address = grub_malloc (sizeof (*dns_address)); ++ if (!dns_address) ++ { ++ grub_free (option_list); ++ return NULL; ++ } ++ grub_memcpy (dns_address, option_list[i]->data, sizeof (dns_address)); ++ grub_free (option_list); ++ return dns_address; ++ } ++ } ++ ++ grub_free (option_list); ++ return NULL; ++} ++ ++#if 0 ++/* Somehow this doesn't work ... */ ++static grub_err_t ++grub_cmd_efi_bootp (struct grub_command *cmd __attribute__ ((unused)), ++ int argc __attribute__ ((unused)), ++ char **args __attribute__ ((unused))) ++{ ++ struct grub_efi_net_device *dev; ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ grub_efi_pxe_t *pxe = dev->ip4_pxe; ++ grub_efi_pxe_mode_t *mode = pxe->mode; ++ grub_efi_status_t status; ++ ++ if (!mode->started) ++ { ++ status = efi_call_2 (pxe->start, pxe, 0); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ grub_printf ("Couldn't start PXE\n"); ++ } ++ ++ status = efi_call_2 (pxe->dhcp, pxe, 0); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp4 configure failed, %d\n", (int)status); ++ continue; ++ } ++ ++ dev->prefer_ip6 = 0; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++#endif ++ ++static grub_err_t ++grub_cmd_efi_bootp (struct grub_command *cmd __attribute__ ((unused)), ++ int argc, ++ char **args) ++{ ++ struct grub_efi_net_device *netdev; ++ ++ for (netdev = net_devices; netdev; netdev = netdev->next) ++ { ++ grub_efi_status_t status; ++ grub_efi_dhcp4_mode_data_t mode; ++ grub_efi_dhcp4_config_data_t config; ++ grub_efi_dhcp4_packet_option_t *options; ++ grub_efi_ipv4_address_t *dns_address; ++ grub_efi_net_ip_manual_address_t net_ip; ++ grub_efi_net_ip_address_t ip_addr; ++ grub_efi_net_interface_t *inf = NULL; ++ ++ if (argc > 0 && grub_strcmp (netdev->card_name, args[0]) != 0) ++ continue; ++ ++ grub_memset (&config, 0, sizeof(config)); ++ ++ config.option_count = 1; ++ options = grub_malloc (sizeof(*options) + 2); ++ /* Parameter request list */ ++ options->op_code = 55; ++ options->length = 3; ++ /* subnet mask */ ++ options->data[0] = 1; ++ /* router */ ++ options->data[1] = 3; ++ /* DNS */ ++ options->data[2] = 6; ++ config.option_list = &options; ++ ++ /* FIXME: What if the dhcp has bounded */ ++ status = efi_call_2 (netdev->dhcp4->configure, netdev->dhcp4, &config); ++ grub_free (options); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp4 configure failed, %d\n", (int)status); ++ continue; ++ } ++ ++ status = efi_call_2 (netdev->dhcp4->start, netdev->dhcp4, NULL); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp4 start failed, %d\n", (int)status); ++ continue; ++ } ++ ++ status = efi_call_2 (netdev->dhcp4->get_mode_data, netdev->dhcp4, &mode); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp4 get mode failed, %d\n", (int)status); ++ continue; ++ } ++ ++#ifdef GRUB_EFI_NET_DEBUG ++ dhcp4_mode_print (&mode); ++#endif ++ ++ for (inf = netdev->net_interfaces; inf; inf = inf->next) ++ if (inf->prefer_ip6 == 0) ++ break; ++ ++ grub_memcpy (net_ip.ip4.address, mode.client_address, sizeof (net_ip.ip4.address)); ++ grub_memcpy (net_ip.ip4.subnet_mask, mode.subnet_mask, sizeof (net_ip.ip4.subnet_mask)); ++ ++ if (!inf) ++ { ++ char *name = grub_xasprintf ("%s:dhcp", netdev->card_name); ++ ++ net_ip.is_ip6 = 0; ++ inf = grub_efi_net_create_interface (netdev, ++ name, ++ &net_ip, ++ 1); ++ grub_free (name); ++ } ++ else ++ { ++ efi_net_interface_set_address (inf, &net_ip, 1); ++ } ++ ++ grub_memcpy (ip_addr.ip4, mode.router_address, sizeof (ip_addr.ip4)); ++ efi_net_interface_set_gateway (inf, &ip_addr); ++ ++ dns_address = grub_efi_dhcp4_parse_dns (netdev->dhcp4, mode.reply_packet); ++ if (dns_address) ++ efi_net_interface_set_dns (inf, (grub_efi_net_ip_address_t *)&dns_address); ++ ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++ ++static grub_err_t ++grub_cmd_efi_bootp6 (struct grub_command *cmd __attribute__ ((unused)), ++ int argc, ++ char **args) ++{ ++ struct grub_efi_net_device *dev; ++ grub_efi_uint32_t ia_id; ++ ++ for (dev = net_devices, ia_id = 0; dev; dev = dev->next, ia_id++) ++ { ++ grub_efi_dhcp6_config_data_t config; ++ grub_efi_dhcp6_packet_option_t *option_list[1]; ++ grub_efi_dhcp6_packet_option_t *opt; ++ grub_efi_status_t status; ++ grub_efi_dhcp6_mode_data_t mode; ++ grub_efi_dhcp6_retransmission_t retrans; ++ grub_efi_net_ip_manual_address_t net_ip; ++ grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; ++ grub_efi_net_interface_t *inf = NULL; ++ ++ if (argc > 0 && grub_strcmp (dev->card_name, args[0]) != 0) ++ continue; ++ ++ opt = grub_malloc (sizeof(*opt) + 2 * sizeof (grub_efi_uint16_t)); ++ ++#define GRUB_EFI_DHCP6_OPT_ORO 6 ++ ++ opt->op_code = grub_cpu_to_be16_compile_time (GRUB_EFI_DHCP6_OPT_ORO); ++ opt->op_len = grub_cpu_to_be16_compile_time (2 * sizeof (grub_efi_uint16_t)); ++ ++#define GRUB_EFI_DHCP6_OPT_BOOT_FILE_URL 59 ++#define GRUB_EFI_DHCP6_OPT_DNS_SERVERS 23 ++ ++ grub_set_unaligned16 (opt->data, grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_BOOT_FILE_URL)); ++ grub_set_unaligned16 (opt->data + 1 * sizeof (grub_efi_uint16_t), ++ grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_DNS_SERVERS)); ++ ++ option_list[0] = opt; ++ retrans.irt = 4; ++ retrans.mrc = 4; ++ retrans.mrt = 32; ++ retrans.mrd = 60; ++ ++ config.dhcp6_callback = NULL; ++ config.callback_context = NULL; ++ config.option_count = 1; ++ config.option_list = option_list; ++ config.ia_descriptor.ia_id = ia_id; ++ config.ia_descriptor.type = GRUB_EFI_DHCP6_IA_TYPE_NA; ++ config.ia_info_event = NULL; ++ config.reconfigure_accept = 0; ++ config.rapid_commit = 0; ++ config.solicit_retransmission = &retrans; ++ ++ status = efi_call_2 (dev->dhcp6->configure, dev->dhcp6, &config); ++ grub_free (opt); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp6 configure failed, %d\n", (int)status); ++ continue; ++ } ++ status = efi_call_1 (dev->dhcp6->start, dev->dhcp6); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp6 start failed, %d\n", (int)status); ++ continue; ++ } ++ ++ status = efi_call_3 (dev->dhcp6->get_mode_data, dev->dhcp6, &mode, NULL); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp4 get mode failed, %d\n", (int)status); ++ continue; ++ } ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ if (inf->prefer_ip6 == 1) ++ break; ++ ++ grub_memcpy (net_ip.ip6.address, mode.ia->ia_address[0].ip_address, sizeof (net_ip.ip6.address)); ++ net_ip.ip6.prefix_length = 64; ++ net_ip.ip6.is_anycast = 0; ++ net_ip.is_ip6 = 1; ++ ++ if (!inf) ++ { ++ char *name = grub_xasprintf ("%s:dhcp", dev->card_name); ++ ++ inf = grub_efi_net_create_interface (dev, ++ name, ++ &net_ip, ++ 1); ++ grub_free (name); ++ } ++ else ++ { ++ efi_net_interface_set_address (inf, &net_ip, 1); ++ } ++ ++ { ++ grub_efi_uint32_t count = 0; ++ grub_efi_dhcp6_packet_option_t **options = NULL; ++ grub_efi_uint32_t i; ++ ++ status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, NULL); ++ ++ if (status == GRUB_EFI_BUFFER_TOO_SMALL && count) ++ { ++ options = grub_calloc (count, sizeof(*options)); ++ if (!options) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); ++ status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, options); ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ if (options) ++ grub_free (options); ++ continue; ++ } ++ ++ for (i = 0; i < count; ++i) ++ { ++ if (options[i]->op_code == grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_DNS_SERVERS)) ++ { ++ grub_efi_net_ip_address_t dns; ++ grub_memcpy (dns.ip6, options[i]->data, sizeof(net_ip.ip6)); ++ efi_net_interface_set_dns (inf, &dns); ++ break; ++ } ++ } ++ ++ if (options) ++ grub_free (options); ++ } ++ ++ efi_call_1 (b->free_pool, mode.client_id); ++ efi_call_1 (b->free_pool, mode.ia); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_command_func_t grub_efi_net_bootp = grub_cmd_efi_bootp; ++grub_command_func_t grub_efi_net_bootp6 = grub_cmd_efi_bootp6; +Index: grub-2.06/grub-core/net/efi/http.c +=================================================================== +--- /dev/null ++++ grub-2.06/grub-core/net/efi/http.c +@@ -0,0 +1,424 @@ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void ++http_configure (struct grub_efi_net_device *dev, int prefer_ip6) ++{ ++ grub_efi_http_config_data_t http_config; ++ grub_efi_httpv4_access_point_t httpv4_node; ++ grub_efi_httpv6_access_point_t httpv6_node; ++ grub_efi_status_t status; ++ ++ grub_efi_http_t *http = dev->http; ++ ++ grub_memset (&http_config, 0, sizeof(http_config)); ++ http_config.http_version = GRUB_EFI_HTTPVERSION11; ++ http_config.timeout_millisec = 5000; ++ ++ if (prefer_ip6) ++ { ++ grub_efi_uintn_t sz; ++ grub_efi_ip6_config_manual_address_t manual_address; ++ ++ http_config.local_address_is_ipv6 = 1; ++ sz = sizeof (manual_address); ++ status = efi_call_4 (dev->ip6_config->get_data, dev->ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, ++ &sz, &manual_address); ++ ++ if (status == GRUB_EFI_NOT_FOUND) ++ { ++ grub_printf ("The MANUAL ADDRESS is not found\n"); ++ } ++ ++ /* FIXME: The manual interface would return BUFFER TOO SMALL !!! */ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("??? %d\n",(int) status); ++ return; ++ } ++ ++ grub_memcpy (httpv6_node.local_address, manual_address.address, sizeof (httpv6_node.local_address)); ++ httpv6_node.local_port = 0; ++ http_config.access_point.ipv6_node = &httpv6_node; ++ } ++ else ++ { ++ http_config.local_address_is_ipv6 = 0; ++ grub_memset (&httpv4_node, 0, sizeof(httpv4_node)); ++ httpv4_node.use_default_address = 1; ++ ++ /* Use random port here */ ++ /* See TcpBind() in edk2/NetworkPkg/TcpDxe/TcpDispatcher.c */ ++ httpv4_node.local_port = 0; ++ http_config.access_point.ipv4_node = &httpv4_node; ++ } ++ ++ status = efi_call_2 (http->configure, http, &http_config); ++ ++ if (status == GRUB_EFI_ALREADY_STARTED) ++ { ++ /* XXX: This hangs HTTPS boot */ ++#if 0 ++ if (efi_call_2 (http->configure, http, NULL) != GRUB_EFI_SUCCESS) ++ { ++ grub_error (GRUB_ERR_IO, N_("couldn't reset http instance")); ++ grub_print_error (); ++ return; ++ } ++ status = efi_call_2 (http->configure, http, &http_config); ++#endif ++ return; ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_error (GRUB_ERR_IO, N_("couldn't configure http protocol, reason: %d"), (int)status); ++ grub_print_error (); ++ return ; ++ } ++} ++ ++static grub_efi_boolean_t request_callback_done; ++static grub_efi_boolean_t response_callback_done; ++ ++static void ++grub_efi_http_request_callback (grub_efi_event_t event __attribute__ ((unused)), ++ void *context __attribute__ ((unused))) ++{ ++ request_callback_done = 1; ++} ++ ++static void ++grub_efi_http_response_callback (grub_efi_event_t event __attribute__ ((unused)), ++ void *context __attribute__ ((unused))) ++{ ++ response_callback_done = 1; ++} ++ ++static grub_err_t ++efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https, int headeronly, grub_off_t *file_size) ++{ ++ grub_efi_http_request_data_t request_data; ++ grub_efi_http_message_t request_message; ++ grub_efi_http_token_t request_token; ++ grub_efi_http_response_data_t response_data; ++ grub_efi_http_message_t response_message; ++ grub_efi_http_token_t response_token; ++ grub_efi_http_header_t request_headers[3]; ++ ++ grub_efi_status_t status; ++ grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; ++ char *url = NULL; ++ ++ request_headers[0].field_name = (grub_efi_char8_t *)"Host"; ++ request_headers[0].field_value = (grub_efi_char8_t *)server; ++ request_headers[1].field_name = (grub_efi_char8_t *)"Accept"; ++ request_headers[1].field_value = (grub_efi_char8_t *)"*/*"; ++ request_headers[2].field_name = (grub_efi_char8_t *)"User-Agent"; ++ request_headers[2].field_value = (grub_efi_char8_t *)"UefiHttpBoot/1.0"; ++ ++ { ++ grub_efi_ipv6_address_t address; ++ const char *rest; ++ grub_efi_char16_t *ucs2_url; ++ grub_size_t url_len, ucs2_url_len; ++ const char *protocol = (use_https == 1) ? "https" : "http"; ++ grub_size_t sz; ++ ++ if (grub_efi_string_to_ip6_address (server, &address, &rest) && *rest == 0) ++ url = grub_xasprintf ("%s://[%s]%s", protocol, server, name); ++ else ++ url = grub_xasprintf ("%s://%s%s", protocol, server, name); ++ ++ if (!url) ++ { ++ return grub_errno; ++ } ++ ++ url_len = grub_strlen (url); ++ if (grub_mul (url_len, GRUB_MAX_UTF16_PER_UTF8, &ucs2_url_len) || ++ grub_add (ucs2_url_len, 1, &sz)) ++ return GRUB_ERR_OUT_OF_RANGE; ++ ++ ucs2_url = grub_calloc (sz, sizeof (ucs2_url[0])); ++ ++ if (!ucs2_url) ++ { ++ grub_free (url); ++ return grub_errno; ++ } ++ ++ ucs2_url_len = grub_utf8_to_utf16 (ucs2_url, ucs2_url_len, (grub_uint8_t *)url, url_len, NULL); /* convert string format from ascii to usc2 */ ++ ucs2_url[ucs2_url_len] = 0; ++ grub_free (url); ++ request_data.url = ucs2_url; ++ } ++ ++ request_data.method = (headeronly > 0) ? GRUB_EFI_HTTPMETHODHEAD : GRUB_EFI_HTTPMETHODGET; ++ ++ request_message.data.request = &request_data; ++ request_message.header_count = 3; ++ request_message.headers = request_headers; ++ request_message.body_length = 0; ++ request_message.body = NULL; ++ ++ /* request token */ ++ request_token.event = NULL; ++ request_token.status = GRUB_EFI_NOT_READY; ++ request_token.message = &request_message; ++ ++ request_callback_done = 0; ++ status = efi_call_5 (b->create_event, ++ GRUB_EFI_EVT_NOTIFY_SIGNAL, ++ GRUB_EFI_TPL_CALLBACK, ++ grub_efi_http_request_callback, ++ NULL, ++ &request_token.event); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (request_data.url); ++ return grub_error (GRUB_ERR_IO, "Fail to create an event! status=0x%" PRIxGRUB_SIZE, status); ++ } ++ ++ status = efi_call_2 (http->request, http, &request_token); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ efi_call_1 (b->close_event, request_token.event); ++ grub_free (request_data.url); ++ return grub_error (GRUB_ERR_IO, "Fail to send a request! status=0x%" PRIxGRUB_SIZE, status); ++ } ++ /* TODO: Add Timeout */ ++ while (!request_callback_done) ++ efi_call_1(http->poll, http); ++ ++ response_data.status_code = GRUB_EFI_HTTP_STATUS_UNSUPPORTED_STATUS; ++ response_message.data.response = &response_data; ++ /* herader_count will be updated by the HTTP driver on response */ ++ response_message.header_count = 0; ++ /* headers will be populated by the driver on response */ ++ response_message.headers = NULL; ++ /* use zero BodyLength to only receive the response headers */ ++ response_message.body_length = 0; ++ response_message.body = NULL; ++ response_token.event = NULL; ++ ++ status = efi_call_5 (b->create_event, ++ GRUB_EFI_EVT_NOTIFY_SIGNAL, ++ GRUB_EFI_TPL_CALLBACK, ++ grub_efi_http_response_callback, ++ NULL, ++ &response_token.event); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ efi_call_1 (b->close_event, request_token.event); ++ grub_free (request_data.url); ++ return grub_error (GRUB_ERR_IO, "Fail to create an event! status=0x%" PRIxGRUB_SIZE, status); ++ } ++ ++ response_token.status = GRUB_EFI_SUCCESS; ++ response_token.message = &response_message; ++ ++ /* wait for HTTP response */ ++ response_callback_done = 0; ++ status = efi_call_2 (http->response, http, &response_token); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ efi_call_1 (b->close_event, response_token.event); ++ efi_call_1 (b->close_event, request_token.event); ++ grub_free (request_data.url); ++ return grub_error (GRUB_ERR_IO, "Fail to receive a response! status=%d\n", (int)status); ++ } ++ ++ /* TODO: Add Timeout */ ++ while (!response_callback_done) ++ efi_call_1 (http->poll, http); ++ ++ if (response_message.data.response->status_code != GRUB_EFI_HTTP_STATUS_200_OK) ++ { ++ grub_efi_http_status_code_t status_code = response_message.data.response->status_code; ++ ++ if (response_message.headers) ++ efi_call_1 (b->free_pool, response_message.headers); ++ efi_call_1 (b->close_event, response_token.event); ++ efi_call_1 (b->close_event, request_token.event); ++ grub_free (request_data.url); ++ if (status_code == GRUB_EFI_HTTP_STATUS_404_NOT_FOUND) ++ { ++ return grub_error (GRUB_ERR_FILE_NOT_FOUND, _("file `%s' not found"), name); ++ } ++ else ++ { ++ return grub_error (GRUB_ERR_NET_UNKNOWN_ERROR, ++ _("unsupported uefi http status code 0x%x"), status_code); ++ } ++ } ++ ++ if (file_size) ++ { ++ int i; ++ /* parse the length of the file from the ContentLength header */ ++ for (*file_size = 0, i = 0; i < (int)response_message.header_count; ++i) ++ { ++ if (!grub_strcmp((const char*)response_message.headers[i].field_name, "Content-Length")) ++ { ++ *file_size = grub_strtoul((const char*)response_message.headers[i].field_value, 0, 10); ++ break; ++ } ++ } ++ } ++ ++ if (response_message.headers) ++ efi_call_1 (b->free_pool, response_message.headers); ++ efi_call_1 (b->close_event, response_token.event); ++ efi_call_1 (b->close_event, request_token.event); ++ grub_free (request_data.url); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_ssize_t ++efihttp_read (struct grub_efi_net_device *dev, ++ char *buf, ++ grub_size_t len) ++{ ++ grub_efi_http_message_t response_message; ++ grub_efi_http_token_t response_token; ++ ++ grub_efi_status_t status; ++ grub_size_t sum = 0; ++ grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; ++ grub_efi_http_t *http = dev->http; ++ ++ if (!len) ++ { ++ grub_error (GRUB_ERR_BUG, "Invalid arguments to EFI HTTP Read"); ++ return -1; ++ } ++ ++ efi_call_5 (b->create_event, ++ GRUB_EFI_EVT_NOTIFY_SIGNAL, ++ GRUB_EFI_TPL_CALLBACK, ++ grub_efi_http_response_callback, ++ NULL, ++ &response_token.event); ++ ++ while (len) ++ { ++ response_message.data.response = NULL; ++ response_message.header_count = 0; ++ response_message.headers = NULL; ++ response_message.body_length = len; ++ response_message.body = buf; ++ ++ response_token.message = &response_message; ++ response_token.status = GRUB_EFI_NOT_READY; ++ ++ response_callback_done = 0; ++ ++ status = efi_call_2 (http->response, http, &response_token); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ efi_call_1 (b->close_event, response_token.event); ++ grub_error (GRUB_ERR_IO, "Error! status=%d\n", (int)status); ++ return -1; ++ } ++ ++ while (!response_callback_done) ++ efi_call_1(http->poll, http); ++ ++ sum += response_message.body_length; ++ buf += response_message.body_length; ++ len -= response_message.body_length; ++ } ++ ++ efi_call_1 (b->close_event, response_token.event); ++ ++ return sum; ++} ++ ++static grub_err_t ++grub_efihttp_open (struct grub_efi_net_device *dev, ++ int prefer_ip6 __attribute__ ((unused)), ++ grub_file_t file, ++ const char *filename __attribute__ ((unused)), ++ int type) ++{ ++ grub_err_t err; ++ grub_off_t size; ++ char *buf; ++ ++ err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 1, 0); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ ++ err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 0, &size); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ ++ buf = grub_malloc (size); ++ efihttp_read (dev, buf, size); ++ ++ file->size = size; ++ file->data = buf; ++ file->not_easily_seekable = 0; ++ file->device->net->offset = 0; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_efihttp_close (struct grub_efi_net_device *dev __attribute__ ((unused)), ++ int prefer_ip6 __attribute__ ((unused)), ++ grub_file_t file) ++{ ++ if (file->data) ++ grub_free (file->data); ++ ++ file->data = 0; ++ file->offset = 0; ++ file->size = 0; ++ file->device->net->offset = 0; ++ return GRUB_ERR_NONE; ++} ++ ++static grub_ssize_t ++grub_efihttp_read (struct grub_efi_net_device *dev __attribute__((unused)), ++ int prefer_ip6 __attribute__((unused)), ++ grub_file_t file, ++ char *buf, ++ grub_size_t len) ++{ ++ grub_size_t r = len; ++ ++ if (!file->data || !buf || !len) ++ return 0; ++ ++ if ((file->device->net->offset + len) > file->size) ++ r = file->size - file->device->net->offset; ++ ++ if (r) ++ { ++ grub_memcpy (buf, (char *)file->data + file->device->net->offset, r); ++ file->device->net->offset += r; ++ } ++ ++ return r; ++} ++ ++struct grub_efi_net_io io_http = ++ { ++ .configure = http_configure, ++ .open = grub_efihttp_open, ++ .read = grub_efihttp_read, ++ .close = grub_efihttp_close ++ }; +Index: grub-2.06/grub-core/net/efi/ip4_config.c +=================================================================== +--- /dev/null ++++ grub-2.06/grub-core/net/efi/ip4_config.c +@@ -0,0 +1,409 @@ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++char * ++grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address) ++{ ++ char *hw_addr, *p; ++ int s; ++ int i; ++ grub_size_t sz; ++ ++ if (grub_mul (hw_address_size, sizeof ("XX:") - 1, &sz) || ++ grub_add (sz, 1, &sz)) ++ return NULL; ++ ++ hw_addr = grub_malloc (sz); ++ if (!hw_addr) ++ return NULL; ++ ++ p = hw_addr; ++ s = sz; ++ for (i = 0; i < (int)hw_address_size; i++) ++ { ++ grub_snprintf (p, sz, "%02x:", hw_address[i]); ++ p += sizeof ("XX:") - 1; ++ s -= sizeof ("XX:") - 1; ++ } ++ ++ hw_addr[sz - 2] = '\0'; ++ return hw_addr; ++} ++ ++char * ++grub_efi_ip4_address_to_string (grub_efi_ipv4_address_t *address) ++{ ++ char *addr; ++ ++ addr = grub_malloc (sizeof ("XXX.XXX.XXX.XXX")); ++ if (!addr) ++ return NULL; ++ ++ /* FIXME: Use grub_xasprintf ? */ ++ grub_snprintf (addr, ++ sizeof ("XXX.XXX.XXX.XXX"), ++ "%u.%u.%u.%u", ++ (*address)[0], ++ (*address)[1], ++ (*address)[2], ++ (*address)[3]); ++ ++ return addr; ++} ++ ++int ++grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest) ++{ ++ grub_uint32_t newip = 0; ++ int i; ++ const char *ptr = val; ++ ++ for (i = 0; i < 4; i++) ++ { ++ unsigned long t; ++ t = grub_strtoul (ptr, &ptr, 0); ++ if (grub_errno) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ return 0; ++ } ++ if (*ptr != '.' && i == 0) ++ { ++ /* XXX: t is in host byte order */ ++ newip = t; ++ break; ++ } ++ if (t & ~0xff) ++ return 0; ++ newip <<= 8; ++ newip |= t; ++ if (i != 3 && *ptr != '.') ++ return 0; ++ ptr++; ++ } ++ ++ newip = grub_cpu_to_be32 (newip); ++ ++ grub_memcpy (address, &newip, sizeof(*address)); ++ ++ if (rest) ++ *rest = (ptr - 1); ++ return 1; ++} ++ ++static grub_efi_ip4_config2_interface_info_t * ++efi_ip4_config_interface_info (grub_efi_ip4_config2_protocol_t *ip4_config) ++{ ++ grub_efi_uintn_t sz; ++ grub_efi_status_t status; ++ grub_efi_ip4_config2_interface_info_t *interface_info; ++ ++ sz = sizeof (*interface_info) + sizeof (*interface_info->route_table); ++ interface_info = grub_malloc (sz); ++ if (!interface_info) ++ return NULL; ++ ++ status = efi_call_4 (ip4_config->get_data, ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO, ++ &sz, interface_info); ++ ++ if (status == GRUB_EFI_BUFFER_TOO_SMALL) ++ { ++ grub_free (interface_info); ++ interface_info = grub_malloc (sz); ++ status = efi_call_4 (ip4_config->get_data, ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO, ++ &sz, interface_info); ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (interface_info); ++ return NULL; ++ } ++ ++ return interface_info; ++} ++ ++static grub_efi_ip4_config2_manual_address_t * ++efi_ip4_config_manual_address (grub_efi_ip4_config2_protocol_t *ip4_config) ++{ ++ grub_efi_uintn_t sz; ++ grub_efi_status_t status; ++ grub_efi_ip4_config2_manual_address_t *manual_address; ++ ++ sz = sizeof (*manual_address); ++ manual_address = grub_malloc (sz); ++ if (!manual_address) ++ return NULL; ++ ++ status = efi_call_4 (ip4_config->get_data, ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, ++ &sz, manual_address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (manual_address); ++ return NULL; ++ } ++ ++ return manual_address; ++} ++ ++char * ++grub_efi_ip4_interface_name (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip4_config2_interface_info_t *interface_info; ++ char *name; ++ ++ interface_info = efi_ip4_config_interface_info (dev->ip4_config); ++ ++ if (!interface_info) ++ return NULL; ++ ++ name = grub_malloc (GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE ++ * GRUB_MAX_UTF8_PER_UTF16 + 1); ++ *grub_utf16_to_utf8 ((grub_uint8_t *)name, interface_info->name, ++ GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE) = 0; ++ grub_free (interface_info); ++ return name; ++} ++ ++static char * ++grub_efi_ip4_interface_hw_address (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip4_config2_interface_info_t *interface_info; ++ char *hw_addr; ++ ++ interface_info = efi_ip4_config_interface_info (dev->ip4_config); ++ ++ if (!interface_info) ++ return NULL; ++ ++ hw_addr = grub_efi_hw_address_to_string (interface_info->hw_address_size, interface_info->hw_address); ++ grub_free (interface_info); ++ ++ return hw_addr; ++} ++ ++static char * ++grub_efi_ip4_interface_address (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip4_config2_manual_address_t *manual_address; ++ char *addr; ++ ++ manual_address = efi_ip4_config_manual_address (dev->ip4_config); ++ ++ if (!manual_address) ++ return NULL; ++ ++ addr = grub_efi_ip4_address_to_string (&manual_address->address); ++ grub_free (manual_address); ++ return addr; ++} ++ ++ ++static int ++address_mask_size (grub_efi_ipv4_address_t *address) ++{ ++ grub_uint8_t i; ++ grub_uint32_t u32_addr = grub_be_to_cpu32 (grub_get_unaligned32 (address)); ++ ++ if (u32_addr == 0) ++ return 0; ++ ++ for (i = 0; i < 32 ; ++i) ++ { ++ if (u32_addr == ((0xffffffff >> i) << i)) ++ return (32 - i); ++ } ++ ++ return -1; ++} ++ ++static char ** ++grub_efi_ip4_interface_route_table (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip4_config2_interface_info_t *interface_info; ++ char **ret; ++ int i, id; ++ grub_size_t sz; ++ ++ interface_info = efi_ip4_config_interface_info (dev->ip4_config); ++ if (!interface_info) ++ return NULL; ++ ++ if (grub_add (interface_info->route_table_size, 1, &sz)) ++ { ++ grub_free (interface_info); ++ return NULL; ++ } ++ ++ ret = grub_calloc (sz, sizeof (*ret)); ++ ++ if (!ret) ++ { ++ grub_free (interface_info); ++ return NULL; ++ } ++ ++ id = 0; ++ for (i = 0; i < (int)interface_info->route_table_size; i++) ++ { ++ char *subnet, *gateway, *mask; ++ grub_uint32_t u32_subnet, u32_gateway; ++ int mask_size; ++ grub_efi_ip4_route_table_t *route_table = interface_info->route_table + i; ++ grub_efi_net_interface_t *inf; ++ char *interface_name = NULL; ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ if (!inf->prefer_ip6) ++ interface_name = inf->name; ++ ++ u32_gateway = grub_get_unaligned32 (&route_table->gateway_address); ++ gateway = grub_efi_ip4_address_to_string (&route_table->gateway_address); ++ u32_subnet = grub_get_unaligned32 (&route_table->subnet_address); ++ subnet = grub_efi_ip4_address_to_string (&route_table->subnet_address); ++ mask_size = address_mask_size (&route_table->subnet_mask); ++ mask = grub_efi_ip4_address_to_string (&route_table->subnet_mask); ++ if (u32_subnet && !u32_gateway && interface_name) ++ ret[id++] = grub_xasprintf ("%s:local %s/%d %s", dev->card_name, subnet, mask_size, interface_name); ++ else if (u32_subnet && u32_gateway) ++ ret[id++] = grub_xasprintf ("%s:gw %s/%d gw %s", dev->card_name, subnet, mask_size, gateway); ++ else if (!u32_subnet && u32_gateway) ++ ret[id++] = grub_xasprintf ("%s:default %s/%d gw %s", dev->card_name, subnet, mask_size, gateway); ++ grub_free (subnet); ++ grub_free (gateway); ++ grub_free (mask); ++ } ++ ++ ret[id] = NULL; ++ grub_free (interface_info); ++ return ret; ++} ++ ++static grub_efi_net_interface_t * ++grub_efi_ip4_interface_match (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *ip_address) ++{ ++ grub_efi_ip4_config2_interface_info_t *interface_info; ++ grub_efi_net_interface_t *inf; ++ int i; ++ grub_efi_ipv4_address_t *address = &ip_address->ip4; ++ ++ interface_info = efi_ip4_config_interface_info (dev->ip4_config); ++ if (!interface_info) ++ return NULL; ++ ++ for (i = 0; i < (int)interface_info->route_table_size; i++) ++ { ++ grub_efi_ip4_route_table_t *route_table = interface_info->route_table + i; ++ grub_uint32_t u32_address, u32_mask, u32_subnet; ++ ++ u32_address = grub_get_unaligned32 (address); ++ u32_subnet = grub_get_unaligned32 (route_table->subnet_address); ++ u32_mask = grub_get_unaligned32 (route_table->subnet_mask); ++ ++ /* SKIP Default GATEWAY */ ++ if (!u32_subnet && !u32_mask) ++ continue; ++ ++ if ((u32_address & u32_mask) == u32_subnet) ++ { ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ if (!inf->prefer_ip6) ++ { ++ grub_free (interface_info); ++ return inf; ++ } ++ } ++ } ++ ++ grub_free (interface_info); ++ return NULL; ++} ++ ++static int ++grub_efi_ip4_interface_set_manual_address (struct grub_efi_net_device *dev, ++ grub_efi_net_ip_manual_address_t *net_ip, ++ int with_subnet) ++{ ++ grub_efi_status_t status; ++ grub_efi_ip4_config2_manual_address_t *address = &net_ip->ip4; ++ ++ if (!with_subnet) ++ { ++ grub_efi_ip4_config2_manual_address_t *manual_address = ++ efi_ip4_config_manual_address (dev->ip4_config); ++ ++ if (manual_address) ++ { ++ grub_memcpy (address->subnet_mask, manual_address->subnet_mask, sizeof(address->subnet_mask)); ++ grub_free (manual_address); ++ } ++ else ++ { ++ /* XXX: */ ++ address->subnet_mask[0] = 0xff; ++ address->subnet_mask[1] = 0xff; ++ address->subnet_mask[2] = 0xff; ++ address->subnet_mask[3] = 0; ++ } ++ } ++ ++ status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, ++ sizeof(*address), address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ ++ return 1; ++} ++ ++static int ++grub_efi_ip4_interface_set_gateway (struct grub_efi_net_device *dev, ++ grub_efi_net_ip_address_t *address) ++{ ++ grub_efi_status_t status; ++ ++ status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_GATEWAY, ++ sizeof (address->ip4), &address->ip4); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ return 1; ++} ++ ++/* FIXME: Multiple DNS */ ++static int ++grub_efi_ip4_interface_set_dns (struct grub_efi_net_device *dev, ++ grub_efi_net_ip_address_t *address) ++{ ++ grub_efi_status_t status; ++ ++ status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER, ++ sizeof (address->ip4), &address->ip4); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ return 1; ++} ++ ++grub_efi_net_ip_config_t *efi_net_ip4_config = &(grub_efi_net_ip_config_t) ++ { ++ .get_hw_address = grub_efi_ip4_interface_hw_address, ++ .get_address = grub_efi_ip4_interface_address, ++ .get_route_table = grub_efi_ip4_interface_route_table, ++ .best_interface = grub_efi_ip4_interface_match, ++ .set_address = grub_efi_ip4_interface_set_manual_address, ++ .set_gateway = grub_efi_ip4_interface_set_gateway, ++ .set_dns = grub_efi_ip4_interface_set_dns ++ }; +Index: grub-2.06/grub-core/net/efi/ip6_config.c +=================================================================== +--- /dev/null ++++ grub-2.06/grub-core/net/efi/ip6_config.c +@@ -0,0 +1,430 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++char * ++grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address) ++{ ++ char *str = grub_malloc (sizeof ("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX")); ++ char *p; ++ int i; ++ int squash; ++ ++ if (!str) ++ return NULL; ++ ++ p = str; ++ squash = 0; ++ for (i = 0; i < 8; ++i) ++ { ++ grub_uint16_t addr; ++ ++ if (i == 7) ++ squash = 2; ++ ++ addr = grub_get_unaligned16 (address->addr + i * 2); ++ ++ if (grub_be_to_cpu16 (addr)) ++ { ++ char buf[sizeof ("XXXX")]; ++ if (i > 0) ++ *p++ = ':'; ++ grub_snprintf (buf, sizeof (buf), "%x", grub_be_to_cpu16 (addr)); ++ grub_strcpy (p, buf); ++ p += grub_strlen (buf); ++ ++ if (squash == 1) ++ squash = 2; ++ } ++ else ++ { ++ if (squash == 0) ++ { ++ *p++ = ':'; ++ squash = 1; ++ } ++ else if (squash == 2) ++ { ++ *p++ = ':'; ++ *p++ = '0'; ++ } ++ } ++ } ++ *p = '\0'; ++ return str; ++} ++ ++int ++grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *address, const char **rest) ++{ ++ grub_uint16_t newip[8]; ++ const char *ptr = val; ++ int word, quaddot = -1; ++ int bracketed = 0; ++ ++ if (ptr[0] == '[') { ++ bracketed = 1; ++ ptr++; ++ } ++ ++ if (ptr[0] == ':' && ptr[1] != ':') ++ return 0; ++ if (ptr[0] == ':') ++ ptr++; ++ ++ for (word = 0; word < 8; word++) ++ { ++ unsigned long t; ++ if (*ptr == ':') ++ { ++ quaddot = word; ++ word--; ++ ptr++; ++ continue; ++ } ++ t = grub_strtoul (ptr, &ptr, 16); ++ if (grub_errno) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ break; ++ } ++ if (t & ~0xffff) ++ return 0; ++ newip[word] = grub_cpu_to_be16 (t); ++ if (*ptr != ':') ++ break; ++ ptr++; ++ } ++ if (quaddot == -1 && word < 7) ++ return 0; ++ if (quaddot != -1) ++ { ++ grub_memmove (&newip[quaddot + 7 - word], &newip[quaddot], ++ (word - quaddot + 1) * sizeof (newip[0])); ++ grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0])); ++ } ++ grub_memcpy (address, newip, 16); ++ if (bracketed && *ptr == ']') { ++ ptr++; ++ } ++ if (rest) ++ *rest = ptr; ++ return 1; ++} ++ ++static grub_efi_ip6_config_interface_info_t * ++efi_ip6_config_interface_info (grub_efi_ip6_config_protocol_t *ip6_config) ++{ ++ grub_efi_uintn_t sz; ++ grub_efi_status_t status; ++ grub_efi_ip6_config_interface_info_t *interface_info; ++ ++ sz = sizeof (*interface_info) + sizeof (*interface_info->route_table); ++ interface_info = grub_malloc (sz); ++ ++ status = efi_call_4 (ip6_config->get_data, ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO, ++ &sz, interface_info); ++ ++ if (status == GRUB_EFI_BUFFER_TOO_SMALL) ++ { ++ grub_free (interface_info); ++ interface_info = grub_malloc (sz); ++ status = efi_call_4 (ip6_config->get_data, ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO, ++ &sz, interface_info); ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (interface_info); ++ return NULL; ++ } ++ ++ return interface_info; ++} ++ ++static grub_efi_ip6_config_manual_address_t * ++efi_ip6_config_manual_address (grub_efi_ip6_config_protocol_t *ip6_config) ++{ ++ grub_efi_uintn_t sz; ++ grub_efi_status_t status; ++ grub_efi_ip6_config_manual_address_t *manual_address; ++ ++ sz = sizeof (*manual_address); ++ manual_address = grub_malloc (sz); ++ if (!manual_address) ++ return NULL; ++ ++ status = efi_call_4 (ip6_config->get_data, ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, ++ &sz, manual_address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (manual_address); ++ return NULL; ++ } ++ ++ return manual_address; ++} ++ ++char * ++grub_efi_ip6_interface_name (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip6_config_interface_info_t *interface_info; ++ char *name; ++ ++ interface_info = efi_ip6_config_interface_info (dev->ip6_config); ++ ++ if (!interface_info) ++ return NULL; ++ ++ name = grub_malloc (GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE ++ * GRUB_MAX_UTF8_PER_UTF16 + 1); ++ *grub_utf16_to_utf8 ((grub_uint8_t *)name, interface_info->name, ++ GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE) = 0; ++ grub_free (interface_info); ++ return name; ++} ++ ++static char * ++grub_efi_ip6_interface_hw_address (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip6_config_interface_info_t *interface_info; ++ char *hw_addr; ++ ++ interface_info = efi_ip6_config_interface_info (dev->ip6_config); ++ ++ if (!interface_info) ++ return NULL; ++ ++ hw_addr = grub_efi_hw_address_to_string (interface_info->hw_address_size, interface_info->hw_address); ++ grub_free (interface_info); ++ ++ return hw_addr; ++} ++ ++static char * ++grub_efi_ip6_interface_address (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip6_config_manual_address_t *manual_address; ++ char *addr; ++ ++ manual_address = efi_ip6_config_manual_address (dev->ip6_config); ++ ++ if (!manual_address) ++ return NULL; ++ ++ addr = grub_efi_ip6_address_to_string ((grub_efi_pxe_ipv6_address_t *)&manual_address->address); ++ grub_free (manual_address); ++ return addr; ++} ++ ++static char ** ++grub_efi_ip6_interface_route_table (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip6_config_interface_info_t *interface_info; ++ char **ret; ++ int i, id; ++ grub_size_t sz; ++ ++ interface_info = efi_ip6_config_interface_info (dev->ip6_config); ++ if (!interface_info) ++ return NULL; ++ ++ if (grub_add (interface_info->route_count, 1, &sz)) ++ { ++ grub_free (interface_info); ++ return NULL; ++ } ++ ++ ret = grub_calloc (sz, sizeof (*ret)); ++ ++ if (!ret) ++ { ++ grub_free (interface_info); ++ return NULL; ++ } ++ ++ id = 0; ++ for (i = 0; i < (int)interface_info->route_count ; i++) ++ { ++ char *gateway, *destination; ++ grub_uint64_t u64_gateway[2]; ++ grub_uint64_t u64_destination[2]; ++ grub_efi_ip6_route_table_t *route_table = interface_info->route_table + i; ++ grub_efi_net_interface_t *inf; ++ char *interface_name = NULL; ++ ++ gateway = grub_efi_ip6_address_to_string (&route_table->gateway); ++ destination = grub_efi_ip6_address_to_string (&route_table->destination); ++ ++ u64_gateway[0] = grub_get_unaligned64 (route_table->gateway.addr); ++ u64_gateway[1] = grub_get_unaligned64 (route_table->gateway.addr + 8); ++ u64_destination[0] = grub_get_unaligned64 (route_table->destination.addr); ++ u64_destination[1] = grub_get_unaligned64 (route_table->destination.addr + 8); ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ if (inf->prefer_ip6) ++ interface_name = inf->name; ++ ++ if ((!u64_gateway[0] && !u64_gateway[1]) ++ && (u64_destination[0] || u64_destination[1])) ++ { ++ if (interface_name) ++ { ++ if ((grub_be_to_cpu64 (u64_destination[0]) == 0xfe80000000000000ULL) ++ && (!u64_destination[1]) ++ && (route_table->prefix_length == 64)) ++ ret[id++] = grub_xasprintf ("%s:link %s/%d %s", dev->card_name, destination, route_table->prefix_length, interface_name); ++ else ++ ret[id++] = grub_xasprintf ("%s:local %s/%d %s", dev->card_name, destination, route_table->prefix_length, interface_name); ++ } ++ } ++ else if ((u64_gateway[0] || u64_gateway[1]) ++ && (u64_destination[0] || u64_destination[1])) ++ ret[id++] = grub_xasprintf ("%s:gw %s/%d gw %s", dev->card_name, destination, route_table->prefix_length, gateway); ++ else if ((u64_gateway[0] || u64_gateway[1]) ++ && (!u64_destination[0] && !u64_destination[1])) ++ ret[id++] = grub_xasprintf ("%s:default %s/%d gw %s", dev->card_name, destination, route_table->prefix_length, gateway); ++ ++ grub_free (gateway); ++ grub_free (destination); ++ } ++ ++ ret[id] = NULL; ++ grub_free (interface_info); ++ return ret; ++} ++ ++static grub_efi_net_interface_t * ++grub_efi_ip6_interface_match (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *ip_address) ++{ ++ grub_efi_ip6_config_interface_info_t *interface_info; ++ grub_efi_net_interface_t *inf; ++ int i; ++ grub_efi_ipv6_address_t *address = &ip_address->ip6; ++ ++ interface_info = efi_ip6_config_interface_info (dev->ip6_config); ++ if (!interface_info) ++ return NULL; ++ ++ for (i = 0; i < (int)interface_info->route_count ; i++) ++ { ++ grub_uint64_t u64_addr[2]; ++ grub_uint64_t u64_subnet[2]; ++ grub_uint64_t u64_mask[2]; ++ ++ grub_efi_ip6_route_table_t *route_table = interface_info->route_table + i; ++ ++ /* SKIP Default GATEWAY */ ++ if (route_table->prefix_length == 0) ++ continue; ++ ++ u64_addr[0] = grub_get_unaligned64 (address); ++ u64_addr[1] = grub_get_unaligned64 (address + 4); ++ u64_subnet[0] = grub_get_unaligned64 (route_table->destination.addr); ++ u64_subnet[1] = grub_get_unaligned64 (route_table->destination.addr + 8); ++ u64_mask[0] = (route_table->prefix_length <= 64) ? ++ 0xffffffffffffffffULL << (64 - route_table->prefix_length) : ++ 0xffffffffffffffffULL; ++ u64_mask[1] = (route_table->prefix_length <= 64) ? ++ 0 : ++ 0xffffffffffffffffULL << (128 - route_table->prefix_length); ++ ++ if (((u64_addr[0] & u64_mask[0]) == u64_subnet[0]) ++ && ((u64_addr[1] & u64_mask[1]) == u64_subnet[1])) ++ { ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ if (inf->prefer_ip6) ++ { ++ grub_free (interface_info); ++ return inf; ++ } ++ } ++ } ++ ++ grub_free (interface_info); ++ return NULL; ++} ++ ++static int ++grub_efi_ip6_interface_set_manual_address (struct grub_efi_net_device *dev, ++ grub_efi_net_ip_manual_address_t *net_ip, ++ int with_subnet) ++{ ++ grub_efi_status_t status; ++ grub_efi_ip6_config_manual_address_t *address = &net_ip->ip6; ++ ++ if (!with_subnet) ++ { ++ grub_efi_ip6_config_manual_address_t *manual_address = ++ efi_ip6_config_manual_address (dev->ip6_config); ++ ++ if (manual_address) ++ { ++ address->prefix_length = manual_address->prefix_length; ++ grub_free (manual_address); ++ } ++ else ++ { ++ /* XXX: */ ++ address->prefix_length = 64; ++ } ++ } ++ ++ status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, ++ sizeof(*address), address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ ++ return 1; ++} ++ ++static int ++grub_efi_ip6_interface_set_gateway (struct grub_efi_net_device *dev, ++ grub_efi_net_ip_address_t *address) ++{ ++ grub_efi_status_t status; ++ ++ status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_GATEWAY, ++ sizeof (address->ip6), &address->ip6); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ return 1; ++} ++ ++static int ++grub_efi_ip6_interface_set_dns (struct grub_efi_net_device *dev, ++ grub_efi_net_ip_address_t *address) ++{ ++ ++ grub_efi_status_t status; ++ ++ status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER, ++ sizeof (address->ip6), &address->ip6); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ return 1; ++} ++ ++grub_efi_net_ip_config_t *efi_net_ip6_config = &(grub_efi_net_ip_config_t) ++ { ++ .get_hw_address = grub_efi_ip6_interface_hw_address, ++ .get_address = grub_efi_ip6_interface_address, ++ .get_route_table = grub_efi_ip6_interface_route_table, ++ .best_interface = grub_efi_ip6_interface_match, ++ .set_address = grub_efi_ip6_interface_set_manual_address, ++ .set_gateway = grub_efi_ip6_interface_set_gateway, ++ .set_dns = grub_efi_ip6_interface_set_dns ++ }; +Index: grub-2.06/grub-core/net/efi/net.c +=================================================================== +--- /dev/null ++++ grub-2.06/grub-core/net/efi/net.c +@@ -0,0 +1,1440 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++#define GRUB_EFI_IP6_PREFIX_LENGTH 64 ++ ++static grub_efi_guid_t ip4_config_guid = GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID; ++static grub_efi_guid_t ip6_config_guid = GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID; ++static grub_efi_guid_t http_service_binding_guid = GRUB_EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID; ++static grub_efi_guid_t http_guid = GRUB_EFI_HTTP_PROTOCOL_GUID; ++static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID; ++static grub_efi_guid_t dhcp4_service_binding_guid = GRUB_EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID; ++static grub_efi_guid_t dhcp4_guid = GRUB_EFI_DHCP4_PROTOCOL_GUID; ++static grub_efi_guid_t dhcp6_service_binding_guid = GRUB_EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID; ++static grub_efi_guid_t dhcp6_guid = GRUB_EFI_DHCP6_PROTOCOL_GUID; ++ ++struct grub_efi_net_device *net_devices; ++ ++static char *default_server; ++static grub_efi_net_interface_t *net_interface; ++static grub_efi_net_interface_t *net_default_interface; ++ ++#define efi_net_interface_configure(inf) inf->io->configure (inf->dev, inf->prefer_ip6) ++#define efi_net_interface_open(inf, file, name) inf->io->open (inf->dev, inf->prefer_ip6, file, name, inf->io_type) ++#define efi_net_interface_read(inf, file, buf, sz) inf->io->read (inf->dev, inf->prefer_ip6, file, buf, sz) ++#define efi_net_interface_close(inf, file) inf->io->close (inf->dev, inf->prefer_ip6, file) ++#define efi_net_interface(m,...) efi_net_interface_ ## m (net_interface, ## __VA_ARGS__) ++ ++static grub_efi_handle_t ++grub_efi_locate_device_path (grub_efi_guid_t *protocol, grub_efi_device_path_t *device_path, ++ grub_efi_device_path_t **r_device_path) ++{ ++ grub_efi_handle_t handle; ++ grub_efi_status_t status; ++ ++ status = efi_call_3 (grub_efi_system_table->boot_services->locate_device_path, ++ protocol, &device_path, &handle); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ ++ if (r_device_path) ++ *r_device_path = device_path; ++ ++ return handle; ++} ++ ++static int ++url_parse_fields (const char *url, char **proto, char **host, char **path) ++{ ++ const char *p, *ps; ++ grub_size_t l; ++ ++ *proto = *host = *path = NULL; ++ ps = p = url; ++ ++ while ((p = grub_strchr (p, ':'))) ++ { ++ if (grub_strlen (p) < sizeof ("://") - 1) ++ break; ++ if (grub_memcmp (p, "://", sizeof ("://") - 1) == 0) ++ { ++ l = p - ps; ++ *proto = grub_malloc (l + 1); ++ if (!*proto) ++ { ++ grub_print_error (); ++ return 0; ++ } ++ ++ grub_memcpy (*proto, ps, l); ++ (*proto)[l] = '\0'; ++ p += sizeof ("://") - 1; ++ break; ++ } ++ ++p; ++ } ++ ++ if (!*proto) ++ { ++ grub_dprintf ("bootp", "url: %s is not valid, protocol not found\n", url); ++ return 0; ++ } ++ ++ ps = p; ++ p = grub_strchr (p, '/'); ++ ++ if (!p) ++ { ++ grub_dprintf ("bootp", "url: %s is not valid, host/path not found\n", url); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ ++ l = p - ps; ++ ++ if (l > 2 && ps[0] == '[' && ps[l - 1] == ']') ++ { ++ *host = grub_malloc (l - 1); ++ if (!*host) ++ { ++ grub_print_error (); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ grub_memcpy (*host, ps + 1, l - 2); ++ (*host)[l - 2] = 0; ++ } ++ else ++ { ++ *host = grub_malloc (l + 1); ++ if (!*host) ++ { ++ grub_print_error (); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ grub_memcpy (*host, ps, l); ++ (*host)[l] = 0; ++ } ++ ++ *path = grub_strdup (p); ++ if (!*path) ++ { ++ grub_print_error (); ++ grub_free (*host); ++ grub_free (*proto); ++ *host = NULL; ++ *proto = NULL; ++ return 0; ++ } ++ return 1; ++} ++ ++static void ++url_get_boot_location (const char *url, char **device, char **path, int is_default) ++{ ++ char *protocol, *server, *file; ++ char *slash; ++ ++ if (!url_parse_fields (url, &protocol, &server, &file)) ++ return; ++ ++ if ((slash = grub_strrchr (file, '/'))) ++ *slash = 0; ++ else ++ *file = 0; ++ ++ *device = grub_xasprintf ("%s,%s", protocol, server); ++ *path = grub_strdup(file); ++ ++ if (is_default) ++ default_server = server; ++ else ++ grub_free (server); ++ ++ grub_free (protocol); ++ grub_free (file); ++} ++ ++static void ++pxe_get_boot_location (const struct grub_net_bootp_packet *bp, ++ char **device, ++ char **path, ++ int is_default) ++{ ++ char *server = grub_xasprintf ("%d.%d.%d.%d", ++ ((grub_uint8_t *) &bp->server_ip)[0], ++ ((grub_uint8_t *) &bp->server_ip)[1], ++ ((grub_uint8_t *) &bp->server_ip)[2], ++ ((grub_uint8_t *) &bp->server_ip)[3]); ++ ++ *device = grub_xasprintf ("tftp,%s", server); ++ ++ *path = grub_strndup (bp->boot_file, sizeof (bp->boot_file)); ++ ++ if (*path) ++ { ++ char *slash; ++ slash = grub_strrchr (*path, '/'); ++ if (slash) ++ *slash = 0; ++ else ++ **path = 0; ++ } ++ ++ if (is_default) ++ default_server = server; ++ else ++ grub_free (server); ++} ++ ++static void ++pxe_get_boot_location_v6 (const struct grub_net_dhcp6_packet *dp, ++ grub_size_t dhcp_size, ++ char **device, ++ char **path) ++{ ++ ++ struct grub_net_dhcp6_option *dhcp_opt; ++ grub_size_t dhcp_remain_size; ++ *device = *path = 0; ++ ++ if (dhcp_size < sizeof (*dp)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("DHCPv6 packet size too small")); ++ return; ++ } ++ ++ dhcp_remain_size = dhcp_size - sizeof (*dp); ++ dhcp_opt = (struct grub_net_dhcp6_option *)dp->dhcp_options; ++ ++ while (dhcp_remain_size) ++ { ++ grub_uint16_t code = grub_be_to_cpu16 (dhcp_opt->code); ++ grub_uint16_t len = grub_be_to_cpu16 (dhcp_opt->len); ++ grub_uint16_t option_size = sizeof (*dhcp_opt) + len; ++ ++ if (dhcp_remain_size < option_size || code == 0) ++ break; ++ ++ if (code == GRUB_NET_DHCP6_OPTION_BOOTFILE_URL) ++ { ++ char *url; ++ grub_size_t sz; ++ ++ if (grub_add (len, 1, &sz)) ++ return; ++ ++ url = grub_malloc (sz); ++ if (!url) ++ return; ++ ++ grub_memcpy (url, dhcp_opt->data, len); ++ url[len] = 0; ++ ++ url_get_boot_location ((const char *)url, device, path, 1); ++ grub_free (url); ++ break; ++ } ++ ++ dhcp_remain_size -= option_size; ++ dhcp_opt = (struct grub_net_dhcp6_option *)((grub_uint8_t *)dhcp_opt + option_size); ++ } ++} ++ ++static grub_efi_net_interface_t * ++grub_efi_net_config_from_device_path (grub_efi_device_path_t *dp, ++ struct grub_efi_net_device *netdev, ++ char **device, ++ char **path) ++{ ++ grub_efi_net_interface_t *inf = NULL; ++ ++ while (1) ++ { ++ grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); ++ grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); ++ grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp); ++ ++ if (type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE) ++ { ++ if (subtype == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE) ++ { ++ grub_efi_uri_device_path_t *uri_dp; ++ uri_dp = (grub_efi_uri_device_path_t *) dp; ++ /* Beware that uri_dp->uri may not be null terminated */ ++ url_get_boot_location ((const char *)uri_dp->uri, device, path, 1); ++ } ++ else if (subtype == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE) ++ { ++ grub_efi_net_ip_manual_address_t net_ip; ++ grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) dp; ++ ++ if (inf) ++ continue; ++ grub_memcpy (net_ip.ip4.address, ipv4->local_ip_address, sizeof (net_ip.ip4.address)); ++ grub_memcpy (net_ip.ip4.subnet_mask, ipv4->subnet_mask, sizeof (net_ip.ip4.subnet_mask)); ++ net_ip.is_ip6 = 0; ++ inf = grub_efi_net_create_interface (netdev, ++ netdev->card_name, ++ &net_ip, ++ 1); ++ } ++ else if (subtype == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE) ++ { ++ grub_efi_net_ip_manual_address_t net_ip; ++ grub_efi_ipv6_device_path_t *ipv6 = (grub_efi_ipv6_device_path_t *) dp; ++ ++ if (inf) ++ continue; ++ grub_memcpy (net_ip.ip6.address, ipv6->local_ip_address, sizeof (net_ip.ip6.address)); ++ net_ip.ip6.prefix_length = GRUB_EFI_IP6_PREFIX_LENGTH; ++ net_ip.ip6.is_anycast = 0; ++ net_ip.is_ip6 = 1; ++ inf = grub_efi_net_create_interface (netdev, ++ netdev->card_name, ++ &net_ip, ++ 1); ++ } ++ } ++ ++ if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) ++ break; ++ dp = (grub_efi_device_path_t *) ((char *) dp + len); ++ } ++ ++ return inf; ++} ++ ++static grub_efi_net_interface_t * ++grub_efi_net_config_from_handle (grub_efi_handle_t *hnd, ++ struct grub_efi_net_device *netdev, ++ char **device, ++ char **path) ++{ ++ grub_efi_pxe_t *pxe = NULL; ++ ++ if (hnd == netdev->ip4_pxe_handle) ++ pxe = netdev->ip4_pxe; ++ else if (hnd == netdev->ip6_pxe_handle) ++ pxe = netdev->ip6_pxe; ++ ++ if (!pxe) ++ return (grub_efi_net_config_from_device_path ( ++ grub_efi_get_device_path (hnd), ++ netdev, ++ device, ++ path)); ++ ++ if (pxe->mode->using_ipv6) ++ { ++ grub_efi_net_ip_manual_address_t net_ip; ++ ++ pxe_get_boot_location_v6 ( ++ (const struct grub_net_dhcp6_packet *) &pxe->mode->dhcp_ack, ++ sizeof (pxe->mode->dhcp_ack), ++ device, ++ path); ++ ++ grub_memcpy (net_ip.ip6.address, pxe->mode->station_ip.v6.addr, sizeof(net_ip.ip6.address)); ++ net_ip.ip6.prefix_length = GRUB_EFI_IP6_PREFIX_LENGTH; ++ net_ip.ip6.is_anycast = 0; ++ net_ip.is_ip6 = 1; ++ return (grub_efi_net_create_interface (netdev, ++ netdev->card_name, ++ &net_ip, ++ 1)); ++ } ++ else ++ { ++ grub_efi_net_ip_manual_address_t net_ip; ++ ++ pxe_get_boot_location ( ++ (const struct grub_net_bootp_packet *) &pxe->mode->dhcp_ack, ++ device, ++ path, ++ 1); ++ ++ grub_memcpy (net_ip.ip4.address, pxe->mode->station_ip.v4.addr, sizeof (net_ip.ip4.address)); ++ grub_memcpy (net_ip.ip4.subnet_mask, pxe->mode->subnet_mask.v4.addr, sizeof (net_ip.ip4.subnet_mask)); ++ net_ip.is_ip6 = 0; ++ return (grub_efi_net_create_interface (netdev, ++ netdev->card_name, ++ &net_ip, ++ 1)); ++ } ++} ++ ++static const char * ++grub_efi_net_var_get_address (struct grub_env_var *var, ++ const char *val __attribute__ ((unused))) ++{ ++ struct grub_efi_net_device *dev; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ grub_efi_net_interface_t *inf; ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ { ++ char *var_name; ++ ++ var_name = grub_xasprintf ("net_%s_ip", inf->name); ++ if (grub_strcmp (var_name, var->name) == 0) ++ return efi_net_interface_get_address (inf); ++ grub_free (var_name); ++ var_name = grub_xasprintf ("net_%s_mac", inf->name); ++ if (grub_strcmp (var_name, var->name) == 0) ++ return efi_net_interface_get_hw_address (inf); ++ grub_free (var_name); ++ } ++ } ++ ++ return NULL; ++} ++ ++static char * ++grub_efi_net_var_set_interface (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val) ++{ ++ struct grub_efi_net_device *dev; ++ grub_efi_net_interface_t *inf; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ if (grub_strcmp (inf->name, val) == 0) ++ { ++ net_default_interface = inf; ++ return grub_strdup (val); ++ } ++ ++ return NULL; ++} ++ ++static char * ++grub_efi_net_var_set_server (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val) ++{ ++ grub_free (default_server); ++ default_server = grub_strdup (val); ++ return grub_strdup (val); ++} ++ ++static const char * ++grub_efi_net_var_get_server (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ return default_server ? : ""; ++} ++ ++static const char * ++grub_efi_net_var_get_ip (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ const char *intf = grub_env_get ("net_default_interface"); ++ const char *ret = NULL; ++ if (intf) ++ { ++ char *buf = grub_xasprintf ("net_%s_ip", intf); ++ if (buf) ++ ret = grub_env_get (buf); ++ grub_free (buf); ++ } ++ return ret; ++} ++ ++static const char * ++grub_efi_net_var_get_mac (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ const char *intf = grub_env_get ("net_default_interface"); ++ const char *ret = NULL; ++ if (intf) ++ { ++ char *buf = grub_xasprintf ("net_%s_mac", intf); ++ if (buf) ++ ret = grub_env_get (buf); ++ grub_free (buf); ++ } ++ return ret; ++} ++ ++static void ++grub_efi_net_export_interface_vars (void) ++{ ++ struct grub_efi_net_device *dev; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ grub_efi_net_interface_t *inf; ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ { ++ char *var; ++ ++ var = grub_xasprintf ("net_%s_ip", inf->name); ++ grub_register_variable_hook (var, grub_efi_net_var_get_address, 0); ++ grub_env_export (var); ++ grub_free (var); ++ var = grub_xasprintf ("net_%s_mac", inf->name); ++ grub_register_variable_hook (var, grub_efi_net_var_get_address, 0); ++ grub_env_export (var); ++ grub_free (var); ++ } ++ } ++} ++ ++static void ++grub_efi_net_unset_interface_vars (void) ++{ ++ struct grub_efi_net_device *dev; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ grub_efi_net_interface_t *inf; ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ { ++ char *var; ++ ++ var = grub_xasprintf ("net_%s_ip", inf->name); ++ grub_register_variable_hook (var, 0, 0); ++ grub_env_unset (var); ++ grub_free (var); ++ var = grub_xasprintf ("net_%s_mac", inf->name); ++ grub_register_variable_hook (var, 0, 0); ++ grub_env_unset (var); ++ grub_free (var); ++ } ++ } ++} ++ ++grub_efi_net_interface_t * ++grub_efi_net_create_interface (struct grub_efi_net_device *dev, ++ const char *interface_name, ++ grub_efi_net_ip_manual_address_t *net_ip, ++ int has_subnet) ++{ ++ grub_efi_net_interface_t *inf; ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ { ++ if (inf->prefer_ip6 == net_ip->is_ip6) ++ break; ++ } ++ ++ if (!inf) ++ { ++ inf = grub_malloc (sizeof(*inf)); ++ inf->name = grub_strdup (interface_name); ++ inf->prefer_ip6 = net_ip->is_ip6; ++ inf->dev = dev; ++ inf->next = dev->net_interfaces; ++ inf->ip_config = (net_ip->is_ip6) ? efi_net_ip6_config : efi_net_ip4_config ; ++ dev->net_interfaces = inf; ++ } ++ else ++ { ++ grub_free (inf->name); ++ inf->name = grub_strdup (interface_name); ++ } ++ ++ if (!efi_net_interface_set_address (inf, net_ip, has_subnet)) ++ { ++ grub_error (GRUB_ERR_BUG, N_("Set Address Failed")); ++ return NULL; ++ } ++ ++ return inf; ++} ++ ++static void ++grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, ++ char **path) ++{ ++ grub_efi_handle_t config_hnd; ++ ++ struct grub_efi_net_device *netdev; ++ grub_efi_net_interface_t *inf; ++ ++ config_hnd = grub_efi_locate_device_path (&ip4_config_guid, grub_efi_get_device_path (hnd), NULL); ++ ++ if (!config_hnd) ++ return; ++ ++ for (netdev = net_devices; netdev; netdev = netdev->next) ++ if (netdev->handle == config_hnd) ++ break; ++ ++ if (!netdev) ++ return; ++ ++ if (!(inf = grub_efi_net_config_from_handle (hnd, netdev, device, path))) ++ return; ++ ++ grub_env_set ("net_default_interface", inf->name); ++ grub_efi_net_export_interface_vars (); ++} ++ ++static grub_err_t ++grub_efi_netfs_dir (grub_device_t device, const char *path __attribute__ ((unused)), ++ grub_fs_dir_hook_t hook __attribute__ ((unused)), ++ void *hook_data __attribute__ ((unused))) ++{ ++ if (!device->net) ++ return grub_error (GRUB_ERR_BUG, "invalid net device"); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_efi_netfs_open (struct grub_file *file_out __attribute__ ((unused)), ++ const char *name __attribute__ ((unused))) ++{ ++ struct grub_file *file, *bufio; ++ ++ file = grub_malloc (sizeof (*file)); ++ if (!file) ++ return grub_errno; ++ ++ grub_memcpy (file, file_out, sizeof (struct grub_file)); ++ file->device->net->name = grub_strdup (name); ++ ++ if (!file->device->net->name) ++ { ++ grub_free (file); ++ return grub_errno; ++ } ++ ++ efi_net_interface(open, file, name); ++ grub_print_error (); ++ ++ bufio = grub_bufio_open (file, 32768); ++ if (!bufio) ++ { ++ grub_free (file->device->net->name); ++ grub_free (file); ++ return grub_errno; ++ } ++ grub_memcpy (file_out, bufio, sizeof (struct grub_file)); ++ grub_free (bufio); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_ssize_t ++grub_efihttp_chunk_read (grub_file_t file, char *buf, ++ grub_size_t len, grub_size_t chunk_size) ++{ ++ char *chunk = grub_malloc (chunk_size); ++ grub_size_t sum = 0; ++ ++ while (len) ++ { ++ grub_ssize_t rd; ++ grub_size_t sz = (len > chunk_size) ? chunk_size : len; ++ ++ rd = efi_net_interface (read, file, chunk, sz); ++ ++ if (rd <= 0) ++ return rd; ++ ++ if (buf) ++ { ++ grub_memcpy (buf, chunk, rd); ++ buf += rd; ++ } ++ sum += rd; ++ len -= rd; ++ } ++ ++ grub_free (chunk); ++ return sum; ++} ++ ++static grub_ssize_t ++grub_efi_netfs_read (grub_file_t file __attribute__ ((unused)), ++ char *buf __attribute__ ((unused)), grub_size_t len __attribute__ ((unused))) ++{ ++ if (file->offset > file->device->net->offset) ++ { ++ grub_efihttp_chunk_read (file, NULL, file->offset - file->device->net->offset, 10240); ++ } ++ else if (file->offset < file->device->net->offset) ++ { ++ efi_net_interface (close, file); ++ efi_net_interface (open, file, file->device->net->name); ++ if (file->offset) ++ grub_efihttp_chunk_read (file, NULL, file->offset, 10240); ++ } ++ ++ return efi_net_interface (read, file, buf, len); ++} ++ ++static grub_err_t ++grub_efi_netfs_close (grub_file_t file) ++{ ++ efi_net_interface (close, file); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_efi_handle_t ++grub_efi_service_binding (grub_efi_handle_t dev, grub_efi_guid_t *service_binding_guid) ++{ ++ grub_efi_service_binding_t *service; ++ grub_efi_status_t status; ++ grub_efi_handle_t child_dev = NULL; ++ ++ service = grub_efi_open_protocol (dev, service_binding_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ if (!service) ++ { ++ grub_error (GRUB_ERR_IO, N_("couldn't open efi service binding protocol")); ++ return NULL; ++ } ++ ++ status = efi_call_2 (service->create_child, service, &child_dev); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_error (GRUB_ERR_IO, N_("Failed to create child device of http service %" PRIxGRUB_SIZE), status); ++ return NULL; ++ } ++ ++ return child_dev; ++} ++ ++static grub_err_t ++grub_efi_net_parse_address (const char *address, ++ grub_efi_ip4_config2_manual_address_t *ip4, ++ grub_efi_ip6_config_manual_address_t *ip6, ++ int *is_ip6, ++ int *has_cidr) ++{ ++ const char *rest; ++ ++ if (grub_efi_string_to_ip4_address (address, &ip4->address, &rest)) ++ { ++ *is_ip6 = 0; ++ if (*rest == '/') ++ { ++ grub_uint32_t subnet_mask_size; ++ ++ subnet_mask_size = grub_strtoul (rest + 1, &rest, 0); ++ ++ if (!grub_errno && subnet_mask_size <= 32 && *rest == 0) ++ { ++ grub_uint32_t subnet_mask; ++ ++ subnet_mask = grub_cpu_to_be32 ((0xffffffffU << (32 - subnet_mask_size))); ++ grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask)); ++ if (has_cidr) ++ *has_cidr = 1; ++ return GRUB_ERR_NONE; ++ } ++ } ++ else if (*rest == 0) ++ { ++ grub_uint32_t subnet_mask = 0xffffffffU; ++ grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask)); ++ if (has_cidr) ++ *has_cidr = 0; ++ return GRUB_ERR_NONE; ++ } ++ } ++ else if (grub_efi_string_to_ip6_address (address, &ip6->address, &rest)) ++ { ++ *is_ip6 = 1; ++ if (*rest == '/') ++ { ++ grub_efi_uint8_t prefix_length; ++ ++ prefix_length = grub_strtoul (rest + 1, &rest, 0); ++ if (!grub_errno && prefix_length <= 128 && *rest == 0) ++ { ++ ip6->prefix_length = prefix_length; ++ ip6->is_anycast = 0; ++ if (has_cidr) ++ *has_cidr = 1; ++ return GRUB_ERR_NONE; ++ } ++ } ++ else if (*rest == 0) ++ { ++ ip6->prefix_length = 128; ++ ip6->is_anycast = 0; ++ if (has_cidr) ++ *has_cidr = 0; ++ return GRUB_ERR_NONE; ++ } ++ } ++ ++ return grub_error (GRUB_ERR_NET_BAD_ADDRESS, ++ N_("unrecognised network address `%s'"), ++ address); ++} ++ ++static grub_efi_net_interface_t * ++match_route (const char *server) ++{ ++ grub_err_t err; ++ grub_efi_ip4_config2_manual_address_t ip4; ++ grub_efi_ip6_config_manual_address_t ip6; ++ grub_efi_net_interface_t *inf; ++ int is_ip6 = 0; ++ ++ grub_error_push (); ++ err = grub_efi_net_parse_address (server, &ip4, &ip6, &is_ip6, 0); ++ ++ if (err) ++ { ++ grub_dprintf ("efinetfs", "error in matching route : %s\n", grub_errmsg); ++ grub_error_pop (); ++ return NULL; ++ } ++ grub_error_pop (); ++ ++ if (is_ip6) ++ { ++ struct grub_efi_net_device *dev; ++ grub_efi_net_ip_address_t addr; ++ ++ grub_memcpy (addr.ip6, ip6.address, sizeof(ip6.address)); ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ if ((inf = efi_net_ip6_config->best_interface (dev, &addr))) ++ return inf; ++ } ++ else ++ { ++ struct grub_efi_net_device *dev; ++ grub_efi_net_ip_address_t addr; ++ ++ grub_memcpy (addr.ip4, ip4.address, sizeof(ip4.address)); ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ if ((inf = efi_net_ip4_config->best_interface (dev, &addr))) ++ return inf; ++ } ++ ++ return 0; ++} ++ ++static void ++grub_efi_net_add_pxebc_to_cards (void) ++{ ++ grub_efi_uintn_t num_handles; ++ grub_efi_handle_t *handles; ++ grub_efi_handle_t *handle; ++ ++ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &pxe_io_guid, ++ 0, &num_handles); ++ if (!handles) ++ return; ++ ++ for (handle = handles; num_handles--; handle++) ++ { ++ grub_efi_device_path_t *dp, *ddp, *ldp; ++ grub_efi_pxe_t *pxe; ++ struct grub_efi_net_device *d; ++ int is_ip6 = 0; ++ ++ dp = grub_efi_get_device_path (*handle); ++ if (!dp) ++ continue; ++ ++ ddp = grub_efi_duplicate_device_path (dp); ++ ldp = grub_efi_find_last_device_path (ddp); ++ ++ if (ldp->type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE ++ && ldp->subtype == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE) ++ { ++ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ ldp->length = sizeof (*ldp); ++ } ++ else if (ldp->type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE ++ && ldp->subtype == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE) ++ { ++ is_ip6 = 1; ++ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ ldp->length = sizeof (*ldp); ++ } ++ ++ for (d = net_devices; d; d = d->next) ++ if (grub_efi_compare_device_paths (ddp, grub_efi_get_device_path (d->handle)) == 0) ++ break; ++ ++ if (!d) ++ { ++ grub_free (ddp); ++ continue; ++ } ++ ++ pxe = grub_efi_open_protocol (*handle, &pxe_io_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ ++ if (!pxe) ++ { ++ grub_free (ddp); ++ continue; ++ } ++ ++ if (is_ip6) ++ { ++ d->ip6_pxe_handle = *handle; ++ d->ip6_pxe = pxe; ++ } ++ else ++ { ++ d->ip4_pxe_handle = *handle; ++ d->ip4_pxe = pxe; ++ } ++ ++ grub_free (ddp); ++ } ++ ++ grub_free (handles); ++} ++ ++static void ++set_ip_policy_to_static (void) ++{ ++ struct grub_efi_net_device *dev; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ grub_efi_ip4_config2_policy_t ip4_policy = GRUB_EFI_IP4_CONFIG2_POLICY_STATIC; ++ ++ if (efi_call_4 (dev->ip4_config->set_data, dev->ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_POLICY, ++ sizeof (ip4_policy), &ip4_policy) != GRUB_EFI_SUCCESS) ++ grub_dprintf ("efinetfs", "could not set GRUB_EFI_IP4_CONFIG2_POLICY_STATIC on dev `%s'", dev->card_name); ++ ++ if (dev->ip6_config) ++ { ++ grub_efi_ip6_config_policy_t ip6_policy = GRUB_EFI_IP6_CONFIG_POLICY_MANUAL; ++ ++ if (efi_call_4 (dev->ip6_config->set_data, dev->ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_POLICY, ++ sizeof (ip6_policy), &ip6_policy) != GRUB_EFI_SUCCESS) ++ grub_dprintf ("efinetfs", "could not set GRUB_EFI_IP6_CONFIG_POLICY_MANUAL on dev `%s'", dev->card_name); ++ } ++ } ++} ++ ++/* FIXME: Do not fail if the card did not support any of the protocol (Eg http) */ ++static void ++grub_efi_net_find_cards (void) ++{ ++ grub_efi_uintn_t num_handles; ++ grub_efi_handle_t *handles; ++ grub_efi_handle_t *handle; ++ int id; ++ ++ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &ip4_config_guid, ++ 0, &num_handles); ++ if (!handles) ++ return; ++ ++ for (id = 0, handle = handles; num_handles--; handle++, id++) ++ { ++ grub_efi_device_path_t *dp; ++ grub_efi_ip4_config2_protocol_t *ip4_config; ++ grub_efi_ip6_config_protocol_t *ip6_config; ++ grub_efi_handle_t http_handle; ++ grub_efi_http_t *http; ++ grub_efi_handle_t dhcp4_handle; ++ grub_efi_dhcp4_protocol_t *dhcp4; ++ grub_efi_handle_t dhcp6_handle; ++ grub_efi_dhcp6_protocol_t *dhcp6; ++ ++ struct grub_efi_net_device *d; ++ ++ dp = grub_efi_get_device_path (*handle); ++ if (!dp) ++ continue; ++ ++ ip4_config = grub_efi_open_protocol (*handle, &ip4_config_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ if (!ip4_config) ++ continue; ++ ++ ip6_config = grub_efi_open_protocol (*handle, &ip6_config_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ ++ http_handle = grub_efi_service_binding (*handle, &http_service_binding_guid); ++ grub_errno = GRUB_ERR_NONE; ++ http = (http_handle) ++ ? grub_efi_open_protocol (http_handle, &http_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL) ++ : NULL; ++ ++ dhcp4_handle = grub_efi_service_binding (*handle, &dhcp4_service_binding_guid); ++ grub_errno = GRUB_ERR_NONE; ++ dhcp4 = (dhcp4_handle) ++ ? grub_efi_open_protocol (dhcp4_handle, &dhcp4_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL) ++ : NULL; ++ ++ ++ dhcp6_handle = grub_efi_service_binding (*handle, &dhcp6_service_binding_guid); ++ grub_errno = GRUB_ERR_NONE; ++ dhcp6 = (dhcp6_handle) ++ ? grub_efi_open_protocol (dhcp6_handle, &dhcp6_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL) ++ : NULL; ++ ++ d = grub_malloc (sizeof (*d)); ++ if (!d) ++ { ++ grub_free (handles); ++ while (net_devices) ++ { ++ d = net_devices->next; ++ grub_free (net_devices); ++ net_devices = d; ++ } ++ return; ++ } ++ d->handle = *handle; ++ d->ip4_config = ip4_config; ++ d->ip6_config = ip6_config; ++ d->http_handle = http_handle; ++ d->http = http; ++ d->dhcp4_handle = dhcp4_handle; ++ d->dhcp4 = dhcp4; ++ d->dhcp6_handle = dhcp6_handle; ++ d->dhcp6 = dhcp6; ++ d->next = net_devices; ++ d->card_name = grub_xasprintf ("efinet%d", id); ++ d->net_interfaces = NULL; ++ net_devices = d; ++ } ++ ++ grub_efi_net_add_pxebc_to_cards (); ++ grub_free (handles); ++ set_ip_policy_to_static (); ++} ++ ++static void ++listroutes_ip4 (struct grub_efi_net_device *netdev) ++{ ++ char **routes; ++ ++ routes = NULL; ++ ++ if ((routes = efi_net_ip4_config->get_route_table (netdev))) ++ { ++ char **r; ++ ++ for (r = routes; *r; ++r) ++ grub_printf ("%s\n", *r); ++ } ++ ++ if (routes) ++ { ++ char **r; ++ ++ for (r = routes; *r; ++r) ++ grub_free (*r); ++ grub_free (routes); ++ } ++} ++ ++static void ++listroutes_ip6 (struct grub_efi_net_device *netdev) ++{ ++ char **routes; ++ ++ routes = NULL; ++ ++ if ((routes = efi_net_ip6_config->get_route_table (netdev))) ++ { ++ char **r; ++ ++ for (r = routes; *r; ++r) ++ grub_printf ("%s\n", *r); ++ } ++ ++ if (routes) ++ { ++ char **r; ++ ++ for (r = routes; *r; ++r) ++ grub_free (*r); ++ grub_free (routes); ++ } ++} ++ ++static grub_err_t ++grub_cmd_efi_listroutes (struct grub_command *cmd __attribute__ ((unused)), ++ int argc __attribute__ ((unused)), ++ char **args __attribute__ ((unused))) ++{ ++ struct grub_efi_net_device *netdev; ++ ++ for (netdev = net_devices; netdev; netdev = netdev->next) ++ { ++ listroutes_ip4 (netdev); ++ listroutes_ip6 (netdev); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++static grub_err_t ++grub_cmd_efi_listcards (struct grub_command *cmd __attribute__ ((unused)), ++ int argc __attribute__ ((unused)), ++ char **args __attribute__ ((unused))) ++{ ++ struct grub_efi_net_device *dev; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ char *hw_addr; ++ ++ hw_addr = efi_net_ip4_config->get_hw_address (dev); ++ ++ if (hw_addr) ++ { ++ grub_printf ("%s %s\n", dev->card_name, hw_addr); ++ grub_free (hw_addr); ++ } ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_efi_listaddrs (struct grub_command *cmd __attribute__ ((unused)), ++ int argc __attribute__ ((unused)), ++ char **args __attribute__ ((unused))) ++{ ++ struct grub_efi_net_device *dev; ++ grub_efi_net_interface_t *inf; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ { ++ char *hw_addr = NULL; ++ char *addr = NULL; ++ ++ if ((hw_addr = efi_net_interface_get_hw_address (inf)) ++ && (addr = efi_net_interface_get_address (inf))) ++ grub_printf ("%s %s %s\n", inf->name, hw_addr, addr); ++ ++ if (hw_addr) ++ grub_free (hw_addr); ++ if (addr) ++ grub_free (addr); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++/* FIXME: support MAC specifying. */ ++static grub_err_t ++grub_cmd_efi_addaddr (struct grub_command *cmd __attribute__ ((unused)), ++ int argc, char **args) ++{ ++ struct grub_efi_net_device *dev; ++ grub_err_t err; ++ grub_efi_ip4_config2_manual_address_t ip4; ++ grub_efi_ip6_config_manual_address_t ip6; ++ grub_efi_net_ip_manual_address_t net_ip; ++ int is_ip6 = 0; ++ int cidr = 0; ++ ++ if (argc != 3) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("three arguments expected")); ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ if (grub_strcmp (dev->card_name, args[1]) == 0) ++ break; ++ } ++ ++ if (!dev) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("card not found")); ++ ++ err = grub_efi_net_parse_address (args[2], &ip4, &ip6, &is_ip6, &cidr); ++ ++ if (err) ++ return err; ++ ++ net_ip.is_ip6 = is_ip6; ++ if (is_ip6) ++ grub_memcpy (&net_ip.ip6, &ip6, sizeof(net_ip.ip6)); ++ else ++ grub_memcpy (&net_ip.ip4, &ip4, sizeof(net_ip.ip4)); ++ ++ if (!grub_efi_net_create_interface (dev, ++ args[0], ++ &net_ip, ++ cidr)) ++ return grub_errno; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static struct grub_fs grub_efi_netfs; ++ ++static grub_net_t ++grub_net_open_real (const char *name __attribute__ ((unused))) ++{ ++ grub_size_t protnamelen; ++ const char *protname, *server; ++ grub_net_t ret; ++ ++ net_interface = NULL; ++ ++ if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0) ++ { ++ protname = "tftp"; ++ protnamelen = sizeof ("tftp") - 1; ++ server = name + sizeof ("pxe:") - 1; ++ } ++ else if (grub_strcmp (name, "pxe") == 0) ++ { ++ protname = "tftp"; ++ protnamelen = sizeof ("tftp") - 1; ++ server = default_server; ++ } ++ else ++ { ++ const char *comma; ++ ++ comma = grub_strchr (name, ','); ++ if (comma) ++ { ++ protnamelen = comma - name; ++ server = comma + 1; ++ protname = name; ++ } ++ else ++ { ++ protnamelen = grub_strlen (name); ++ server = default_server; ++ protname = name; ++ } ++ } ++ ++ if (!server) ++ { ++ grub_error (GRUB_ERR_NET_BAD_ADDRESS, ++ N_("no server is specified")); ++ return NULL; ++ } ++ ++ /*FIXME: Use DNS translate name to address */ ++ net_interface = match_route (server); ++ ++ /*XXX: should we check device with default gateway ? */ ++ if (!net_interface && !(net_interface = net_default_interface)) ++ { ++ grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' no route found"), ++ name); ++ return NULL; ++ } ++ ++ if ((protnamelen == (sizeof ("https") - 1) ++ && grub_memcmp ("https", protname, protnamelen) == 0)) ++ { ++ net_interface->io = &io_http; ++ net_interface->io_type = 1; ++ } ++ else if ((protnamelen == (sizeof ("http") - 1) ++ && grub_memcmp ("http", protname, protnamelen) == 0)) ++ { ++ net_interface->io = &io_http; ++ net_interface->io_type = 0; ++ } ++ else if (protnamelen == (sizeof ("tftp") - 1) ++ && grub_memcmp ("tftp", protname, protnamelen) == 0) ++ { ++ net_interface->io = &io_pxe; ++ net_interface->io_type = 0; ++ } ++ else ++ { ++ grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' not found"), ++ name); ++ return NULL; ++ } ++ ++ /*XXX: Should we try to avoid doing excess "reconfigure" here ??? */ ++ efi_net_interface (configure); ++ ++ ret = grub_zalloc (sizeof (*ret)); ++ if (!ret) ++ return NULL; ++ ++ ret->server = grub_strdup (server); ++ if (!ret->server) ++ { ++ grub_free (ret); ++ return NULL; ++ } ++ ++ ret->fs = &grub_efi_netfs; ++ return ret; ++} ++#if 0 ++static grub_command_t cmd_efi_lsaddr; ++static grub_command_t cmd_efi_lscards; ++static grub_command_t cmd_efi_lsroutes; ++static grub_command_t cmd_efi_addaddr; ++#endif ++ ++static struct grub_fs grub_efi_netfs = ++ { ++ .name = "efi netfs", ++ .fs_dir = grub_efi_netfs_dir, ++ .fs_open = grub_efi_netfs_open, ++ .fs_read = grub_efi_netfs_read, ++ .fs_close = grub_efi_netfs_close, ++ .fs_label = NULL, ++ .fs_uuid = NULL, ++ .fs_mtime = NULL, ++ }; ++ ++int ++grub_efi_net_boot_from_https (void) ++{ ++ grub_efi_loaded_image_t *image = NULL; ++ grub_efi_device_path_t *dp; ++ ++ image = grub_efi_get_loaded_image (grub_efi_image_handle); ++ if (!image) ++ return 0; ++ ++ dp = grub_efi_get_device_path (image->device_handle); ++ ++ while (1) ++ { ++ grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); ++ grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); ++ grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp); ++ ++ if ((type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE) ++ && (subtype == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)) ++ { ++ grub_efi_uri_device_path_t *uri_dp = (grub_efi_uri_device_path_t *) dp; ++ return (grub_strncmp ((const char*)uri_dp->uri, "https://", sizeof ("https://") - 1) == 0) ? 1 : 0; ++ } ++ ++ if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) ++ break; ++ dp = (grub_efi_device_path_t *) ((char *) dp + len); ++ } ++ ++ return 0; ++} ++ ++int ++grub_efi_net_boot_from_opa (void) ++{ ++ grub_efi_loaded_image_t *image = NULL; ++ grub_efi_device_path_t *dp; ++ ++ image = grub_efi_get_loaded_image (grub_efi_image_handle); ++ if (!image) ++ return 0; ++ ++ dp = grub_efi_get_device_path (image->device_handle); ++ ++ while (1) ++ { ++ grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); ++ grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); ++ grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp); ++ ++ if ((type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE) ++ && (subtype == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE)) ++ { ++ grub_efi_mac_address_device_path_t *mac_dp = (grub_efi_mac_address_device_path_t *)dp; ++ return (mac_dp->if_type == 0xC7) ? 1 : 0; ++ } ++ ++ if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) ++ break; ++ dp = (grub_efi_device_path_t *) ((char *) dp + len); ++ } ++ ++ return 0; ++} ++ ++static char * ++grub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ return NULL; ++} ++ ++grub_command_func_t grub_efi_net_list_routes = grub_cmd_efi_listroutes; ++grub_command_func_t grub_efi_net_list_cards = grub_cmd_efi_listcards; ++grub_command_func_t grub_efi_net_list_addrs = grub_cmd_efi_listaddrs; ++grub_command_func_t grub_efi_net_add_addr = grub_cmd_efi_addaddr; ++ ++int ++grub_efi_net_fs_init () ++{ ++ grub_efi_net_find_cards (); ++ grub_efi_net_config = grub_efi_net_config_real; ++ grub_net_open = grub_net_open_real; ++ grub_register_variable_hook ("net_default_server", grub_efi_net_var_get_server, ++ grub_efi_net_var_set_server); ++ grub_env_export ("net_default_server"); ++ grub_register_variable_hook ("pxe_default_server", grub_efi_net_var_get_server, ++ grub_efi_net_var_set_server); ++ grub_env_export ("pxe_default_server"); ++ grub_register_variable_hook ("net_default_interface", 0, ++ grub_efi_net_var_set_interface); ++ grub_env_export ("net_default_interface"); ++ grub_register_variable_hook ("net_default_ip", grub_efi_net_var_get_ip, ++ 0); ++ grub_env_export ("net_default_ip"); ++ grub_register_variable_hook ("net_default_mac", grub_efi_net_var_get_mac, ++ 0); ++ grub_env_export ("net_default_mac"); ++ ++ grub_env_set ("grub_netfs_type", "efi"); ++ grub_register_variable_hook ("grub_netfs_type", 0, grub_env_write_readonly); ++ grub_env_export ("grub_netfs_type"); ++ ++ return 1; ++} ++ ++void ++grub_efi_net_fs_fini (void) ++{ ++ grub_env_unset ("grub_netfs_type"); ++ grub_efi_net_unset_interface_vars (); ++ grub_register_variable_hook ("net_default_server", 0, 0); ++ grub_env_unset ("net_default_server"); ++ grub_register_variable_hook ("net_default_interface", 0, 0); ++ grub_env_unset ("net_default_interface"); ++ grub_register_variable_hook ("pxe_default_server", 0, 0); ++ grub_env_unset ("pxe_default_server"); ++ grub_register_variable_hook ("net_default_ip", 0, 0); ++ grub_env_unset ("net_default_ip"); ++ grub_register_variable_hook ("net_default_mac", 0, 0); ++ grub_env_unset ("net_default_mac"); ++ grub_efi_net_config = NULL; ++ grub_net_open = NULL; ++ grub_fs_unregister (&grub_efi_netfs); ++} +Index: grub-2.06/grub-core/net/efi/pxe.c +=================================================================== +--- /dev/null ++++ grub-2.06/grub-core/net/efi/pxe.c +@@ -0,0 +1,424 @@ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static grub_efi_ip6_config_manual_address_t * ++efi_ip6_config_manual_address (grub_efi_ip6_config_protocol_t *ip6_config) ++{ ++ grub_efi_uintn_t sz; ++ grub_efi_status_t status; ++ grub_efi_ip6_config_manual_address_t *manual_address; ++ ++ sz = sizeof (*manual_address); ++ manual_address = grub_malloc (sz); ++ if (!manual_address) ++ return NULL; ++ ++ status = efi_call_4 (ip6_config->get_data, ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, ++ &sz, manual_address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (manual_address); ++ return NULL; ++ } ++ ++ return manual_address; ++} ++ ++static grub_efi_ip4_config2_manual_address_t * ++efi_ip4_config_manual_address (grub_efi_ip4_config2_protocol_t *ip4_config) ++{ ++ grub_efi_uintn_t sz; ++ grub_efi_status_t status; ++ grub_efi_ip4_config2_manual_address_t *manual_address; ++ ++ sz = sizeof (*manual_address); ++ manual_address = grub_malloc (sz); ++ if (!manual_address) ++ return NULL; ++ ++ status = efi_call_4 (ip4_config->get_data, ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, ++ &sz, manual_address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (manual_address); ++ return NULL; ++ } ++ ++ return manual_address; ++} ++ ++static void ++pxe_configure (struct grub_efi_net_device *dev, int prefer_ip6) ++{ ++ grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe; ++ ++ grub_efi_pxe_mode_t *mode = pxe->mode; ++ ++ if (!mode->started) ++ { ++ grub_efi_status_t status; ++ status = efi_call_2 (pxe->start, pxe, prefer_ip6); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ grub_printf ("Couldn't start PXE\n"); ++ } ++ ++#if 0 ++ grub_printf ("PXE STARTED: %u\n", mode->started); ++ grub_printf ("PXE USING IPV6: %u\n", mode->using_ipv6); ++#endif ++ ++ if (mode->using_ipv6) ++ { ++ grub_efi_ip6_config_manual_address_t *manual_address; ++ manual_address = efi_ip6_config_manual_address (dev->ip6_config); ++ ++ if (manual_address && ++ grub_memcmp (manual_address->address, mode->station_ip.v6.addr, sizeof (manual_address->address)) != 0) ++ { ++ grub_efi_status_t status; ++ grub_efi_pxe_ip_address_t station_ip; ++ ++ grub_memcpy (station_ip.v6.addr, manual_address->address, sizeof (station_ip.v6.addr)); ++ status = efi_call_3 (pxe->set_station_ip, pxe, &station_ip, NULL); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ grub_printf ("Couldn't set station ip\n"); ++ ++ grub_free (manual_address); ++ } ++ } ++ else ++ { ++ grub_efi_ip4_config2_manual_address_t *manual_address; ++ manual_address = efi_ip4_config_manual_address (dev->ip4_config); ++ ++ if (manual_address && ++ grub_memcmp (manual_address->address, mode->station_ip.v4.addr, sizeof (manual_address->address)) != 0) ++ { ++ grub_efi_status_t status; ++ grub_efi_pxe_ip_address_t station_ip; ++ grub_efi_pxe_ip_address_t subnet_mask; ++ ++ grub_memcpy (station_ip.v4.addr, manual_address->address, sizeof (station_ip.v4.addr)); ++ grub_memcpy (subnet_mask.v4.addr, manual_address->subnet_mask, sizeof (subnet_mask.v4.addr)); ++ ++ status = efi_call_3 (pxe->set_station_ip, pxe, &station_ip, &subnet_mask); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ grub_printf ("Couldn't set station ip\n"); ++ ++ grub_free (manual_address); ++ } ++ } ++ ++#if 0 ++ if (mode->using_ipv6) ++ { ++ grub_printf ("PXE STATION IP: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n", ++ mode->station_ip.v6.addr[0], ++ mode->station_ip.v6.addr[1], ++ mode->station_ip.v6.addr[2], ++ mode->station_ip.v6.addr[3], ++ mode->station_ip.v6.addr[4], ++ mode->station_ip.v6.addr[5], ++ mode->station_ip.v6.addr[6], ++ mode->station_ip.v6.addr[7], ++ mode->station_ip.v6.addr[8], ++ mode->station_ip.v6.addr[9], ++ mode->station_ip.v6.addr[10], ++ mode->station_ip.v6.addr[11], ++ mode->station_ip.v6.addr[12], ++ mode->station_ip.v6.addr[13], ++ mode->station_ip.v6.addr[14], ++ mode->station_ip.v6.addr[15]); ++ } ++ else ++ { ++ grub_printf ("PXE STATION IP: %d.%d.%d.%d\n", ++ mode->station_ip.v4.addr[0], ++ mode->station_ip.v4.addr[1], ++ mode->station_ip.v4.addr[2], ++ mode->station_ip.v4.addr[3]); ++ grub_printf ("PXE SUBNET MASK: %d.%d.%d.%d\n", ++ mode->subnet_mask.v4.addr[0], ++ mode->subnet_mask.v4.addr[1], ++ mode->subnet_mask.v4.addr[2], ++ mode->subnet_mask.v4.addr[3]); ++ } ++#endif ++ ++ /* TODO: Set The Station IP to the IP2 Config */ ++} ++ ++static int ++parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest) ++{ ++ grub_uint16_t newip[8]; ++ const char *ptr = val; ++ int word, quaddot = -1; ++ int bracketed = 0; ++ ++ if (ptr[0] == '[') { ++ bracketed = 1; ++ ptr++; ++ } ++ ++ if (ptr[0] == ':' && ptr[1] != ':') ++ return 0; ++ if (ptr[0] == ':') ++ ptr++; ++ ++ for (word = 0; word < 8; word++) ++ { ++ unsigned long t; ++ if (*ptr == ':') ++ { ++ quaddot = word; ++ word--; ++ ptr++; ++ continue; ++ } ++ t = grub_strtoul (ptr, &ptr, 16); ++ if (grub_errno) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ break; ++ } ++ if (t & ~0xffff) ++ return 0; ++ newip[word] = grub_cpu_to_be16 (t); ++ if (*ptr != ':') ++ break; ++ ptr++; ++ } ++ if (quaddot == -1 && word < 7) ++ return 0; ++ if (quaddot != -1) ++ { ++ grub_memmove (&newip[quaddot + 7 - word], &newip[quaddot], ++ (word - quaddot + 1) * sizeof (newip[0])); ++ grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0])); ++ } ++ grub_memcpy (ip, newip, 16); ++ if (bracketed && *ptr == ']') { ++ ptr++; ++ } ++ if (rest) ++ *rest = ptr; ++ return 1; ++} ++ ++static grub_err_t ++pxe_open (struct grub_efi_net_device *dev, ++ int prefer_ip6, ++ grub_file_t file, ++ const char *filename, ++ int type __attribute__((unused))) ++{ ++ int i; ++ const char *p; ++ grub_efi_status_t status; ++ grub_efi_pxe_ip_address_t server_ip; ++ grub_efi_uint64_t file_size = 0; ++ grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe; ++ ++ if (pxe->mode->using_ipv6) ++ { ++ const char *rest; ++ grub_uint64_t ip6[2]; ++ if (parse_ip6 (file->device->net->server, ip6, &rest) && *rest == 0) ++ grub_memcpy (server_ip.v6.addr, ip6, sizeof (server_ip.v6.addr)); ++ /* TODO: ERROR Handling Here */ ++#if 0 ++ grub_printf ("PXE SERVER IP: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n", ++ server_ip.v6.addr[0], ++ server_ip.v6.addr[1], ++ server_ip.v6.addr[2], ++ server_ip.v6.addr[3], ++ server_ip.v6.addr[4], ++ server_ip.v6.addr[5], ++ server_ip.v6.addr[6], ++ server_ip.v6.addr[7], ++ server_ip.v6.addr[8], ++ server_ip.v6.addr[9], ++ server_ip.v6.addr[10], ++ server_ip.v6.addr[11], ++ server_ip.v6.addr[12], ++ server_ip.v6.addr[13], ++ server_ip.v6.addr[14], ++ server_ip.v6.addr[15]); ++#endif ++ } ++ else ++ { ++ for (i = 0, p = file->device->net->server; i < 4; ++i, ++p) ++ server_ip.v4.addr[i] = grub_strtoul (p, &p, 10); ++ } ++ ++ status = efi_call_10 (pxe->mtftp, ++ pxe, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, ++ NULL, ++ 0, ++ &file_size, ++ NULL, ++ &server_ip, ++ (grub_efi_char8_t *)filename, ++ NULL, ++ 0); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return grub_error (GRUB_ERR_IO, "Couldn't get file size"); ++ ++ file->size = (grub_off_t)file_size; ++ file->not_easily_seekable = 0; ++ file->data = 0; ++ file->device->net->offset = 0; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++pxe_close (struct grub_efi_net_device *dev __attribute__((unused)), ++ int prefer_ip6 __attribute__((unused)), ++ grub_file_t file __attribute__((unused))) ++{ ++ file->offset = 0; ++ file->size = 0; ++ file->device->net->offset = 0; ++ ++ if (file->data) ++ { ++ grub_free (file->data); ++ file->data = NULL; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_ssize_t ++pxe_read (struct grub_efi_net_device *dev, ++ int prefer_ip6, ++ grub_file_t file, ++ char *buf, ++ grub_size_t len) ++{ ++ int i; ++ const char *p; ++ grub_efi_status_t status; ++ grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe; ++ grub_efi_uint64_t bufsz = len; ++ grub_efi_pxe_ip_address_t server_ip; ++ char *buf2 = NULL; ++ ++ if (file->data) ++ { ++ /* TODO: RANGE Check for offset and file size */ ++ grub_memcpy (buf, (char*)file->data + file->device->net->offset, len); ++ file->device->net->offset += len; ++ return len; ++ } ++ ++ if (file->device->net->offset) ++ { ++ grub_error (GRUB_ERR_BUG, "No Offet Read Possible"); ++ grub_print_error (); ++ return 0; ++ } ++ ++ if (pxe->mode->using_ipv6) ++ { ++ const char *rest; ++ grub_uint64_t ip6[2]; ++ if (parse_ip6 (file->device->net->server, ip6, &rest) && *rest == 0) ++ grub_memcpy (server_ip.v6.addr, ip6, sizeof (server_ip.v6.addr)); ++ /* TODO: ERROR Handling Here */ ++ } ++ else ++ { ++ for (i = 0, p = file->device->net->server; i < 4; ++i, ++p) ++ server_ip.v4.addr[i] = grub_strtoul (p, &p, 10); ++ } ++ ++ status = efi_call_10 (pxe->mtftp, ++ pxe, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE, ++ buf, ++ 0, ++ &bufsz, ++ NULL, ++ &server_ip, ++ (grub_efi_char8_t *)file->device->net->name, ++ NULL, ++ 0); ++ ++ if (bufsz != file->size) ++ { ++ grub_error (GRUB_ERR_BUG, "Short read should not happen here"); ++ grub_print_error (); ++ return 0; ++ } ++ ++ if (status == GRUB_EFI_BUFFER_TOO_SMALL) ++ { ++ ++ buf2 = grub_malloc (bufsz); ++ ++ if (!buf2) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, "ERROR OUT OF MEMORY"); ++ grub_print_error (); ++ return 0; ++ } ++ ++ status = efi_call_10 (pxe->mtftp, ++ pxe, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE, ++ buf2, ++ 0, ++ &bufsz, ++ NULL, ++ &server_ip, ++ (grub_efi_char8_t *)file->device->net->name, ++ NULL, ++ 0); ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ if (buf2) ++ grub_free (buf2); ++ ++ grub_error (GRUB_ERR_IO, "Failed to Read File"); ++ grub_print_error (); ++ return 0; ++ } ++ ++ if (buf2) ++ grub_memcpy (buf, buf2, len); ++ ++ file->device->net->offset = len; ++ ++ if (buf2) ++ file->data = buf2; ++ ++ return len; ++} ++ ++struct grub_efi_net_io io_pxe = ++ { ++ .configure = pxe_configure, ++ .open = pxe_open, ++ .read = pxe_read, ++ .close = pxe_close ++ }; ++ +Index: grub-2.06/grub-core/net/net.c +=================================================================== +--- grub-2.06.orig/grub-core/net/net.c ++++ grub-2.06/grub-core/net/net.c +@@ -32,6 +32,9 @@ + #include + #include + #include ++#ifdef GRUB_MACHINE_EFI ++#include ++#endif + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -1954,8 +1957,49 @@ static grub_command_t cmd_addaddr, cmd_d + static grub_command_t cmd_lsroutes, cmd_lscards; + static grub_command_t cmd_lsaddr, cmd_slaac; + ++#ifdef GRUB_MACHINE_EFI ++ ++static enum { ++ INIT_MODE_NONE, ++ INIT_MODE_GRUB, ++ INIT_MODE_EFI ++} init_mode; ++ ++static grub_command_t cmd_bootp, cmd_bootp6; ++ ++#endif ++ + GRUB_MOD_INIT(net) + { ++#ifdef GRUB_MACHINE_EFI ++ if (grub_net_open) ++ return; ++ ++ if ((grub_efi_net_boot_from_https () || grub_efi_net_boot_from_opa ()) ++ && grub_efi_net_fs_init ()) ++ { ++ cmd_lsroutes = grub_register_command ("net_ls_routes", grub_efi_net_list_routes, ++ "", N_("list network routes")); ++ cmd_lscards = grub_register_command ("net_ls_cards", grub_efi_net_list_cards, ++ "", N_("list network cards")); ++ cmd_lsaddr = grub_register_command ("net_ls_addr", grub_efi_net_list_addrs, ++ "", N_("list network addresses")); ++ cmd_addaddr = grub_register_command ("net_add_addr", grub_efi_net_add_addr, ++ /* TRANSLATORS: HWADDRESS stands for ++ "hardware address". */ ++ N_("SHORTNAME CARD ADDRESS [HWADDRESS]"), ++ N_("Add a network address.")); ++ cmd_bootp = grub_register_command ("net_bootp", grub_efi_net_bootp, ++ N_("[CARD]"), ++ N_("perform a bootp autoconfiguration")); ++ cmd_bootp6 = grub_register_command ("net_bootp6", grub_efi_net_bootp6, ++ N_("[CARD]"), ++ N_("perform a bootp autoconfiguration")); ++ init_mode = INIT_MODE_EFI; ++ return; ++ } ++#endif ++ + grub_register_variable_hook ("net_default_server", defserver_get_env, + defserver_set_env); + grub_env_export ("net_default_server"); +@@ -2003,10 +2047,37 @@ GRUB_MOD_INIT(net) + grub_net_restore_hw, + GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK); + grub_net_poll_cards_idle = grub_net_poll_cards_idle_real; ++ ++#ifdef GRUB_MACHINE_EFI ++ grub_env_set ("grub_netfs_type", "grub"); ++ grub_register_variable_hook ("grub_netfs_type", 0, grub_env_write_readonly); ++ grub_env_export ("grub_netfs_type"); ++ init_mode = INIT_MODE_GRUB; ++#endif ++ + } + + GRUB_MOD_FINI(net) + { ++ ++#ifdef GRUB_MACHINE_EFI ++ if (init_mode == INIT_MODE_NONE) ++ return; ++ ++ if (init_mode == INIT_MODE_EFI) ++ { ++ grub_unregister_command (cmd_lsroutes); ++ grub_unregister_command (cmd_lscards); ++ grub_unregister_command (cmd_lsaddr); ++ grub_unregister_command (cmd_addaddr); ++ grub_unregister_command (cmd_bootp); ++ grub_unregister_command (cmd_bootp6); ++ grub_efi_net_fs_fini (); ++ init_mode = INIT_MODE_NONE; ++ return; ++ } ++#endif ++ + grub_register_variable_hook ("net_default_server", 0, 0); + grub_register_variable_hook ("pxe_default_server", 0, 0); + +@@ -2025,4 +2096,7 @@ GRUB_MOD_FINI(net) + grub_net_fini_hw (0); + grub_loader_unregister_preboot_hook (fini_hnd); + grub_net_poll_cards_idle = grub_net_poll_cards_idle_real; ++#ifdef GRUB_MACHINE_EFI ++ init_mode = INIT_MODE_NONE; ++#endif + } +Index: grub-2.06/include/grub/efi/api.h +=================================================================== +--- grub-2.06.orig/include/grub/efi/api.h ++++ grub-2.06/include/grub/efi/api.h +@@ -608,6 +608,23 @@ typedef grub_uint16_t grub_efi_ipv6_addr + typedef grub_uint8_t grub_efi_ip_address_t[8] __attribute__ ((aligned(4))); + typedef grub_efi_uint64_t grub_efi_physical_address_t; + typedef grub_efi_uint64_t grub_efi_virtual_address_t; ++typedef struct { ++ grub_uint8_t addr[4]; ++} grub_efi_pxe_ipv4_address_t; ++ ++typedef struct { ++ grub_uint8_t addr[16]; ++} grub_efi_pxe_ipv6_address_t; ++ ++typedef struct { ++ grub_uint8_t addr[32]; ++} grub_efi_pxe_mac_address_t; ++ ++typedef union { ++ grub_uint32_t addr[4]; ++ grub_efi_pxe_ipv4_address_t v4; ++ grub_efi_pxe_ipv6_address_t v6; ++} grub_efi_pxe_ip_address_t; + + struct grub_efi_guid + { +@@ -875,6 +892,8 @@ struct grub_efi_ipv6_device_path + grub_efi_uint16_t remote_port; + grub_efi_uint16_t protocol; + grub_efi_uint8_t static_ip_address; ++ grub_efi_uint8_t prefix_length; ++ grub_efi_ipv6_address_t gateway_ip_address; + } GRUB_PACKED; + typedef struct grub_efi_ipv6_device_path grub_efi_ipv6_device_path_t; + +@@ -924,6 +943,15 @@ struct grub_efi_uri_device_path + } GRUB_PACKED; + typedef struct grub_efi_uri_device_path grub_efi_uri_device_path_t; + ++#define GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE 31 ++struct grub_efi_dns_device_path ++{ ++ grub_efi_device_path_t header; ++ grub_efi_uint8_t is_ipv6; ++ grub_efi_pxe_ip_address_t dns_server_ip[0]; ++} GRUB_PACKED; ++typedef struct grub_efi_dns_device_path grub_efi_dns_device_path_t; ++ + #define GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE 10 + + /* Media Device Path. */ +@@ -1006,6 +1034,23 @@ struct grub_efi_bios_device_path + } GRUB_PACKED; + typedef struct grub_efi_bios_device_path grub_efi_bios_device_path_t; + ++/* Service Binding definitions */ ++struct grub_efi_service_binding; ++ ++typedef grub_efi_status_t ++(*grub_efi_service_binding_create_child) (struct grub_efi_service_binding *this, ++ grub_efi_handle_t *child_handle); ++ ++typedef grub_efi_status_t ++(*grub_efi_service_binding_destroy_child) (struct grub_efi_service_binding *this, ++ grub_efi_handle_t *child_handle); ++ ++typedef struct grub_efi_service_binding ++{ ++ grub_efi_service_binding_create_child create_child; ++ grub_efi_service_binding_destroy_child destroy_child; ++} grub_efi_service_binding_t; ++ + struct grub_efi_open_protocol_information_entry + { + grub_efi_handle_t agent_handle; +@@ -1497,23 +1542,28 @@ typedef struct grub_efi_simple_text_outp + + typedef grub_uint8_t grub_efi_pxe_packet_t[1472]; + +-typedef struct { +- grub_uint8_t addr[4]; +-} grub_efi_pxe_ipv4_address_t; ++typedef grub_efi_uint16_t grub_efi_pxe_base_code_udp_port_t; + +-typedef struct { +- grub_uint8_t addr[16]; +-} grub_efi_pxe_ipv6_address_t; ++typedef enum { ++ GRUB_EFI_PXE_BASE_CODE_TFTP_FIRST, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_WRITE_FILE, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY, ++ GRUB_EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE, ++ GRUB_EFI_PXE_BASE_CODE_MTFTP_READ_FILE, ++ GRUB_EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY, ++ GRUB_EFI_PXE_BASE_CODE_MTFTP_LAST ++} grub_efi_pxe_base_code_tftp_opcode_t; + +-typedef struct { +- grub_uint8_t addr[32]; +-} grub_efi_pxe_mac_address_t; + +-typedef union { +- grub_uint32_t addr[4]; +- grub_efi_pxe_ipv4_address_t v4; +- grub_efi_pxe_ipv6_address_t v6; +-} grub_efi_pxe_ip_address_t; ++typedef struct { ++ grub_efi_ip_address_t mcast_ip; ++ grub_efi_pxe_base_code_udp_port_t c_port; ++ grub_efi_pxe_base_code_udp_port_t s_port; ++ grub_efi_uint16_t listen_timeout; ++ grub_efi_uint16_t transmit_timeout; ++} grub_efi_pxe_base_code_mtftp_info_t; + + #define GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT 8 + typedef struct { +@@ -1563,17 +1613,31 @@ typedef struct grub_efi_pxe_mode + typedef struct grub_efi_pxe + { + grub_uint64_t rev; +- void (*start) (void); ++ grub_efi_status_t (*start) (struct grub_efi_pxe *this, grub_efi_boolean_t use_ipv6); + void (*stop) (void); +- void (*dhcp) (void); ++ grub_efi_status_t (*dhcp) (struct grub_efi_pxe *this, ++ grub_efi_boolean_t sort_offers); + void (*discover) (void); +- void (*mftp) (void); ++ grub_efi_status_t (*mtftp) (struct grub_efi_pxe *this, ++ grub_efi_pxe_base_code_tftp_opcode_t operation, ++ void *buffer_ptr, ++ grub_efi_boolean_t overwrite, ++ grub_efi_uint64_t *buffer_size, ++ grub_efi_uintn_t *block_size, ++ grub_efi_pxe_ip_address_t *server_ip, ++ //grub_efi_ip_address_t *server_ip, ++ grub_efi_char8_t *filename, ++ grub_efi_pxe_base_code_mtftp_info_t *info, ++ grub_efi_boolean_t dont_use_buffer); + void (*udpwrite) (void); + void (*udpread) (void); + void (*setipfilter) (void); + void (*arp) (void); + void (*setparams) (void); +- void (*setstationip) (void); ++ grub_efi_status_t (*set_station_ip) (struct grub_efi_pxe *this, ++ grub_efi_pxe_ip_address_t *new_station_ip, ++ grub_efi_pxe_ip_address_t *new_subnet_mask); ++ //void (*setstationip) (void); + void (*setpackets) (void); + struct grub_efi_pxe_mode *mode; + } grub_efi_pxe_t; +@@ -1835,6 +1899,44 @@ struct grub_efi_ip4_config2_protocol + }; + typedef struct grub_efi_ip4_config2_protocol grub_efi_ip4_config2_protocol_t; + ++struct grub_efi_ip4_route_table { ++ grub_efi_ipv4_address_t subnet_address; ++ grub_efi_ipv4_address_t subnet_mask; ++ grub_efi_ipv4_address_t gateway_address; ++}; ++ ++typedef struct grub_efi_ip4_route_table grub_efi_ip4_route_table_t; ++ ++#define GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE 32 ++ ++struct grub_efi_ip4_config2_interface_info { ++ grub_efi_char16_t name[GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE]; ++ grub_efi_uint8_t if_type; ++ grub_efi_uint32_t hw_address_size; ++ grub_efi_mac_address_t hw_address; ++ grub_efi_ipv4_address_t station_address; ++ grub_efi_ipv4_address_t subnet_mask; ++ grub_efi_uint32_t route_table_size; ++ grub_efi_ip4_route_table_t *route_table; ++}; ++ ++typedef struct grub_efi_ip4_config2_interface_info grub_efi_ip4_config2_interface_info_t; ++ ++enum grub_efi_ip4_config2_policy { ++ GRUB_EFI_IP4_CONFIG2_POLICY_STATIC, ++ GRUB_EFI_IP4_CONFIG2_POLICY_DHCP, ++ GRUB_EFI_IP4_CONFIG2_POLICY_MAX ++}; ++ ++typedef enum grub_efi_ip4_config2_policy grub_efi_ip4_config2_policy_t; ++ ++struct grub_efi_ip4_config2_manual_address { ++ grub_efi_ipv4_address_t address; ++ grub_efi_ipv4_address_t subnet_mask; ++}; ++ ++typedef struct grub_efi_ip4_config2_manual_address grub_efi_ip4_config2_manual_address_t; ++ + enum grub_efi_ip6_config_data_type { + GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO, + GRUB_EFI_IP6_CONFIG_DATA_TYPE_ALT_INTERFACEID, +@@ -1869,6 +1971,49 @@ struct grub_efi_ip6_config_protocol + }; + typedef struct grub_efi_ip6_config_protocol grub_efi_ip6_config_protocol_t; + ++enum grub_efi_ip6_config_policy { ++ GRUB_EFI_IP6_CONFIG_POLICY_MANUAL, ++ GRUB_EFI_IP6_CONFIG_POLICY_AUTOMATIC ++}; ++typedef enum grub_efi_ip6_config_policy grub_efi_ip6_config_policy_t; ++ ++struct grub_efi_ip6_address_info { ++ grub_efi_ipv6_address_t address; ++ grub_efi_uint8_t prefix_length; ++}; ++typedef struct grub_efi_ip6_address_info grub_efi_ip6_address_info_t; ++ ++struct grub_efi_ip6_route_table { ++ grub_efi_pxe_ipv6_address_t gateway; ++ grub_efi_pxe_ipv6_address_t destination; ++ grub_efi_uint8_t prefix_length; ++}; ++typedef struct grub_efi_ip6_route_table grub_efi_ip6_route_table_t; ++ ++struct grub_efi_ip6_config_interface_info { ++ grub_efi_char16_t name[32]; ++ grub_efi_uint8_t if_type; ++ grub_efi_uint32_t hw_address_size; ++ grub_efi_mac_address_t hw_address; ++ grub_efi_uint32_t address_info_count; ++ grub_efi_ip6_address_info_t *address_info; ++ grub_efi_uint32_t route_count; ++ grub_efi_ip6_route_table_t *route_table; ++}; ++typedef struct grub_efi_ip6_config_interface_info grub_efi_ip6_config_interface_info_t; ++ ++struct grub_efi_ip6_config_dup_addr_detect_transmits { ++ grub_efi_uint32_t dup_addr_detect_transmits; ++}; ++typedef struct grub_efi_ip6_config_dup_addr_detect_transmits grub_efi_ip6_config_dup_addr_detect_transmits_t; ++ ++struct grub_efi_ip6_config_manual_address { ++ grub_efi_ipv6_address_t address; ++ grub_efi_boolean_t is_anycast; ++ grub_efi_uint8_t prefix_length; ++}; ++typedef struct grub_efi_ip6_config_manual_address grub_efi_ip6_config_manual_address_t; ++ + #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \ + || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) \ + || defined(__riscv) +Index: grub-2.06/include/grub/efi/dhcp.h +=================================================================== +--- /dev/null ++++ grub-2.06/include/grub/efi/dhcp.h +@@ -0,0 +1,343 @@ ++#ifndef GRUB_EFI_DHCP_HEADER ++#define GRUB_EFI_DHCP_HEADER 1 ++ ++#define GRUB_EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID \ ++ { 0x9d9a39d8, 0xbd42, 0x4a73, \ ++ { 0xa4, 0xd5, 0x8e, 0xe9, 0x4b, 0xe1, 0x13, 0x80 } \ ++ } ++ ++#define GRUB_EFI_DHCP4_PROTOCOL_GUID \ ++ { 0x8a219718, 0x4ef5, 0x4761, \ ++ { 0x91, 0xc8, 0xc0, 0xf0, 0x4b, 0xda, 0x9e, 0x56 } \ ++ } ++ ++#define GRUB_EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID \ ++ { 0x9fb9a8a1, 0x2f4a, 0x43a6, \ ++ { 0x88, 0x9c, 0xd0, 0xf7, 0xb6, 0xc4 ,0x7a, 0xd5 } \ ++ } ++ ++#define GRUB_EFI_DHCP6_PROTOCOL_GUID \ ++ { 0x87c8bad7, 0x595, 0x4053, \ ++ { 0x82, 0x97, 0xde, 0xde, 0x39, 0x5f, 0x5d, 0x5b } \ ++ } ++ ++typedef struct grub_efi_dhcp4_protocol grub_efi_dhcp4_protocol_t; ++ ++enum grub_efi_dhcp4_state { ++ GRUB_EFI_DHCP4_STOPPED, ++ GRUB_EFI_DHCP4_INIT, ++ GRUB_EFI_DHCP4_SELECTING, ++ GRUB_EFI_DHCP4_REQUESTING, ++ GRUB_EFI_DHCP4_BOUND, ++ GRUB_EFI_DHCP4_RENEWING, ++ GRUB_EFI_DHCP4_REBINDING, ++ GRUB_EFI_DHCP4_INIT_REBOOT, ++ GRUB_EFI_DHCP4_REBOOTING ++}; ++ ++typedef enum grub_efi_dhcp4_state grub_efi_dhcp4_state_t; ++ ++struct grub_efi_dhcp4_header { ++ grub_efi_uint8_t op_code; ++ grub_efi_uint8_t hw_type; ++ grub_efi_uint8_t hw_addr_len; ++ grub_efi_uint8_t hops; ++ grub_efi_uint32_t xid; ++ grub_efi_uint16_t seconds; ++ grub_efi_uint16_t reserved; ++ grub_efi_ipv4_address_t client_addr; ++ grub_efi_ipv4_address_t your_addr; ++ grub_efi_ipv4_address_t server_addr; ++ grub_efi_ipv4_address_t gateway_addr; ++ grub_efi_uint8_t client_hw_addr[16]; ++ grub_efi_char8_t server_name[64]; ++ grub_efi_char8_t boot_file_name[128]; ++} GRUB_PACKED; ++ ++typedef struct grub_efi_dhcp4_header grub_efi_dhcp4_header_t; ++ ++struct grub_efi_dhcp4_packet { ++ grub_efi_uint32_t size; ++ grub_efi_uint32_t length; ++ struct { ++ grub_efi_dhcp4_header_t header; ++ grub_efi_uint32_t magik; ++ grub_efi_uint8_t option[1]; ++ } dhcp4; ++} GRUB_PACKED; ++ ++typedef struct grub_efi_dhcp4_packet grub_efi_dhcp4_packet_t; ++ ++struct grub_efi_dhcp4_listen_point { ++ grub_efi_ipv4_address_t listen_address; ++ grub_efi_ipv4_address_t subnet_mask; ++ grub_efi_uint16_t listen_port; ++}; ++ ++typedef struct grub_efi_dhcp4_listen_point grub_efi_dhcp4_listen_point_t; ++ ++struct grub_efi_dhcp4_transmit_receive_token { ++ grub_efi_status_t status; ++ grub_efi_event_t completion_event; ++ grub_efi_ipv4_address_t remote_address; ++ grub_efi_uint16_t remote_port; ++ grub_efi_ipv4_address_t gateway_address; ++ grub_efi_uint32_t listen_point_count; ++ grub_efi_dhcp4_listen_point_t *listen_points; ++ grub_efi_uint32_t timeout_value; ++ grub_efi_dhcp4_packet_t *packet; ++ grub_efi_uint32_t response_count; ++ grub_efi_dhcp4_packet_t *response_list; ++}; ++ ++typedef struct grub_efi_dhcp4_transmit_receive_token grub_efi_dhcp4_transmit_receive_token_t; ++ ++enum grub_efi_dhcp4_event { ++ GRUB_EFI_DHCP4_SEND_DISCOVER = 0X01, ++ GRUB_EFI_DHCP4_RCVD_OFFER, ++ GRUB_EFI_DHCP4_SELECT_OFFER, ++ GRUB_EFI_DHCP4_SEND_REQUEST, ++ GRUB_EFI_DHCP4_RCVD_ACK, ++ GRUB_EFI_DHCP4_RCVD_NAK, ++ GRUB_EFI_DHCP4_SEND_DECLINE, ++ GRUB_EFI_DHCP4_BOUND_COMPLETED, ++ GRUB_EFI_DHCP4_ENTER_RENEWING, ++ GRUB_EFI_DHCP4_ENTER_REBINDING, ++ GRUB_EFI_DHCP4_ADDRESS_LOST, ++ GRUB_EFI_DHCP4_FAIL ++}; ++ ++typedef enum grub_efi_dhcp4_event grub_efi_dhcp4_event_t; ++ ++struct grub_efi_dhcp4_packet_option { ++ grub_efi_uint8_t op_code; ++ grub_efi_uint8_t length; ++ grub_efi_uint8_t data[1]; ++} GRUB_PACKED; ++ ++typedef struct grub_efi_dhcp4_packet_option grub_efi_dhcp4_packet_option_t; ++ ++struct grub_efi_dhcp4_config_data { ++ grub_efi_uint32_t discover_try_count; ++ grub_efi_uint32_t *discover_timeout; ++ grub_efi_uint32_t request_try_count; ++ grub_efi_uint32_t *request_timeout; ++ grub_efi_ipv4_address_t client_address; ++ grub_efi_status_t (*dhcp4_callback) ( ++ grub_efi_dhcp4_protocol_t *this, ++ void *context, ++ grub_efi_dhcp4_state_t current_state, ++ grub_efi_dhcp4_event_t dhcp4_event, ++ grub_efi_dhcp4_packet_t *packet, ++ grub_efi_dhcp4_packet_t **new_packet ++ ); ++ void *callback_context; ++ grub_efi_uint32_t option_count; ++ grub_efi_dhcp4_packet_option_t **option_list; ++}; ++ ++typedef struct grub_efi_dhcp4_config_data grub_efi_dhcp4_config_data_t; ++ ++struct grub_efi_dhcp4_mode_data { ++ grub_efi_dhcp4_state_t state; ++ grub_efi_dhcp4_config_data_t config_data; ++ grub_efi_ipv4_address_t client_address; ++ grub_efi_mac_address_t client_mac_address; ++ grub_efi_ipv4_address_t server_address; ++ grub_efi_ipv4_address_t router_address; ++ grub_efi_ipv4_address_t subnet_mask; ++ grub_efi_uint32_t lease_time; ++ grub_efi_dhcp4_packet_t *reply_packet; ++}; ++ ++typedef struct grub_efi_dhcp4_mode_data grub_efi_dhcp4_mode_data_t; ++ ++struct grub_efi_dhcp4_protocol { ++ grub_efi_status_t (*get_mode_data) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_dhcp4_mode_data_t *dhcp4_mode_data); ++ grub_efi_status_t (*configure) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_dhcp4_config_data_t *dhcp4_cfg_data); ++ grub_efi_status_t (*start) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_event_t completion_event); ++ grub_efi_status_t (*renew_rebind) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_boolean_t rebind_request, ++ grub_efi_event_t completion_event); ++ grub_efi_status_t (*release) (grub_efi_dhcp4_protocol_t *this); ++ grub_efi_status_t (*stop) (grub_efi_dhcp4_protocol_t *this); ++ grub_efi_status_t (*build) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_dhcp4_packet_t *seed_packet, ++ grub_efi_uint32_t delete_count, ++ grub_efi_uint8_t *delete_list, ++ grub_efi_uint32_t append_count, ++ grub_efi_dhcp4_packet_option_t *append_list[], ++ grub_efi_dhcp4_packet_t **new_packet); ++ grub_efi_status_t (*transmit_receive) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_dhcp4_transmit_receive_token_t *token); ++ grub_efi_status_t (*parse) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_dhcp4_packet_t *packet, ++ grub_efi_uint32_t *option_count, ++ grub_efi_dhcp4_packet_option_t *packet_option_list[]); ++}; ++ ++typedef struct grub_efi_dhcp6_protocol grub_efi_dhcp6_protocol_t; ++ ++struct grub_efi_dhcp6_retransmission { ++ grub_efi_uint32_t irt; ++ grub_efi_uint32_t mrc; ++ grub_efi_uint32_t mrt; ++ grub_efi_uint32_t mrd; ++}; ++ ++typedef struct grub_efi_dhcp6_retransmission grub_efi_dhcp6_retransmission_t; ++ ++enum grub_efi_dhcp6_event { ++ GRUB_EFI_DHCP6_SEND_SOLICIT, ++ GRUB_EFI_DHCP6_RCVD_ADVERTISE, ++ GRUB_EFI_DHCP6_SELECT_ADVERTISE, ++ GRUB_EFI_DHCP6_SEND_REQUEST, ++ GRUB_EFI_DHCP6_RCVD_REPLY, ++ GRUB_EFI_DHCP6_RCVD_RECONFIGURE, ++ GRUB_EFI_DHCP6_SEND_DECLINE, ++ GRUB_EFI_DHCP6_SEND_CONFIRM, ++ GRUB_EFI_DHCP6_SEND_RELEASE, ++ GRUB_EFI_DHCP6_SEND_RENEW, ++ GRUB_EFI_DHCP6_SEND_REBIND ++}; ++ ++typedef enum grub_efi_dhcp6_event grub_efi_dhcp6_event_t; ++ ++struct grub_efi_dhcp6_packet_option { ++ grub_efi_uint16_t op_code; ++ grub_efi_uint16_t op_len; ++ grub_efi_uint8_t data[1]; ++} GRUB_PACKED; ++ ++typedef struct grub_efi_dhcp6_packet_option grub_efi_dhcp6_packet_option_t; ++ ++struct grub_efi_dhcp6_header { ++ grub_efi_uint32_t transaction_id:24; ++ grub_efi_uint32_t message_type:8; ++} GRUB_PACKED; ++ ++typedef struct grub_efi_dhcp6_header grub_efi_dhcp6_header_t; ++ ++struct grub_efi_dhcp6_packet { ++ grub_efi_uint32_t size; ++ grub_efi_uint32_t length; ++ struct { ++ grub_efi_dhcp6_header_t header; ++ grub_efi_uint8_t option[1]; ++ } dhcp6; ++} GRUB_PACKED; ++ ++typedef struct grub_efi_dhcp6_packet grub_efi_dhcp6_packet_t; ++ ++struct grub_efi_dhcp6_ia_address { ++ grub_efi_ipv6_address_t ip_address; ++ grub_efi_uint32_t preferred_lifetime; ++ grub_efi_uint32_t valid_lifetime; ++}; ++ ++typedef struct grub_efi_dhcp6_ia_address grub_efi_dhcp6_ia_address_t; ++ ++enum grub_efi_dhcp6_state { ++ GRUB_EFI_DHCP6_INIT, ++ GRUB_EFI_DHCP6_SELECTING, ++ GRUB_EFI_DHCP6_REQUESTING, ++ GRUB_EFI_DHCP6_DECLINING, ++ GRUB_EFI_DHCP6_CONFIRMING, ++ GRUB_EFI_DHCP6_RELEASING, ++ GRUB_EFI_DHCP6_BOUND, ++ GRUB_EFI_DHCP6_RENEWING, ++ GRUB_EFI_DHCP6_REBINDING ++}; ++ ++typedef enum grub_efi_dhcp6_state grub_efi_dhcp6_state_t; ++ ++#define GRUB_EFI_DHCP6_IA_TYPE_NA 3 ++#define GRUB_EFI_DHCP6_IA_TYPE_TA 4 ++ ++struct grub_efi_dhcp6_ia_descriptor { ++ grub_efi_uint16_t type; ++ grub_efi_uint32_t ia_id; ++}; ++ ++typedef struct grub_efi_dhcp6_ia_descriptor grub_efi_dhcp6_ia_descriptor_t; ++ ++struct grub_efi_dhcp6_ia { ++ grub_efi_dhcp6_ia_descriptor_t descriptor; ++ grub_efi_dhcp6_state_t state; ++ grub_efi_dhcp6_packet_t *reply_packet; ++ grub_efi_uint32_t ia_address_count; ++ grub_efi_dhcp6_ia_address_t ia_address[1]; ++}; ++ ++typedef struct grub_efi_dhcp6_ia grub_efi_dhcp6_ia_t; ++ ++struct grub_efi_dhcp6_duid { ++ grub_efi_uint16_t length; ++ grub_efi_uint8_t duid[1]; ++}; ++ ++typedef struct grub_efi_dhcp6_duid grub_efi_dhcp6_duid_t; ++ ++struct grub_efi_dhcp6_mode_data { ++ grub_efi_dhcp6_duid_t *client_id; ++ grub_efi_dhcp6_ia_t *ia; ++}; ++ ++typedef struct grub_efi_dhcp6_mode_data grub_efi_dhcp6_mode_data_t; ++ ++struct grub_efi_dhcp6_config_data { ++ grub_efi_status_t (*dhcp6_callback) (grub_efi_dhcp6_protocol_t this, ++ void *context, ++ grub_efi_dhcp6_state_t current_state, ++ grub_efi_dhcp6_event_t dhcp6_event, ++ grub_efi_dhcp6_packet_t *packet, ++ grub_efi_dhcp6_packet_t **new_packet); ++ void *callback_context; ++ grub_efi_uint32_t option_count; ++ grub_efi_dhcp6_packet_option_t **option_list; ++ grub_efi_dhcp6_ia_descriptor_t ia_descriptor; ++ grub_efi_event_t ia_info_event; ++ grub_efi_boolean_t reconfigure_accept; ++ grub_efi_boolean_t rapid_commit; ++ grub_efi_dhcp6_retransmission_t *solicit_retransmission; ++}; ++ ++typedef struct grub_efi_dhcp6_config_data grub_efi_dhcp6_config_data_t; ++ ++struct grub_efi_dhcp6_protocol { ++ grub_efi_status_t (*get_mode_data) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_dhcp6_mode_data_t *dhcp6_mode_data, ++ grub_efi_dhcp6_config_data_t *dhcp6_config_data); ++ grub_efi_status_t (*configure) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_dhcp6_config_data_t *dhcp6_cfg_data); ++ grub_efi_status_t (*start) (grub_efi_dhcp6_protocol_t *this); ++ grub_efi_status_t (*info_request) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_boolean_t send_client_id, ++ grub_efi_dhcp6_packet_option_t *option_request, ++ grub_efi_uint32_t option_count, ++ grub_efi_dhcp6_packet_option_t *option_list[], ++ grub_efi_dhcp6_retransmission_t *retransmission, ++ grub_efi_event_t timeout_event, ++ grub_efi_status_t (*reply_callback) (grub_efi_dhcp6_protocol_t *this, ++ void *context, ++ grub_efi_dhcp6_packet_t *packet), ++ void *callback_context); ++ grub_efi_status_t (*renew_rebind) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_boolean_t rebind_request); ++ grub_efi_status_t (*decline) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_uint32_t address_count, ++ grub_efi_ipv6_address_t *addresses); ++ grub_efi_status_t (*release) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_uint32_t address_count, ++ grub_efi_ipv6_address_t *addresses); ++ grub_efi_status_t (*stop) (grub_efi_dhcp6_protocol_t *this); ++ grub_efi_status_t (*parse) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_dhcp6_packet_t *packet, ++ grub_efi_uint32_t *option_count, ++ grub_efi_dhcp6_packet_option_t *packet_option_list[]); ++}; ++ ++#endif /* ! GRUB_EFI_DHCP_HEADER */ +Index: grub-2.06/include/grub/efi/http.h +=================================================================== +--- /dev/null ++++ grub-2.06/include/grub/efi/http.h +@@ -0,0 +1,215 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2006,2007,2008 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 . ++ */ ++ ++#ifndef GRUB_EFI_HTTP_HEADER ++#define GRUB_EFI_HTTP_HEADER 1 ++ ++#include ++#include ++#include ++ ++#define GRUB_EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID \ ++ { 0xbdc8e6af, 0xd9bc, 0x4379, \ ++ { 0xa7, 0x2a, 0xe0, 0xc4, 0xe7, 0x5d, 0xae, 0x1c } \ ++ } ++ ++#define GRUB_EFI_HTTP_PROTOCOL_GUID \ ++ { 0x7A59B29B, 0x910B, 0x4171, \ ++ { 0x82, 0x42, 0xA8, 0x5A, 0x0D, 0xF2, 0x5B, 0x5B } \ ++ } ++ ++#define EFIHTTP_WAIT_TIME 10000 // 10000ms = 10s ++#define EFIHTTP_RX_BUF_LEN 10240 ++ ++//****************************************** ++// Protocol Interface Structure ++//****************************************** ++struct grub_efi_http; ++ ++//****************************************** ++// EFI_HTTP_VERSION ++//****************************************** ++typedef enum { ++ GRUB_EFI_HTTPVERSION10, ++ GRUB_EFI_HTTPVERSION11, ++ GRUB_EFI_HTTPVERSIONUNSUPPORTED ++} grub_efi_http_version_t; ++ ++//****************************************** ++// EFI_HTTPv4_ACCESS_POINT ++//****************************************** ++typedef struct { ++ grub_efi_boolean_t use_default_address; ++ grub_efi_ipv4_address_t local_address; ++ grub_efi_ipv4_address_t local_subnet; ++ grub_efi_uint16_t local_port; ++} grub_efi_httpv4_access_point_t; ++ ++//****************************************** ++// EFI_HTTPv6_ACCESS_POINT ++//****************************************** ++typedef struct { ++ grub_efi_ipv6_address_t local_address; ++ grub_efi_uint16_t local_port; ++} grub_efi_httpv6_access_point_t; ++ ++//****************************************** ++// EFI_HTTP_CONFIG_DATA ++//****************************************** ++typedef struct { ++ grub_efi_http_version_t http_version; ++ grub_efi_uint32_t timeout_millisec; ++ grub_efi_boolean_t local_address_is_ipv6; ++ union { ++ grub_efi_httpv4_access_point_t *ipv4_node; ++ grub_efi_httpv6_access_point_t *ipv6_node; ++ } access_point; ++} grub_efi_http_config_data_t; ++ ++//****************************************** ++// EFI_HTTP_METHOD ++//****************************************** ++typedef enum { ++ GRUB_EFI_HTTPMETHODGET, ++ GRUB_EFI_HTTPMETHODPOST, ++ GRUB_EFI_HTTPMETHODPATCH, ++ GRUB_EFI_HTTPMETHODOPTIONS, ++ GRUB_EFI_HTTPMETHODCONNECT, ++ GRUB_EFI_HTTPMETHODHEAD, ++ GRUB_EFI_HTTPMETHODPUT, ++ GRUB_EFI_HTTPMETHODDELETE, ++ GRUB_EFI_HTTPMETHODTRACE, ++} grub_efi_http_method_t; ++ ++//****************************************** ++// EFI_HTTP_REQUEST_DATA ++//****************************************** ++typedef struct { ++ grub_efi_http_method_t method; ++ grub_efi_char16_t *url; ++} grub_efi_http_request_data_t; ++ ++typedef enum { ++ GRUB_EFI_HTTP_STATUS_UNSUPPORTED_STATUS = 0, ++ GRUB_EFI_HTTP_STATUS_100_CONTINUE, ++ GRUB_EFI_HTTP_STATUS_101_SWITCHING_PROTOCOLS, ++ GRUB_EFI_HTTP_STATUS_200_OK, ++ GRUB_EFI_HTTP_STATUS_201_CREATED, ++ GRUB_EFI_HTTP_STATUS_202_ACCEPTED, ++ GRUB_EFI_HTTP_STATUS_203_NON_AUTHORITATIVE_INFORMATION, ++ GRUB_EFI_HTTP_STATUS_204_NO_CONTENT, ++ GRUB_EFI_HTTP_STATUS_205_RESET_CONTENT, ++ GRUB_EFI_HTTP_STATUS_206_PARTIAL_CONTENT, ++ GRUB_EFI_HTTP_STATUS_300_MULTIPLE_CHIOCES, ++ GRUB_EFI_HTTP_STATUS_301_MOVED_PERMANENTLY, ++ GRUB_EFI_HTTP_STATUS_302_FOUND, ++ GRUB_EFI_HTTP_STATUS_303_SEE_OTHER, ++ GRUB_EFI_HTTP_STATUS_304_NOT_MODIFIED, ++ GRUB_EFI_HTTP_STATUS_305_USE_PROXY, ++ GRUB_EFI_HTTP_STATUS_307_TEMPORARY_REDIRECT, ++ GRUB_EFI_HTTP_STATUS_400_BAD_REQUEST, ++ GRUB_EFI_HTTP_STATUS_401_UNAUTHORIZED, ++ GRUB_EFI_HTTP_STATUS_402_PAYMENT_REQUIRED, ++ GRUB_EFI_HTTP_STATUS_403_FORBIDDEN, ++ GRUB_EFI_HTTP_STATUS_404_NOT_FOUND, ++ GRUB_EFI_HTTP_STATUS_405_METHOD_NOT_ALLOWED, ++ GRUB_EFI_HTTP_STATUS_406_NOT_ACCEPTABLE, ++ GRUB_EFI_HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED, ++ GRUB_EFI_HTTP_STATUS_408_REQUEST_TIME_OUT, ++ GRUB_EFI_HTTP_STATUS_409_CONFLICT, ++ GRUB_EFI_HTTP_STATUS_410_GONE, ++ GRUB_EFI_HTTP_STATUS_411_LENGTH_REQUIRED, ++ GRUB_EFI_HTTP_STATUS_412_PRECONDITION_FAILED, ++ GRUB_EFI_HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE, ++ GRUB_EFI_HTTP_STATUS_414_REQUEST_URI_TOO_LARGE, ++ GRUB_EFI_HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE, ++ GRUB_EFI_HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED, ++ GRUB_EFI_HTTP_STATUS_417_EXPECTATION_FAILED, ++ GRUB_EFI_HTTP_STATUS_500_INTERNAL_SERVER_ERROR, ++ GRUB_EFI_HTTP_STATUS_501_NOT_IMPLEMENTED, ++ GRUB_EFI_HTTP_STATUS_502_BAD_GATEWAY, ++ GRUB_EFI_HTTP_STATUS_503_SERVICE_UNAVAILABLE, ++ GRUB_EFI_HTTP_STATUS_504_GATEWAY_TIME_OUT, ++ GRUB_EFI_HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED ++} grub_efi_http_status_code_t; ++ ++//****************************************** ++// EFI_HTTP_RESPONSE_DATA ++//****************************************** ++typedef struct { ++ grub_efi_http_status_code_t status_code; ++} grub_efi_http_response_data_t; ++ ++//****************************************** ++// EFI_HTTP_HEADER ++//****************************************** ++typedef struct { ++ grub_efi_char8_t *field_name; ++ grub_efi_char8_t *field_value; ++} grub_efi_http_header_t; ++ ++//****************************************** ++// EFI_HTTP_MESSAGE ++//****************************************** ++typedef struct { ++ union { ++ grub_efi_http_request_data_t *request; ++ grub_efi_http_response_data_t *response; ++ } data; ++ grub_efi_uint32_t header_count; ++ grub_efi_http_header_t *headers; ++ grub_efi_uint32_t body_length; ++ void *body; ++} grub_efi_http_message_t; ++ ++//****************************************** ++// EFI_HTTP_TOKEN ++//****************************************** ++typedef struct { ++ grub_efi_event_t event; ++ grub_efi_status_t status; ++ grub_efi_http_message_t *message; ++} grub_efi_http_token_t; ++ ++struct grub_efi_http { ++ grub_efi_status_t ++ (*get_mode_data) (struct grub_efi_http *this, ++ grub_efi_http_config_data_t *http_config_data); ++ ++ grub_efi_status_t ++ (*configure) (struct grub_efi_http *this, ++ grub_efi_http_config_data_t *http_config_data); ++ ++ grub_efi_status_t ++ (*request) (struct grub_efi_http *this, ++ grub_efi_http_token_t *token); ++ ++ grub_efi_status_t ++ (*cancel) (struct grub_efi_http *this, ++ grub_efi_http_token_t *token); ++ ++ grub_efi_status_t ++ (*response) (struct grub_efi_http *this, ++ grub_efi_http_token_t *token); ++ ++ grub_efi_status_t ++ (*poll) (struct grub_efi_http *this); ++}; ++typedef struct grub_efi_http grub_efi_http_t; ++ ++#endif /* !GRUB_EFI_HTTP_HEADER */ +Index: grub-2.06/include/grub/net/efi.h +=================================================================== +--- /dev/null ++++ grub-2.06/include/grub/net/efi.h +@@ -0,0 +1,144 @@ ++#ifndef GRUB_NET_EFI_HEADER ++#define GRUB_NET_EFI_HEADER 1 ++ ++#include ++#include ++#include ++#include ++ ++typedef struct grub_efi_net_interface grub_efi_net_interface_t; ++typedef struct grub_efi_net_ip_config grub_efi_net_ip_config_t; ++typedef union grub_efi_net_ip_address grub_efi_net_ip_address_t; ++typedef struct grub_efi_net_ip_manual_address grub_efi_net_ip_manual_address_t; ++ ++struct grub_efi_net_interface ++{ ++ char *name; ++ int prefer_ip6; ++ struct grub_efi_net_device *dev; ++ struct grub_efi_net_io *io; ++ grub_efi_net_ip_config_t *ip_config; ++ int io_type; ++ struct grub_efi_net_interface *next; ++}; ++ ++#define efi_net_interface_get_hw_address(inf) inf->ip_config->get_hw_address (inf->dev) ++#define efi_net_interface_get_address(inf) inf->ip_config->get_address (inf->dev) ++#define efi_net_interface_get_route_table(inf) inf->ip_config->get_route_table (inf->dev) ++#define efi_net_interface_set_address(inf, addr, with_subnet) inf->ip_config->set_address (inf->dev, addr, with_subnet) ++#define efi_net_interface_set_gateway(inf, addr) inf->ip_config->set_gateway (inf->dev, addr) ++#define efi_net_interface_set_dns(inf, addr) inf->ip_config->set_dns (inf->dev, addr) ++ ++struct grub_efi_net_ip_config ++{ ++ char * (*get_hw_address) (struct grub_efi_net_device *dev); ++ char * (*get_address) (struct grub_efi_net_device *dev); ++ char ** (*get_route_table) (struct grub_efi_net_device *dev); ++ grub_efi_net_interface_t * (*best_interface) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *address); ++ int (*set_address) (struct grub_efi_net_device *dev, grub_efi_net_ip_manual_address_t *net_ip, int with_subnet); ++ int (*set_gateway) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *address); ++ int (*set_dns) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *dns); ++}; ++ ++union grub_efi_net_ip_address ++{ ++ grub_efi_ipv4_address_t ip4; ++ grub_efi_ipv6_address_t ip6; ++}; ++ ++struct grub_efi_net_ip_manual_address ++{ ++ int is_ip6; ++ union ++ { ++ grub_efi_ip4_config2_manual_address_t ip4; ++ grub_efi_ip6_config_manual_address_t ip6; ++ }; ++}; ++ ++struct grub_efi_net_device ++{ ++ grub_efi_handle_t handle; ++ grub_efi_ip4_config2_protocol_t *ip4_config; ++ grub_efi_ip6_config_protocol_t *ip6_config; ++ grub_efi_handle_t http_handle; ++ grub_efi_http_t *http; ++ grub_efi_handle_t ip4_pxe_handle; ++ grub_efi_pxe_t *ip4_pxe; ++ grub_efi_handle_t ip6_pxe_handle; ++ grub_efi_pxe_t *ip6_pxe; ++ grub_efi_handle_t dhcp4_handle; ++ grub_efi_dhcp4_protocol_t *dhcp4; ++ grub_efi_handle_t dhcp6_handle; ++ grub_efi_dhcp6_protocol_t *dhcp6; ++ char *card_name; ++ grub_efi_net_interface_t *net_interfaces; ++ struct grub_efi_net_device *next; ++}; ++ ++struct grub_efi_net_io ++{ ++ void (*configure) (struct grub_efi_net_device *dev, int prefer_ip6); ++ grub_err_t (*open) (struct grub_efi_net_device *dev, ++ int prefer_ip6, ++ grub_file_t file, ++ const char *filename, ++ int type); ++ grub_ssize_t (*read) (struct grub_efi_net_device *dev, ++ int prefer_ip6, ++ grub_file_t file, ++ char *buf, ++ grub_size_t len); ++ grub_err_t (*close) (struct grub_efi_net_device *dev, ++ int prefer_ip6, ++ grub_file_t file); ++}; ++ ++extern struct grub_efi_net_device *net_devices; ++ ++extern struct grub_efi_net_io io_http; ++extern struct grub_efi_net_io io_pxe; ++ ++extern grub_efi_net_ip_config_t *efi_net_ip4_config; ++extern grub_efi_net_ip_config_t *efi_net_ip6_config; ++ ++char * ++grub_efi_ip4_address_to_string (grub_efi_ipv4_address_t *address); ++ ++char * ++grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address); ++ ++char * ++grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address); ++ ++int ++grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest); ++ ++int ++grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *address, const char **rest); ++ ++char * ++grub_efi_ip6_interface_name (struct grub_efi_net_device *dev); ++ ++char * ++grub_efi_ip4_interface_name (struct grub_efi_net_device *dev); ++ ++grub_efi_net_interface_t * ++grub_efi_net_create_interface (struct grub_efi_net_device *dev, ++ const char *interface_name, ++ grub_efi_net_ip_manual_address_t *net_ip, ++ int has_subnet); ++ ++int grub_efi_net_fs_init (void); ++void grub_efi_net_fs_fini (void); ++int grub_efi_net_boot_from_https (void); ++int grub_efi_net_boot_from_opa (void); ++ ++extern grub_command_func_t grub_efi_net_list_routes; ++extern grub_command_func_t grub_efi_net_list_cards; ++extern grub_command_func_t grub_efi_net_list_addrs; ++extern grub_command_func_t grub_efi_net_add_addr; ++extern grub_command_func_t grub_efi_net_bootp; ++extern grub_command_func_t grub_efi_net_bootp6; ++ ++#endif /* ! GRUB_NET_EFI_HEADER */ diff --git a/0001-arm64-Fix-EFI-loader-kernel-image-allocation.patch b/0001-arm64-Fix-EFI-loader-kernel-image-allocation.patch new file mode 100644 index 0000000..81ea274 --- /dev/null +++ b/0001-arm64-Fix-EFI-loader-kernel-image-allocation.patch @@ -0,0 +1,179 @@ +From 10d0f70ac194931c63f2cbd6fdebd6697abae992 Mon Sep 17 00:00:00 2001 +From: Benjamin Herrenschmidt +Date: Mon, 2 Aug 2021 23:10:01 +1000 +Subject: [PATCH 1/2] arm64: Fix EFI loader kernel image allocation + +We are currently allocating just enough memory for the file size, +which means that the kernel BSS is in limbo (and not even zeroed). + +We are also not honoring the alignment specified in the image +PE header. + +This makes us use the PE optional header in which the kernel puts the +actual size it needs, including BSS, and make sure we clear it, and +honors the specified alignment for the image. + +Signed-off-by: Benjamin Herrenschmidt +--- + grub-core/loader/arm64/efi/linux.c | 92 ++++++++++++++++++++---------- + 1 file changed, 63 insertions(+), 29 deletions(-) + +diff --git a/grub-core/loader/arm64/efi/linux.c b/grub-core/loader/arm64/efi/linux.c +index b73105347..4da49a182 100644 +--- a/grub-core/loader/arm64/efi/linux.c ++++ b/grub-core/loader/arm64/efi/linux.c +@@ -39,6 +39,8 @@ GRUB_MOD_LICENSE ("GPLv3+"); + static grub_dl_t my_mod; + static int loaded; + ++static void *kernel_alloc_addr; ++static grub_uint32_t kernel_alloc_pages; + static void *kernel_addr; + static grub_uint64_t kernel_size; + static grub_uint32_t handover_offset; +@@ -258,9 +260,8 @@ grub_linux_unload (void) + GRUB_EFI_BYTES_TO_PAGES (initrd_end - initrd_start)); + initrd_start = initrd_end = 0; + grub_free (linux_args); +- if (kernel_addr) +- grub_efi_free_pages ((grub_addr_t) kernel_addr, +- GRUB_EFI_BYTES_TO_PAGES (kernel_size)); ++ if (kernel_alloc_addr) ++ grub_efi_free_pages ((grub_addr_t) kernel_alloc_addr, kernel_alloc_pages); + grub_fdt_unload (); + return GRUB_ERR_NONE; + } +@@ -365,14 +366,35 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + return grub_errno; + } + ++static grub_err_t ++parse_pe_header (void *kernel, grub_uint64_t *total_size, ++ grub_uint32_t *entry_offset, ++ grub_uint32_t *alignment) ++{ ++ struct linux_arch_kernel_header *lh = kernel; ++ struct grub_armxx_linux_pe_header *pe; ++ ++ pe = (void *)((unsigned long)kernel + lh->hdr_offset); ++ ++ if (pe->opt.magic != GRUB_PE32_PE64_MAGIC) ++ return grub_error(GRUB_ERR_BAD_OS, "Invalid PE optional header magic"); ++ ++ *total_size = pe->opt.image_size; ++ *entry_offset = pe->opt.entry_addr; ++ *alignment = pe->opt.section_alignment; ++ ++ return GRUB_ERR_NONE; ++} ++ + static grub_err_t + grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) + { + grub_file_t file = 0; +- struct linux_arch_kernel_header lh; +- struct grub_armxx_linux_pe_header *pe; + grub_err_t err; ++ grub_off_t filelen; ++ grub_uint32_t align = 0; ++ void *kernel = NULL; + + grub_dl_ref (my_mod); + +@@ -386,39 +408,49 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + if (!file) + goto fail; + +- kernel_size = grub_file_size (file); ++ filelen = grub_file_size (file); ++ kernel = grub_malloc(filelen); ++ if (!kernel) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel load buffer")); ++ goto fail; ++ } + +- if (grub_file_read (file, &lh, sizeof (lh)) < (long) sizeof (lh)) +- return grub_errno; ++ if (grub_file_read (file, kernel, filelen) < (grub_ssize_t)filelen) ++ { ++ grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), ++ argv[0]); ++ goto fail; ++ } + +- if (grub_arch_efi_linux_check_image (&lh) != GRUB_ERR_NONE) ++ grub_dprintf ("linux", "kernel @ %p\n", kernel_addr); ++ ++ if (grub_arch_efi_linux_check_image (kernel) != GRUB_ERR_NONE) ++ goto fail; ++ if (parse_pe_header (kernel, &kernel_size, &handover_offset, &align) != GRUB_ERR_NONE) + goto fail; ++ grub_dprintf ("linux", "kernel mem size : %lld\n", (long long) kernel_size); ++ grub_dprintf ("linux", "kernel entry offset : %d\n", handover_offset); ++ grub_dprintf ("linux", "kernel alignment : 0x%x\n", align); + + grub_loader_unset(); + +- grub_dprintf ("linux", "kernel file size: %lld\n", (long long) kernel_size); +- kernel_addr = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (kernel_size)); +- grub_dprintf ("linux", "kernel numpages: %lld\n", +- (long long) GRUB_EFI_BYTES_TO_PAGES (kernel_size)); +- if (!kernel_addr) ++ kernel_alloc_pages = GRUB_EFI_BYTES_TO_PAGES (kernel_size + align - 1); ++ kernel_alloc_addr = grub_efi_allocate_any_pages (kernel_alloc_pages); ++ grub_dprintf ("linux", "kernel numpages: %d\n", kernel_alloc_pages); ++ if (!kernel_alloc_addr) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + goto fail; + } +- +- grub_file_seek (file, 0); +- if (grub_file_read (file, kernel_addr, kernel_size) +- < (grub_int64_t) kernel_size) +- { +- if (!grub_errno) +- grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), argv[0]); +- goto fail; +- } ++ kernel_addr = (void *)ALIGN_UP((grub_uint64_t)kernel_alloc_addr, align); + + grub_dprintf ("linux", "kernel @ %p\n", kernel_addr); +- +- pe = (void *)((unsigned long)kernel_addr + lh.hdr_offset); +- handover_offset = pe->opt.entry_addr; ++ grub_memcpy (kernel_addr, kernel, grub_min(filelen, kernel_size)); ++ if (kernel_size > filelen) ++ grub_memset ((char *)kernel_addr + filelen, 0, kernel_size - filelen); ++ grub_free(kernel); ++ kernel = NULL; + + cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE); + linux_args = grub_malloc (cmdline_size); +@@ -442,6 +474,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + + fail: ++ if (kernel) ++ grub_free (kernel); ++ + if (file) + grub_file_close (file); + +@@ -454,9 +489,8 @@ fail: + if (linux_args && !loaded) + grub_free (linux_args); + +- if (kernel_addr && !loaded) +- grub_efi_free_pages ((grub_addr_t) kernel_addr, +- GRUB_EFI_BYTES_TO_PAGES (kernel_size)); ++ if (kernel_alloc_addr && !loaded) ++ grub_efi_free_pages ((grub_addr_t) kernel_alloc_addr, kernel_alloc_pages); + + return grub_errno; + } +-- +2.31.1 + diff --git a/0001-commands-efi-tpm-Refine-the-status-of-log-event.patch b/0001-commands-efi-tpm-Refine-the-status-of-log-event.patch new file mode 100644 index 0000000..7a7d1ce --- /dev/null +++ b/0001-commands-efi-tpm-Refine-the-status-of-log-event.patch @@ -0,0 +1,39 @@ +From f82968ededa4ae89a6cec174aec7a3df6d044747 Mon Sep 17 00:00:00 2001 +From: Lu Ken +Date: Wed, 13 Jul 2022 10:06:10 +0800 +Subject: [PATCH 1/3] commands/efi/tpm: Refine the status of log event + +1. Use macro GRUB_ERR_NONE instead of hard code 0. +2. Keep lowercase of the first char for the status string of log event. + +Signed-off-by: Lu Ken +Reviewed-by: Daniel Kiper +--- + grub-core/commands/efi/tpm.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c +index 1e399a964..e6953e3f5 100644 +--- a/grub-core/commands/efi/tpm.c ++++ b/grub-core/commands/efi/tpm.c +@@ -135,13 +135,13 @@ grub_efi_log_event_status (grub_efi_status_t status) + switch (status) + { + case GRUB_EFI_SUCCESS: +- return 0; ++ return GRUB_ERR_NONE; + case GRUB_EFI_DEVICE_ERROR: +- return grub_error (GRUB_ERR_IO, N_("Command failed")); ++ return grub_error (GRUB_ERR_IO, N_("command failed")); + case GRUB_EFI_INVALID_PARAMETER: +- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter")); ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid parameter")); + case GRUB_EFI_BUFFER_TOO_SMALL: +- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small")); ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("output buffer too small")); + case GRUB_EFI_NOT_FOUND: + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable")); + default: +-- +2.35.3 + diff --git a/0001-crytodisk-fix-cryptodisk-module-looking-up.patch b/0001-crytodisk-fix-cryptodisk-module-looking-up.patch new file mode 100644 index 0000000..17fca17 --- /dev/null +++ b/0001-crytodisk-fix-cryptodisk-module-looking-up.patch @@ -0,0 +1,33 @@ +From 822f71318a69c150da3ad7df5fe8667dfa6e8069 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Thu, 31 Mar 2022 15:45:35 +0800 +Subject: [PATCH] crytodisk: fix cryptodisk module looking up + +The error "no cryptodisk module can handle this device" may happen even +encrypted disk were correctly formatted and required modules were loaded. + +It is casued by missing break to the loop in which cryptodisk modules are +iterated to find the one matching target's disk format. With the break +statement, the loop will be always ended with testing last cryptodisk module on +the list that may not be able to handle the format of encrypted disk's. + +Signed-off-by: Michael Chang +--- + grub-core/disk/cryptodisk.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 00c44773fb..6d22bf871c 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -1021,6 +1021,7 @@ grub_cryptodisk_scan_device_real (const char *name, + if (!dev) + continue; + crd = cr; ++ break; + } + + if (!dev) +-- +2.34.1 + diff --git a/0001-devmapper-getroot-Have-devmapper-recognize-LUKS2.patch b/0001-devmapper-getroot-Have-devmapper-recognize-LUKS2.patch new file mode 100644 index 0000000..ffc2696 --- /dev/null +++ b/0001-devmapper-getroot-Have-devmapper-recognize-LUKS2.patch @@ -0,0 +1,53 @@ +From ebe4ac49e800b18b539564169593ab1c6f163378 Mon Sep 17 00:00:00 2001 +From: Josselin Poiret via Grub-devel +Date: Tue, 14 Jun 2022 15:47:29 +0200 +Subject: [PATCH 01/10] devmapper/getroot: Have devmapper recognize LUKS2 + +Changes UUID comparisons so that LUKS1 and LUKS2 are both recognized +as being LUKS cryptodisks. +--- + grub-core/osdep/devmapper/getroot.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/grub-core/osdep/devmapper/getroot.c b/grub-core/osdep/devmapper/getroot.c +index 9ba5c98655..2bf4264cf0 100644 +--- a/grub-core/osdep/devmapper/getroot.c ++++ b/grub-core/osdep/devmapper/getroot.c +@@ -138,7 +138,8 @@ grub_util_get_dm_abstraction (const char *os_dev) + grub_free (uuid); + return GRUB_DEV_ABSTRACTION_LVM; + } +- if (strncmp (uuid, "CRYPT-LUKS1-", 12) == 0) ++ if (strncmp (uuid, "CRYPT-LUKS1-", sizeof ("CRYPT-LUKS1-") - 1) == 0 ++ || strncmp (uuid, "CRYPT-LUKS2-", sizeof ("CRYPT-LUKS2-") - 1) == 0) + { + grub_free (uuid); + return GRUB_DEV_ABSTRACTION_LUKS; +@@ -179,7 +180,9 @@ grub_util_pull_devmapper (const char *os_dev) + grub_util_pull_device (subdev); + } + } +- if (uuid && strncmp (uuid, "CRYPT-LUKS1-", sizeof ("CRYPT-LUKS1-") - 1) == 0 ++ if (uuid ++ && (strncmp (uuid, "CRYPT-LUKS1-", sizeof ("CRYPT-LUKS1-") - 1) == 0 ++ || strncmp (uuid, "CRYPT-LUKS2-", sizeof ("CRYPT-LUKS2-") - 1) == 0) + && lastsubdev) + { + char *grdev = grub_util_get_grub_dev (lastsubdev); +@@ -253,11 +256,11 @@ grub_util_get_devmapper_grub_dev (const char *os_dev) + { + char *dash; + +- dash = grub_strchr (uuid + sizeof ("CRYPT-LUKS1-") - 1, '-'); ++ dash = grub_strchr (uuid + sizeof ("CRYPT-LUKS*-") - 1, '-'); + if (dash) + *dash = 0; + grub_dev = grub_xasprintf ("cryptouuid/%s", +- uuid + sizeof ("CRYPT-LUKS1-") - 1); ++ uuid + sizeof ("CRYPT-LUKS*-") - 1); + grub_free (uuid); + return grub_dev; + } +-- +2.34.1 + diff --git a/0001-disk-diskfilter-Use-nodes-in-logical-volume-s-segmen.patch b/0001-disk-diskfilter-Use-nodes-in-logical-volume-s-segmen.patch new file mode 100644 index 0000000..5e1ca65 --- /dev/null +++ b/0001-disk-diskfilter-Use-nodes-in-logical-volume-s-segmen.patch @@ -0,0 +1,180 @@ +From 5cc00eac24c7019d9696a859f69b587e11f1621e Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Mon, 27 Sep 2021 17:39:56 +0800 +Subject: [PATCH] disk/diskfilter: Use nodes in logical volume's segment as + member device + +Currently the grub_diskfilter_memberlist() function returns all physical +volumes added to a volume group to which a logical volume (LV) belongs. +However, this is suboptimal as it doesn't fit the intended behavior of +returning underlying devices that make up the LV. To give a clear +picture, the result should be identical to running commands below to +display the logical volumes with underlying physical volumes in use. + + localhost:~ # lvs -o lv_name,vg_name,devices /dev/system/root + LV VG Devices + root system /dev/vda2(512) + + localhost:~ # lvdisplay --maps /dev/system/root + --- Logical volume --- + ... + --- Segments --- + Logical extents 0 to 4604: + Type linear + Physical volume /dev/vda2 + Physical extents 512 to 5116 + +As shown above, we can know system-root LV uses only /dev/vda2 to +allocate it's extents, or we can say that /dev/vda2 is the member device +comprising the system-root LV. + +It is important to be precise on the member devices, because that helps +to avoid pulling in excessive dependency. Let's use an example to +demonstrate why it is needed. + + localhost:~ # findmnt / + TARGET SOURCE FSTYPE OPTIONS + / /dev/mapper/system-root ext4 rw,relatime + + localhost:~ # pvs + PV VG Fmt Attr PSize PFree + /dev/mapper/data system lvm2 a-- 1020.00m 0 + /dev/vda2 system lvm2 a-- 19.99g 0 + + localhost:~ # cryptsetup status /dev/mapper/data + /dev/mapper/data is active and is in use. + type: LUKS1 + cipher: aes-xts-plain64 + keysize: 512 bits + key location: dm-crypt + device: /dev/vdb + sector size: 512 + offset: 4096 sectors + size: 2093056 sectors + mode: read/write + + localhost:~ # vgs + VG #PV #LV #SN Attr VSize VFree + system 2 3 0 wz--n- 20.98g 0 + + localhost:~ # lvs -o lv_name,vg_name,devices + LV VG Devices + data system /dev/mapper/data(0) + root system /dev/vda2(512) + swap system /dev/vda2(0) + +We can learn from above that /dev/mapper/data is an encrypted volume and +also gets assigned to volume group "system" as one of it's physical +volumes. And also it is not used by root device, /dev/mapper/system-root, +for allocating extents, so it shouldn't be taking part in the process of +setting up GRUB to access root device. + +However, running grub-install reports error as volume group "system" +contains encrypted volume. + + error: attempt to install to encrypted disk without cryptodisk + enabled. Set `GRUB_ENABLE_CRYPTODISK=y' in file `/etc/default/grub'. + +Certainly we can enable GRUB_ENABLE_CRYPTODISK=y and move on, but that +is not always acceptable since the server may need to be booted unattended. +Additionally, typing passphrase for every system startup can be a big +hassle of which most users would like to avoid. + +This patch solves the problem by returning exact physical volume, /dev/vda2, +rightly used by system-root from the example above, thus grub-install will +not error out because the excessive encrypted device to boot the root device +is not configured. + +Signed-off-by: Michael Chang +Tested-by: Olav Reinert +Reviewed-by: Daniel Kiper +--- + grub-core/disk/diskfilter.c | 61 ++++++++++++++++++++++++++----------- + 1 file changed, 44 insertions(+), 17 deletions(-) + +diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c +index d094f7882..39d74cb86 100644 +--- a/grub-core/disk/diskfilter.c ++++ b/grub-core/disk/diskfilter.c +@@ -396,6 +396,8 @@ grub_diskfilter_memberlist (grub_disk_t disk) + grub_disk_dev_t p; + struct grub_diskfilter_vg *vg; + struct grub_diskfilter_lv *lv2 = NULL; ++ struct grub_diskfilter_segment *seg; ++ unsigned int i, j; + + if (!lv->vg->pvs) + return NULL; +@@ -427,27 +429,52 @@ grub_diskfilter_memberlist (grub_disk_t disk) + } + } + +- for (pv = lv->vg->pvs; pv; pv = pv->next) +- { +- if (!pv->disk) ++ for (i = 0, seg = lv->segments; i < lv->segment_count; i++, seg++) ++ for (j = 0; j < seg->node_count; ++j) ++ if (seg->nodes[j].pv != NULL) + { +- /* TRANSLATORS: This message kicks in during the detection of +- which modules needs to be included in core image. This happens +- in the case of degraded RAID and means that autodetection may +- fail to include some of modules. It's an installation time +- message, not runtime message. */ +- grub_util_warn (_("Couldn't find physical volume `%s'." +- " Some modules may be missing from core image."), +- pv->name); +- continue; ++ pv = seg->nodes[j].pv; ++ ++ if (pv->disk == NULL) ++ { ++ /* ++ * TRANSLATORS: This message kicks in during the detection of ++ * which modules needs to be included in core image. This happens ++ * in the case of degraded RAID and means that autodetection may ++ * fail to include some of modules. It's an installation time ++ * message, not runtime message. ++ */ ++ grub_util_warn (_("Couldn't find physical volume `%s'." ++ " Some modules may be missing from core image."), ++ pv->name); ++ continue; ++ } ++ ++ for (tmp = list; tmp != NULL; tmp = tmp->next) ++ if (!grub_strcmp (tmp->disk->name, pv->disk->name)) ++ break; ++ if (tmp != NULL) ++ continue; ++ ++ tmp = grub_malloc (sizeof (*tmp)); ++ if (tmp == NULL) ++ goto fail; ++ tmp->disk = pv->disk; ++ tmp->next = list; ++ list = tmp; + } +- tmp = grub_malloc (sizeof (*tmp)); +- tmp->disk = pv->disk; +- tmp->next = list; +- list = tmp; +- } + + return list; ++ ++ fail: ++ while (list != NULL) ++ { ++ tmp = list; ++ list = list->next; ++ grub_free (tmp); ++ } ++ ++ return NULL; + } + + void +-- +2.31.1 + diff --git a/0001-efi-linux-provide-linux-command.patch b/0001-efi-linux-provide-linux-command.patch new file mode 100644 index 0000000..9773cc6 --- /dev/null +++ b/0001-efi-linux-provide-linux-command.patch @@ -0,0 +1,103 @@ +From 987ab0dfbe7ef42bb6386fb7b428d3b965ba6d2b Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Mon, 7 Sep 2020 17:02:57 +0800 +Subject: [PATCH] efi/linux: provide linux command + +The linux kernel's efi handover entry point is used to boot efistub of +the linux kernel. Since then the efistub has been improved with many new +features and fixes that ordinary 32-bit entry point cannot provide. + +Besides, nearly every x86 efi kernel is built with efistub enabled so it +is of little value to keep 32-bit entry as default to boot kernel +without needed kconfig options enabled. + +For all good reasons, making efi handover the default entry point for +booting kernel in x86 efi platform so that linux command works in the +same way to linuxefi. This can also reduce the complexity of providing +general grub configuation for x86 system due to the linux command may +not be available in signed image for UEFI Secure Boot and linuxefi is +not available for leagcy bios booting. + +Signed-off-by: Michael Chang +--- + grub-core/Makefile.core.def | 6 ++++-- + grub-core/gensyminfo.sh.in | 3 +++ + grub-core/loader/i386/efi/linux.c | 17 +++++++++++++---- + 3 files changed, 20 insertions(+), 6 deletions(-) + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 6045da47b..3ea9dace0 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -1773,7 +1773,9 @@ module = { + + module = { + name = linux; +- x86 = loader/i386/linux.c; ++ i386_pc = loader/i386/linux.c; ++ i386_efi = loader/i386/efi/linux.c; ++ x86_64_efi = loader/i386/efi/linux.c; + i386_xen_pvh = loader/i386/linux.c; + xen = loader/i386/xen.c; + i386_pc = lib/i386/pc/vesa_modes_table.c; +@@ -1852,7 +1854,7 @@ module = { + + module = { + name = linuxefi; +- efi = loader/i386/efi/linux.c; ++ efi = lib/fake_module.c; + enable = i386_efi; + enable = x86_64_efi; + }; +diff --git a/grub-core/gensyminfo.sh.in b/grub-core/gensyminfo.sh.in +index 9bc767532..098de9258 100644 +--- a/grub-core/gensyminfo.sh.in ++++ b/grub-core/gensyminfo.sh.in +@@ -35,3 +35,6 @@ fi + + # Print all undefined symbols used by module + @TARGET_NM@ -u @TARGET_NMFLAGS_MINUS_P@ -p $module | sed "s@^\([^ ]*\).*@undefined $modname \1@g" ++ ++# Specify linuxefi module should load default linux ++test "$modname" = "linuxefi" && echo "undefined $modname grub_initrd_init" || true +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 8017e8c05..3f6d51519 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -347,20 +347,29 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + + static grub_command_t cmd_linux, cmd_initrd; ++static grub_command_t cmd_linuxefi, cmd_initrdefi; + +-GRUB_MOD_INIT(linuxefi) ++GRUB_MOD_INIT(linux) + { +- cmd_linux = ++ cmd_linuxefi = + grub_register_command ("linuxefi", grub_cmd_linux, + 0, N_("Load Linux.")); +- cmd_initrd = ++ cmd_initrdefi = + grub_register_command ("initrdefi", grub_cmd_initrd, + 0, N_("Load initrd.")); ++ cmd_linux = ++ grub_register_command ("linux", grub_cmd_linux, ++ 0, N_("Load Linux.")); ++ cmd_initrd = ++ grub_register_command ("initrd", grub_cmd_initrd, ++ 0, N_("Load initrd.")); + my_mod = mod; + } + +-GRUB_MOD_FINI(linuxefi) ++GRUB_MOD_FINI(linux) + { ++ grub_unregister_command (cmd_linuxefi); ++ grub_unregister_command (cmd_initrdefi); + grub_unregister_command (cmd_linux); + grub_unregister_command (cmd_initrd); + } +-- +2.26.2 + diff --git a/0001-emu-fix-executable-stack-marking.patch b/0001-emu-fix-executable-stack-marking.patch new file mode 100644 index 0000000..9d6e17f --- /dev/null +++ b/0001-emu-fix-executable-stack-marking.patch @@ -0,0 +1,70 @@ +From 4cc06bef26c3573309086bec4472cc9151b0379e Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Mon, 1 Feb 2021 20:14:12 +0800 +Subject: [PATCH] emu: fix executable stack marking + +The gcc by default assumes executable stack is required if the source +object file doesn't have .note.GNU-stack section in place. If any of the +source objects doesn't incorporate the GNU-stack note, the resulting +program will have executable stack flag set in PT_GNU_STACK program +header to instruct program loader or kernel to set up the exeutable +stack when program loads to memory. + +Usually the .note.GNU-stack section will be generated by gcc +automatically if it finds that executable stack is not required. However +it doesn't take care of generating .note.GNU-stack section for those +object files built from assembler sources. This leads to unnecessary +risk of security of exploiting the executable stack because those +assembler sources don't actually require stack to be executable to work. + +The grub-emu and grub-emu-lite are found to flag stack as executable +revealed by execstack tool. + + $ mkdir -p build-emu && cd build-emu + $ ../configure --with-platform=emu && make + $ execstack -q grub-core/grub-emu grub-core/grub-emu-lite + X grub-core/grub-emu + X grub-core/grub-emu-lite + +This patch will add the missing GNU-stack note to the assembler source +used by both utilities, therefore the result doesn't count on gcc +default behavior and the executable stack is disabled. + + $ execstack -q grub-core/grub-emu grub-core/grub-emu-lite + - grub-core/grub-emu + - grub-core/grub-emu-lite + +Signed-off-by: Michael Chang +--- + grub-core/kern/emu/cache_s.S | 5 +++++ + grub-core/lib/setjmp.S | 4 ++++ + 2 files changed, 9 insertions(+) + +Index: grub-2.04/grub-core/kern/emu/cache_s.S +=================================================================== +--- grub-2.04.orig/grub-core/kern/emu/cache_s.S ++++ grub-2.04/grub-core/kern/emu/cache_s.S +@@ -2,6 +2,11 @@ + #error "This source is only meant for grub-emu platform" + #endif + ++/* An executable stack is not required for these functions */ ++#if defined (__linux__) && defined (__ELF__) ++.section .note.GNU-stack,"",%progbits ++#endif ++ + #if defined(__i386__) || defined(__x86_64__) + /* Nothing is necessary. */ + #elif defined(__sparc__) +Index: grub-2.04/grub-core/lib/setjmp.S +=================================================================== +--- grub-2.04.orig/grub-core/lib/setjmp.S ++++ grub-2.04/grub-core/lib/setjmp.S +@@ -1,3 +1,7 @@ ++/* An executable stack is not required for these functions */ ++#if defined (__linux__) && defined (__ELF__) ++.section .note.GNU-stack,"",%progbits ++#endif + #if defined(__i386__) + #include "./i386/setjmp.S" + #elif defined(__x86_64__) diff --git a/0001-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch b/0001-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch new file mode 100644 index 0000000..25fac6b --- /dev/null +++ b/0001-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch @@ -0,0 +1,33 @@ +From a2606b0cb95f261288c79cafc7295927d868cb04 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Wed, 3 Aug 2022 19:45:33 +0800 +Subject: [PATCH 01/12] font: Reject glyphs exceeds font->max_glyph_width or + font->max_glyph_height + +Check glyph's width and height against limits specified in font's +metadata. Reject the glyph (and font) if such limits are exceeded. + +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +--- + grub-core/font/font.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index d09bb38d8..2f09a4a55 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -760,7 +760,9 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code) + || read_be_uint16 (font->file, &height) != 0 + || read_be_int16 (font->file, &xoff) != 0 + || read_be_int16 (font->file, &yoff) != 0 +- || read_be_int16 (font->file, &dwidth) != 0) ++ || read_be_int16 (font->file, &dwidth) != 0 ++ || width > font->max_char_width ++ || height > font->max_char_height) + { + remove_font (font); + return 0; +-- +2.35.3 + diff --git a/0001-fs-btrfs-Make-extent-item-iteration-to-handle-gaps.patch b/0001-fs-btrfs-Make-extent-item-iteration-to-handle-gaps.patch new file mode 100644 index 0000000..7089035 --- /dev/null +++ b/0001-fs-btrfs-Make-extent-item-iteration-to-handle-gaps.patch @@ -0,0 +1,124 @@ +From 149df8b7bb86401693e1f064859de0a8906d97b7 Mon Sep 17 00:00:00 2001 +From: Qu Wenruo +Date: Thu, 28 Oct 2021 17:44:57 +0800 +Subject: [PATCH] fs/btrfs: Make extent item iteration to handle gaps + +[BUG] +Grub btrfs implementation can't handle two very basic btrfs file +layouts: + +1. Mixed inline/regualr extents + # mkfs.btrfs -f test.img + # mount test.img /mnt/btrfs + # xfs_io -f -c "pwrite 0 1k" -c "sync" -c "falloc 0 4k" \ + -c "pwrite 4k 4k" /mnt/btrfs/file + # umount /mnt/btrfs + # ./grub-fstest ./grub-fstest --debug=btrfs ~/test.img hex "/file" + + Such mixed inline/regular extents case is not recommended layout, + but all existing tools and kernel can handle it without problem + +2. NO_HOLES feature + # mkfs.btrfs -f test.img -O no_holes + # mount test.img /mnt/btrfs + # xfs_io -f -c "pwrite 0 4k" -c "pwrite 8k 4k" /mnt/btrfs/file + # umount /mnt/btrfs + # ./grub-fstest ./grub-fstest --debug=btrfs ~/test.img hex "/file" + + NO_HOLES feature is going to be the default mkfs feature in the incoming + v5.15 release, and kernel has support for it since v4.0. + +[CAUSE] +The way GRUB btrfs code iterates through file extents relies on no gap +between extents. + +If any gap is hit, then grub btrfs will error out, without any proper +reason to help debug the bug. + +This is a bad assumption, since a long long time ago btrfs has a new +feature called NO_HOLES to allow btrfs to skip the padding hole extent +to reduce metadata usage. + +The NO_HOLES feature is already stable since kernel v4.0 and is going to +be the default mkfs feature in the incoming v5.15 btrfs-progs release. + +[FIX] +When there is a extent gap, instead of error out, just try next item. + +This is still not ideal, as kernel/progs/U-boot all do the iteration +item by item, not relying on the file offset continuity. + +But it will be way more time consuming to correct the whole behavior +than starting from scratch to build a proper designed btrfs module for GRUB. + +Signed-off-by: Qu Wenruo +Reviewed-by: Daniel Kiper +--- + grub-core/fs/btrfs.c | 35 ++++++++++++++++++++++++++++++++--- + 1 file changed, 32 insertions(+), 3 deletions(-) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index 9625bdf16..b8625197b 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -1506,6 +1506,7 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data, + grub_size_t csize; + grub_err_t err; + grub_off_t extoff; ++ struct grub_btrfs_leaf_descriptor desc; + if (!data->extent || data->extstart > pos || data->extino != ino + || data->exttree != tree || data->extend <= pos) + { +@@ -1518,7 +1519,7 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data, + key_in.type = GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM; + key_in.offset = grub_cpu_to_le64 (pos); + err = lower_bound (data, &key_in, &key_out, tree, +- &elemaddr, &elemsize, NULL, 0); ++ &elemaddr, &elemsize, &desc, 0); + if (err) + return -1; + if (key_out.object_id != ino +@@ -1557,10 +1558,38 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data, + PRIxGRUB_UINT64_T "\n", + grub_le_to_cpu64 (key_out.offset), + grub_le_to_cpu64 (data->extent->size)); ++ /* ++ * The way of extent item iteration is pretty bad, it completely ++ * requires all extents are contiguous, which is not ensured. ++ * ++ * Features like NO_HOLE and mixed inline/regular extents can cause ++ * gaps between file extent items. ++ * ++ * The correct way is to follow kernel/U-boot to iterate item by ++ * item, without any assumption on the file offset continuity. ++ * ++ * Here we just manually skip to next item and re-do the verification. ++ * ++ * TODO: Rework the whole extent item iteration code, if not the ++ * whole btrfs implementation. ++ */ + if (data->extend <= pos) + { +- grub_error (GRUB_ERR_BAD_FS, "extent not found"); +- return -1; ++ err = next(data, &desc, &elemaddr, &elemsize, &key_out); ++ if (err < 0) ++ return -1; ++ /* No next item for the inode, we hit the end */ ++ if (err == 0 || key_out.object_id != ino || ++ key_out.type != GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM) ++ return pos - pos0; ++ ++ csize = grub_le_to_cpu64(key_out.offset) - pos; ++ if (csize > len) ++ csize = len; ++ buf += csize; ++ pos += csize; ++ len -= csize; ++ continue; + } + } + csize = data->extend - pos; +-- +2.31.1 + diff --git a/0001-fs-ntfs-Fix-an-OOB-write-when-parsing-the-ATTRIBUTE_.patch b/0001-fs-ntfs-Fix-an-OOB-write-when-parsing-the-ATTRIBUTE_.patch new file mode 100644 index 0000000..7a9b59d --- /dev/null +++ b/0001-fs-ntfs-Fix-an-OOB-write-when-parsing-the-ATTRIBUTE_.patch @@ -0,0 +1,93 @@ +From 43651027d24e62a7a463254165e1e46e42aecdea Mon Sep 17 00:00:00 2001 +From: Maxim Suhanov +Date: Mon, 28 Aug 2023 16:31:57 +0300 +Subject: [PATCH 1/6] fs/ntfs: Fix an OOB write when parsing the + $ATTRIBUTE_LIST attribute for the $MFT file + +When parsing an extremely fragmented $MFT file, i.e., the file described +using the $ATTRIBUTE_LIST attribute, current NTFS code will reuse a buffer +containing bytes read from the underlying drive to store sector numbers, +which are consumed later to read data from these sectors into another buffer. + +These sectors numbers, two 32-bit integers, are always stored at predefined +offsets, 0x10 and 0x14, relative to first byte of the selected entry within +the $ATTRIBUTE_LIST attribute. Usually, this won't cause any problem. + +However, when parsing a specially-crafted file system image, this may cause +the NTFS code to write these integers beyond the buffer boundary, likely +causing the GRUB memory allocator to misbehave or fail. These integers contain +values which are controlled by on-disk structures of the NTFS file system. + +Such modification and resulting misbehavior may touch a memory range not +assigned to the GRUB and owned by firmware or another EFI application/driver. + +This fix introduces checks to ensure that these sector numbers are never +written beyond the boundary. + +Fixes: CVE-2023-4692 + +Reported-by: Maxim Suhanov +Signed-off-by: Maxim Suhanov +Reviewed-by: Daniel Kiper +--- + grub-core/fs/ntfs.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index bbdbe24ad..c3c4db117 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -184,7 +184,7 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + } + if (at->attr_end) + { +- grub_uint8_t *pa; ++ grub_uint8_t *pa, *pa_end; + + at->emft_buf = grub_malloc (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR); + if (at->emft_buf == NULL) +@@ -209,11 +209,13 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + } + at->attr_nxt = at->edat_buf; + at->attr_end = at->edat_buf + u32at (pa, 0x30); ++ pa_end = at->edat_buf + n; + } + else + { + at->attr_nxt = at->attr_end + u16at (pa, 0x14); + at->attr_end = at->attr_end + u32at (pa, 4); ++ pa_end = at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR); + } + at->flags |= GRUB_NTFS_AF_ALST; + while (at->attr_nxt < at->attr_end) +@@ -230,6 +232,13 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + at->flags |= GRUB_NTFS_AF_GPOS; + at->attr_cur = at->attr_nxt; + pa = at->attr_cur; ++ ++ if ((pa >= pa_end) || (pa_end - pa < 0x18)) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "can\'t parse attribute list"); ++ return NULL; ++ } ++ + grub_set_unaligned32 ((char *) pa + 0x10, + grub_cpu_to_le32 (at->mft->data->mft_start)); + grub_set_unaligned32 ((char *) pa + 0x14, +@@ -240,6 +249,13 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + { + if (*pa != attr) + break; ++ ++ if ((pa >= pa_end) || (pa_end - pa < 0x18)) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "can\'t parse attribute list"); ++ return NULL; ++ } ++ + if (read_attr + (at, pa + 0x10, + u32at (pa, 0x10) * (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR), +-- +2.42.0 + diff --git a/0001-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch b/0001-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch new file mode 100644 index 0000000..40a1cf2 --- /dev/null +++ b/0001-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch @@ -0,0 +1,120 @@ +From 7c11f4f3d71c3fc8acff820b1fd449c94095dab9 Mon Sep 17 00:00:00 2001 +From: Erwan Velu +Date: Wed, 25 Aug 2021 15:31:52 +0200 +Subject: [PATCH] fs/xfs: Fix unreadable filesystem with v4 superblock + +The commit 8b1e5d193 (fs/xfs: Add bigtime incompat feature support) +introduced the bigtime support by adding some features in v3 inodes. +This change extended grub_xfs_inode struct by 76 bytes but also changed +the computation of XFS_V2_INODE_SIZE and XFS_V3_INODE_SIZE. Prior this +commit, XFS_V2_INODE_SIZE was 100 bytes. After the commit it's 84 bytes +XFS_V2_INODE_SIZE becomes 16 bytes too small. + +As a result, the data structures aren't properly aligned and the GRUB +generates "attempt to read or write outside of partition" errors when +trying to read the XFS filesystem: + + GNU GRUB version 2.11 + .... + grub> set debug=efi,gpt,xfs + grub> insmod part_gpt + grub> ls (hd0,gpt1)/ + partmap/gpt.c:93: Read a valid GPT header + partmap/gpt.c:115: GPT entry 0: start=4096, length=1953125 + fs/xfs.c:931: Reading sb + fs/xfs.c:270: Validating superblock + fs/xfs.c:295: XFS v4 superblock detected + fs/xfs.c:962: Reading root ino 128 + fs/xfs.c:515: Reading inode (128) - 64, 0 + fs/xfs.c:515: Reading inode (739521961424144223) - 344365866970255880, 3840 + error: attempt to read or write outside of partition. + +This commit change the XFS_V2_INODE_SIZE computation by subtracting 76 +bytes instead of 92 bytes from the actual size of grub_xfs_inode struct. +This 76 bytes value comes from added members: + 20 grub_uint8_t unused5 + 1 grub_uint64_t flags2 + 48 grub_uint8_t unused6 + +This patch explicitly splits the v2 and v3 parts of the structure. +The unused4 is still ending of the v2 structures and the v3 starts +at unused5. Thanks to this we will avoid future corruptions of v2 +or v3 inodes. + +The XFS_V2_INODE_SIZE is returning to its expected size and the +filesystem is back to a readable state: + + GNU GRUB version 2.11 + .... + grub> set debug=efi,gpt,xfs + grub> insmod part_gpt + grub> ls (hd0,gpt1)/ + partmap/gpt.c:93: Read a valid GPT header + partmap/gpt.c:115: GPT entry 0: start=4096, length=1953125 + fs/xfs.c:931: Reading sb + fs/xfs.c:270: Validating superblock + fs/xfs.c:295: XFS v4 superblock detected + fs/xfs.c:962: Reading root ino 128 + fs/xfs.c:515: Reading inode (128) - 64, 0 + fs/xfs.c:515: Reading inode (128) - 64, 0 + fs/xfs.c:931: Reading sb + fs/xfs.c:270: Validating superblock + fs/xfs.c:295: XFS v4 superblock detected + fs/xfs.c:962: Reading root ino 128 + fs/xfs.c:515: Reading inode (128) - 64, 0 + fs/xfs.c:515: Reading inode (128) - 64, 0 + fs/xfs.c:515: Reading inode (128) - 64, 0 + fs/xfs.c:515: Reading inode (131) - 64, 768 + efi/ fs/xfs.c:515: Reading inode (3145856) - 1464904, 0 + grub2/ fs/xfs.c:515: Reading inode (132) - 64, 1024 + grub/ fs/xfs.c:515: Reading inode (139) - 64, 2816 + grub> + +Fixes: 8b1e5d193 (fs/xfs: Add bigtime incompat feature support) + +Signed-off-by: Erwan Velu +Tested-by: Carlos Maiolino +Reviewed-by: Daniel Kiper +--- + grub-core/fs/xfs.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c +index 0f524c3a8..e3816d1ec 100644 +--- a/grub-core/fs/xfs.c ++++ b/grub-core/fs/xfs.c +@@ -192,6 +192,11 @@ struct grub_xfs_time_legacy + grub_uint32_t nanosec; + } GRUB_PACKED; + ++/* ++ * The struct grub_xfs_inode layout was taken from the ++ * struct xfs_dinode_core which is described here: ++ * https://mirrors.edge.kernel.org/pub/linux/utils/fs/xfs/docs/xfs_filesystem_structure.pdf ++ */ + struct grub_xfs_inode + { + grub_uint8_t magic[2]; +@@ -208,14 +213,15 @@ struct grub_xfs_inode + grub_uint32_t nextents; + grub_uint16_t unused3; + grub_uint8_t fork_offset; +- grub_uint8_t unused4[37]; ++ grub_uint8_t unused4[17]; /* Last member of inode v2. */ ++ grub_uint8_t unused5[20]; /* First member of inode v3. */ + grub_uint64_t flags2; +- grub_uint8_t unused5[48]; ++ grub_uint8_t unused6[48]; /* Last member of inode v3. */ + } GRUB_PACKED; + + #define XFS_V3_INODE_SIZE sizeof(struct grub_xfs_inode) +-/* Size of struct grub_xfs_inode until fork_offset (included). */ +-#define XFS_V2_INODE_SIZE (XFS_V3_INODE_SIZE - 92) ++/* Size of struct grub_xfs_inode v2, up to unused4 member included. */ ++#define XFS_V2_INODE_SIZE (XFS_V3_INODE_SIZE - 76) + + struct grub_xfs_dirblock_tail + { +-- +2.31.1 + diff --git a/0001-grub-core-modify-sector-by-sysfs-as-disk-sector.patch b/0001-grub-core-modify-sector-by-sysfs-as-disk-sector.patch new file mode 100644 index 0000000..d0e79f2 --- /dev/null +++ b/0001-grub-core-modify-sector-by-sysfs-as-disk-sector.patch @@ -0,0 +1,57 @@ +From 1eee02bbf2c11167e94f424846ce1de0b6e7fa8e Mon Sep 17 00:00:00 2001 +From: Mukesh Kumar Chaurasiya +Date: Fri, 3 Feb 2023 10:10:43 +0530 +Subject: [PATCH] grub-core: modify sector by sysfs as disk sector + +The disk sector size provided by sysfs file system considers the +sector size of 512 irrespective of disk sector size, Thus +causing the read by grub to an incorrect offset from what was +originally intended. + +Considering the 512 sector size of sysfs data the actual sector +needs to be modified corresponding to disk sector size. + +Signed-off-by: Mukesh Kumar Chaurasiya +--- + grub-core/osdep/linux/hostdisk.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +--- a/grub-core/osdep/linux/hostdisk.c ++++ b/grub-core/osdep/linux/hostdisk.c +@@ -199,8 +199,15 @@ + + #pragma GCC diagnostic ignored "-Wformat-nonliteral" + ++static inline grub_disk_addr_t ++transform_sector (grub_disk_t disk, grub_disk_addr_t sector) ++{ ++ return sector >> (disk->log_sector_size - GRUB_DISK_SECTOR_BITS); ++} ++ + static int +-grub_hostdisk_linux_find_partition (char *dev, grub_disk_addr_t sector) ++grub_hostdisk_linux_find_partition (const grub_disk_t disk, char *dev, ++ grub_disk_addr_t sector) + { + size_t len = strlen (dev); + const char *format; +@@ -265,7 +272,8 @@ + if (fstat (fd, &st) < 0 + || !grub_util_device_is_mapped_stat (&st) + || !grub_util_get_dm_node_linear_info (st.st_rdev, 0, 0, &start)) +- start = grub_util_find_partition_start_os (real_dev); ++ start = transform_sector (disk, ++ grub_util_find_partition_start_os (real_dev)); + /* We don't care about errors here. */ + grub_errno = GRUB_ERR_NONE; + +@@ -346,7 +354,8 @@ + && strncmp (dev, "/dev/", 5) == 0) + { + if (sector >= part_start) +- is_partition = grub_hostdisk_linux_find_partition (dev, part_start); ++ is_partition = grub_hostdisk_linux_find_partition (disk, dev, ++ part_start); + else + *max = part_start - sector; + } diff --git a/0001-grub-install-Add-SUSE-signed-image-support-for-power.patch b/0001-grub-install-Add-SUSE-signed-image-support-for-power.patch new file mode 100644 index 0000000..cae425c --- /dev/null +++ b/0001-grub-install-Add-SUSE-signed-image-support-for-power.patch @@ -0,0 +1,110 @@ +From 83a6f72e1896bd012b7fbca21317e96c2c22b327 Mon Sep 17 00:00:00 2001 +From: Michal Suchanek +Date: Wed, 12 Jan 2022 19:25:54 +0100 +Subject: [PATCH] grub-install: Add SUSE signed image support for powerpc. + +Signed-off-by: Michal Suchanek +--- + grub-core/osdep/linux/platform.c | 13 +++++++++++++ + include/grub/util/install.h | 3 +++ + util/grub-install.c | 29 ++++++++++++++++++++++++++--- + 3 files changed, 42 insertions(+), 3 deletions(-) + +diff --git a/grub-core/osdep/linux/platform.c b/grub-core/osdep/linux/platform.c +index e28a79dab..2a12ed867 100644 +--- a/grub-core/osdep/linux/platform.c ++++ b/grub-core/osdep/linux/platform.c +@@ -154,3 +154,16 @@ grub_install_get_default_x86_platform (void) + grub_util_info ("... not found"); + return "i386-pc"; + } ++ ++int ++grub_install_get_powerpc_secure_boot (void) ++{ ++ int32_t ret = -1; ++ FILE *fp = grub_util_fopen ("/proc/device-tree/ibm,secure-boot", "rb"); ++ if (fp) { ++ if (fread (&ret , 1, sizeof(ret), fp) > 0) ++ ret = grub_be_to_cpu32(ret); ++ fclose(fp); ++ } ++ return ret; ++} +diff --git a/include/grub/util/install.h b/include/grub/util/install.h +index c241a2a40..154487b72 100644 +--- a/include/grub/util/install.h ++++ b/include/grub/util/install.h +@@ -233,6 +233,9 @@ grub_install_get_default_arm_platform (void); + const char * + grub_install_get_default_x86_platform (void); + ++int ++grub_install_get_powerpc_secure_boot (void); ++ + int + grub_install_register_efi (grub_device_t efidir_grub_dev, + const char *efifile_path, +diff --git a/util/grub-install.c b/util/grub-install.c +index a2286b3dd..8fb5ea616 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -321,10 +321,10 @@ static struct argp_option options[] = { + {"suse-enable-tpm", OPTION_SUSE_ENABLE_TPM, 0, 0, N_("install TPM modules"), 0}, + {"suse-force-signed", OPTION_SUSE_FORCE_SIGNED, 0, 0, + N_("force installation of signed grub" "%s." +- "This option is only available on ARM64 EFI targets."), 0}, ++ "This option is only available on ARM64 EFI and powerpc targets."), 0}, + {"suse-inhibit-signed", OPTION_SUSE_INHIBIT_SIGNED, 0, 0, + N_("inhibit installation of signed grub. " +- "This option is only available on ARM64 EFI targets."), 0}, ++ "This option is only available on ARM64 EFI and powerpc targets."), 0}, + {"debug", OPTION_DEBUG, 0, OPTION_HIDDEN, 0, 2}, + {"no-floppy", OPTION_NO_FLOPPY, 0, OPTION_HIDDEN, 0, 2}, + {"debug-image", OPTION_DEBUG_IMAGE, N_("STRING"), OPTION_HIDDEN, 0, 2}, +@@ -1724,6 +1724,7 @@ main (int argc, char *argv[]) + char mkimage_target[200]; + const char *core_name = NULL; + char *signed_imgfile = NULL; ++ int ppc_sb_state = -1; + + switch (platform) + { +@@ -1770,11 +1771,33 @@ main (int argc, char *argv[]) + grub_install_get_platform_platform (platform)); + break; + ++ ++ case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275: ++ ppc_sb_state = grub_install_get_powerpc_secure_boot(); ++ ++ if ((signed_grub_mode >= SIGNED_GRUB_FORCE) || ((signed_grub_mode == SIGNED_GRUB_AUTO) && (ppc_sb_state > 0))) ++ { ++ signed_imgfile = grub_util_path_concat (2, grub_install_source_directory, "grub.elf"); ++ if (!grub_util_is_regular (signed_imgfile)) ++ { ++ if ((signed_grub_mode >= SIGNED_GRUB_FORCE) || (ppc_sb_state > 1)) ++ grub_util_error ("signed image `%s' does not exist\n", signed_imgfile); ++ else ++ { ++ free (signed_imgfile); ++ signed_imgfile = NULL; ++ } ++ } ++ } ++ ++ if (signed_imgfile) ++ fprintf (stderr, _("Use signed file in %s for installation.\n"), signed_imgfile); ++ ++ /* fallthrough. */ + case GRUB_INSTALL_PLATFORM_I386_COREBOOT: + case GRUB_INSTALL_PLATFORM_ARM_COREBOOT: + case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT: + case GRUB_INSTALL_PLATFORM_I386_IEEE1275: +- case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275: + case GRUB_INSTALL_PLATFORM_I386_XEN: + case GRUB_INSTALL_PLATFORM_X86_64_XEN: + case GRUB_INSTALL_PLATFORM_I386_XEN_PVH: +-- +2.31.1 + diff --git a/0001-grub-install-bailout-root-device-probing.patch b/0001-grub-install-bailout-root-device-probing.patch new file mode 100644 index 0000000..ea24471 --- /dev/null +++ b/0001-grub-install-bailout-root-device-probing.patch @@ -0,0 +1,176 @@ +From 58dcf7985b20de876a6fc44a591aa377d0a0302c Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Thu, 10 Feb 2022 22:16:58 +0800 +Subject: [PATCH] grub-install: bailout root device probing + +The root device is probed to test if the filesystem is btrfs in order to setup +boot configs for snapshot booting. However when the root device is a lvm thin +volume, due to lack in grub support, the probing will be errored out and entire +installation process aborts. + +Here we call out stat to bailout the situation whenever grub fails to probe +filesystem in it's own right. + + stat -f -c %T / + +The command is also used by grub-mkconfig for the same purpose. + +Signed-off-by: Michael Chang +--- + grub-core/osdep/basic/no_platform.c | 5 +++++ + grub-core/osdep/unix/platform.c | 34 +++++++++++++++++++++++++++++ + grub-core/osdep/windows/platform.c | 6 +++++ + include/grub/util/install.h | 3 +++ + util/grub-install.c | 31 ++++++++++++++++++-------- + 5 files changed, 70 insertions(+), 9 deletions(-) + +diff --git a/grub-core/osdep/basic/no_platform.c b/grub-core/osdep/basic/no_platform.c +index a173dafe90..dfbdd58e4e 100644 +--- a/grub-core/osdep/basic/no_platform.c ++++ b/grub-core/osdep/basic/no_platform.c +@@ -51,3 +51,8 @@ grub_install_zipl (const char *d, int i, int f) + grub_util_error ("%s", _("no zIPL routines are available for your platform")); + } + ++char * ++grub_install_get_filesystem (const char *path) ++{ ++ return NULL; ++} +diff --git a/grub-core/osdep/unix/platform.c b/grub-core/osdep/unix/platform.c +index 4df143671a..68186480b2 100644 +--- a/grub-core/osdep/unix/platform.c ++++ b/grub-core/osdep/unix/platform.c +@@ -250,3 +250,37 @@ grub_install_zipl (const char *dest, int install, int force) + "-z", dest, NULL })) + grub_util_error (_("`%s' failed.\n"), PACKAGE"-zipl-setup"); + } ++ ++char * ++grub_install_get_filesystem (const char *path) ++{ ++ int fd; ++ pid_t pid; ++ FILE *fp; ++ ssize_t len; ++ char *buf = NULL; ++ size_t bufsz = 0; ++ ++ pid = grub_util_exec_pipe ((const char * []){ "stat", "-f", "-c", "%T", path, NULL }, &fd); ++ if (!pid) ++ return NULL; ++ ++ fp = fdopen (fd, "r"); ++ if (!fp) ++ return NULL; ++ ++ len = getline (&buf, &bufsz, fp); ++ if (len == -1) ++ { ++ free (buf); ++ fclose (fp); ++ return NULL; ++ } ++ ++ fclose (fp); ++ ++ if (len > 0 && buf[len - 1] == '\n') ++ buf[len - 1] = '\0'; ++ ++ return buf; ++} +diff --git a/grub-core/osdep/windows/platform.c b/grub-core/osdep/windows/platform.c +index 733c36d72c..1d2e356e6b 100644 +--- a/grub-core/osdep/windows/platform.c ++++ b/grub-core/osdep/windows/platform.c +@@ -430,3 +430,9 @@ grub_install_zipl (const char *d, int i, int f) + { + grub_util_error ("%s", _("no zIPL routines are available for your platform")); + } ++ ++char * ++grub_install_get_filesystem (const char *path) ++{ ++ return NULL; ++} +diff --git a/include/grub/util/install.h b/include/grub/util/install.h +index 154487b72b..456955c3d7 100644 +--- a/include/grub/util/install.h ++++ b/include/grub/util/install.h +@@ -252,6 +252,9 @@ grub_install_sgi_setup (const char *install_device, + void + grub_install_zipl (const char *d, int i, int f); + ++char * ++grub_install_get_filesystem (const char *path); ++ + int + grub_install_compress_gzip (const char *src, const char *dest); + int +diff --git a/util/grub-install.c b/util/grub-install.c +index 7bc5f84378..213f54a782 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -871,7 +871,6 @@ main (int argc, char *argv[]) + const char *efi_file = NULL; + char **grub_devices; + grub_fs_t grub_fs; +- grub_fs_t root_fs; + grub_device_t grub_dev = NULL; + enum grub_install_plat platform; + char *grubdir, *device_map; +@@ -1049,8 +1048,10 @@ main (int argc, char *argv[]) + grub_host_init (); + + { +- char *rootdir_grub_devname; +- grub_device_t rootdir_grub_dev; ++ grub_device_t rootdir_grub_dev = NULL; ++ char *rootdir_grub_devname = NULL; ++ char *root_fs_name = NULL; ++ + char *t = grub_util_path_concat (2, "/", rootdir); + + rootdir_path = grub_canonicalize_file_name (t); +@@ -1071,20 +1072,32 @@ main (int argc, char *argv[]) + rootdir_devices[0]); + + rootdir_grub_dev = grub_device_open (rootdir_grub_devname); +- if (! rootdir_grub_dev) +- grub_util_error ("%s", grub_errmsg); ++ if (!rootdir_grub_dev) ++ { ++ root_fs_name = grub_install_get_filesystem (t); ++ if (root_fs_name) ++ grub_errno = 0; ++ } ++ else ++ { ++ grub_fs_t root_fs = grub_fs_probe (rootdir_grub_dev); ++ if (root_fs) ++ root_fs_name = grub_strdup (root_fs->name); ++ } + +- root_fs = grub_fs_probe (rootdir_grub_dev); +- if (!root_fs) ++ if (!root_fs_name) + grub_util_error ("%s", grub_errmsg); + + if (config.is_suse_btrfs_snapshot_enabled +- && grub_strncmp(root_fs->name, "btrfs", sizeof ("btrfs") - 1) == 0) ++ && root_fs_name ++ && grub_strncmp(root_fs_name, "btrfs", sizeof ("btrfs") - 1) == 0) + use_relative_path_on_btrfs = 1; + ++ free (root_fs_name); + free (t); + free (rootdir_grub_devname); +- grub_device_close (rootdir_grub_dev); ++ if (rootdir_grub_dev) ++ grub_device_close (rootdir_grub_dev); + } + + switch (platform) +-- +2.34.1 + diff --git a/0001-grub-install-set-point-of-no-return-for-powerpc-ieee1275.patch b/0001-grub-install-set-point-of-no-return-for-powerpc-ieee1275.patch new file mode 100644 index 0000000..1b74911 --- /dev/null +++ b/0001-grub-install-set-point-of-no-return-for-powerpc-ieee1275.patch @@ -0,0 +1,32 @@ +From grub-devel-bounces@gnu.org Thu Aug 25 08:11:08 2022 +From: Michael Chang +Date: Thu, 25 Aug 2022 14:05:01 +0800 +Subject: [PATCH] grub-install: set point of no return for powerpc-ieee1275 + install + +The point of no return is used to define a point where no change should +be reverted in a wake of fatal error that consequently aborts the +process. The powerpc-ieee1275 install apparently missed this point of no +return defintion that newly installed modules could be inadvertently +reverted after successful image embedding so that boot failure is +incurred due to inconsistent state. + +Signed-off-by: Michael Chang +[iluceno@suse.de: Backported to SLES-15-SP4] +Signed-off-by: Ismael Luceno +--- + util/grub-install.c | 1 + + 1 file changed, 1 insertion(+) + +Index: grub-2.06/util/grub-install.c +=================================================================== +--- grub-2.06.orig/util/grub-install.c ++++ grub-2.06/util/grub-install.c +@@ -2160,6 +2160,7 @@ main (int argc, char *argv[]) + { + grub_util_error ("%s", _("failed to copy Grub to the PReP partition")); + } ++ grub_set_install_backup_ponr (); + + if ((signed_grub_mode >= SIGNED_GRUB_FORCE) || ((signed_grub_mode == SIGNED_GRUB_AUTO) && (ppc_sb_state > 0))) + { diff --git a/0001-grub-mkconfig-restore-umask-for-grub.cfg.patch b/0001-grub-mkconfig-restore-umask-for-grub.cfg.patch new file mode 100644 index 0000000..93d4647 --- /dev/null +++ b/0001-grub-mkconfig-restore-umask-for-grub.cfg.patch @@ -0,0 +1,44 @@ +From 7a5022ea64fd6af859383a1731632abc8755b8f7 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Thu, 26 Aug 2021 15:52:00 +0800 +Subject: [PATCH] grub-mkconfig: restore umask for grub.cfg + +Since commit: + + ab2e53c8a grub-mkconfig: Honor a symlink when generating configuration +by grub-mkconfig + +has inadvertently discarded umask for creating grub.cfg in the process +of grub-mkconfig. The resulting wrong permission (0644) would allow +unprivileged users to read grub's configuration file content. This +presents a low confidentiality risk as grub.cfg may contain non-secured +plain-text passwords. + +This patch restores the missing umask and set the file mode of creation +to 0600 preventing unprivileged access. + +Fixes: CVE-2021-3981 + +Signed-off-by: Michael Chang +Reviewed-by: Daniel Kiper +--- + util/grub-mkconfig.in | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in +index 7f6d961d2..4aca09d8e 100644 +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -351,7 +351,9 @@ and /etc/grub.d/* files or please file a bug report with + exit 1 + else + # none of the children aborted with error, install the new grub.cfg ++ oldumask=$(umask); umask 077 + cat ${grub_cfg}.new > ${grub_cfg} ++ umask $oldumask + rm -f ${grub_cfg}.new + # check if default entry need to be corrected for updated distributor version + # and/or use fallback entry if default kernel entry removed +-- +2.31.1 + diff --git a/0001-grub2-Can-t-setup-a-default-boot-device-correctly-on.patch b/0001-grub2-Can-t-setup-a-default-boot-device-correctly-on.patch new file mode 100644 index 0000000..5a1a8dd --- /dev/null +++ b/0001-grub2-Can-t-setup-a-default-boot-device-correctly-on.patch @@ -0,0 +1,44 @@ +From a59b58f6ae327a8f6949991cb5531db01e1ba14d Mon Sep 17 00:00:00 2001 +From: Wen Xiong +Date: Tue, 7 Feb 2023 15:10:15 -0500 +Subject: [PATCH] grub2: Can't setup a default boot device correctly on nvme + device in Beta3 + +The patch in Bug 200486 - SUSE1205666 - SLES15SP5 Beta1: Setup multiple dev path + for a nvmf boot device in grub2 caused the issue. That patch didn't consider +nvme devices carefully. + +The new patch will check "nvme-of" instead of "nvme" to call +build_multi_boot_device(). + +Signed-off-by: Wen Xiong +--- + grub-core/osdep/unix/platform.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/grub-core/osdep/unix/platform.c b/grub-core/osdep/unix/platform.c +index db8fa4b95..fb47c0ffa 100644 +--- a/grub-core/osdep/unix/platform.c ++++ b/grub-core/osdep/unix/platform.c +@@ -288,11 +288,15 @@ grub_install_register_ieee1275 (int is_prep, const char *install_device, + } + *ptr = '\0'; + } +- else if (grub_strstr(install_device, "nvme")) +- boot_device = build_multi_boot_device(install_device); +- else ++ else { + boot_device = get_ofpathname (install_device); + ++ if (grub_strstr(boot_device, "nvme-of")) { ++ free (boot_device); ++ boot_device = build_multi_boot_device(install_device); ++ } ++ } ++ + if (grub_util_exec ((const char * []){ "nvsetenv", "boot-device", + boot_device, NULL })) + { +-- +2.39.1 + diff --git a/0001-grub2-Set-multiple-device-path-for-a-nvmf-boot-devic.patch b/0001-grub2-Set-multiple-device-path-for-a-nvmf-boot-devic.patch new file mode 100644 index 0000000..0b7c96d --- /dev/null +++ b/0001-grub2-Set-multiple-device-path-for-a-nvmf-boot-devic.patch @@ -0,0 +1,175 @@ +From 3e77c5494fd06f430588ae9c304fea370439d531 Mon Sep 17 00:00:00 2001 +From: Wen Xiong +Date: Thu, 15 Dec 2022 21:33:41 -0500 +Subject: [PATCH] grub2: Set multiple device path for a nvmf boot device + +nvmf support native multipath(ANA) by default. +The patch added the support for setting multiple +device path for a nvmf boot device. + +localhost:~ grub2-install -v /dev/nvme1n1p1 +... +... +... +grub2-install: info: executing nvsetenv boot-device /pci@800000020000132/fibre-channel@0,1/nvme-of/controller@5005076810193675,ffff:nqn=nqn.1986-03.com.ibm:nvme:2145.0000020420006CEA/namespace@ec /pci@800000020000132/fibre-channel@0/nvme-of/controller@5005076810193675,ffff:nqn=nqn.1986-03.com.ibm:nvme:2145.0000020420006CEA/namespace@ec /pci@800000020000132/fibre-channel@0/nvme-of/controller@50050768101935e5,ffff:nqn=nqn.1986-03.com.ibm:nvme:2145.0000020420006CEA/namespace@ec /pci@800000020000132/fibre-channel@0,1/nvme-of/controller@50050768101935e5,ffff:nqn=nqn.1986-03.com.ibm:nvme:2145.0000020420006CEA/namespace@ec. +Installation finished. No error reported. + +localhost:~ # bootlist -m normal -o +nvme7n1 +nvme5n1 +nvme1n1 +nvme4n1 + +localhost:~ # bootlist -m normal -r +/pci@800000020000132/fibre-channel@0,1/nvme-of/controller@5005076810193675,ffff:nqn=nqn.1986-03.com.ibm:nvme:2145.0000020420006CEA/namespace@ec +/pci@800000020000132/fibre-channel@0/nvme-of/controller@5005076810193675,ffff:nqn=nqn.1986-03.com.ibm:nvme:2145.0000020420006CEA/namespace@ec +/pci@800000020000132/fibre-channel@0/nvme-of/controller@50050768101935e5,ffff:nqn=nqn.1986-03.com.ibm:nvme:2145.0000020420006CEA/namespace@ec +/pci@800000020000132/fibre-channel@0,1/nvme-of/controller@50050768101935e5,ffff:nqn=nqn.1986-03.com.ibm:nvme:2145.0000020420006CEA/namespace@ec + +Signed-off-by: Wen Xiong +--- + grub-core/osdep/linux/ofpath.c | 6 ++--- + grub-core/osdep/unix/platform.c | 48 +++++++++++++++++++++++++++++++++ + include/grub/util/install.h | 3 +++ + include/grub/util/ofpath.h | 9 +++++++ + 4 files changed, 63 insertions(+), 3 deletions(-) + +diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c +index 7d31cfd0f..7129099db 100644 +--- a/grub-core/osdep/linux/ofpath.c ++++ b/grub-core/osdep/linux/ofpath.c +@@ -209,7 +209,7 @@ find_obppath (const char *sysfs_path_orig) + } + } + +-static char * ++char * + xrealpath (const char *in) + { + char *out; +@@ -224,7 +224,7 @@ xrealpath (const char *in) + return out; + } + +-static char * ++char * + block_device_get_sysfs_path_and_link(const char *devicenode) + { + char *rpath; +@@ -535,7 +535,7 @@ of_path_get_nvme_nsid(const char* devname) + + } + +-static char * ++char * + nvme_get_syspath(const char *nvmedev) + { + char *sysfs_path, *controller_node; +diff --git a/grub-core/osdep/unix/platform.c b/grub-core/osdep/unix/platform.c +index 1e2961e00..db8fa4b95 100644 +--- a/grub-core/osdep/unix/platform.c ++++ b/grub-core/osdep/unix/platform.c +@@ -19,6 +19,7 @@ + #include + + #include ++#include + #include + #include + #include +@@ -131,6 +132,51 @@ grub_install_remove_efi_entries_by_distributor (const char *efi_distributor) + return rc; + } + ++char * ++build_multi_boot_device(const char *install_device) ++{ ++ char *sysfs_path; ++ char *nvme_ns; ++ unsigned int nsid; ++ char *ptr; ++ char *boot_device_string; ++ struct dirent *ep; ++ DIR *dp; ++ ++ nvme_ns = strchr(install_device, 'n'); ++ nsid = of_path_get_nvme_nsid(nvme_ns); ++ sysfs_path = nvme_get_syspath(nvme_ns); ++ strcat(sysfs_path, "/device"); ++ sysfs_path = xrealpath(sysfs_path); ++ ++ dp = opendir(sysfs_path); ++ ptr = boot_device_string = xmalloc (1000); ++ ++ /* We cannot have a boot list with more than five entries */ ++ while((ep = readdir(dp)) != NULL){ ++ char *nvme_device; ++ ++ if (grub_strstr(ep->d_name, "nvme")) { ++ nvme_device = xasprintf ("%s%s%x ", ++ get_ofpathname(ep->d_name),"/namespace@", nsid); ++ if ((strlen(boot_device_string) + strlen(nvme_device)) >= 200*5 - 1) { ++ grub_util_warn (_("More than five entries cannot be specified in the bootlist")); ++ free(nvme_device); ++ break; ++ } ++ ++ strncpy(ptr, nvme_device, strlen(nvme_device)); ++ ptr += strlen(nvme_device); ++ free(nvme_device); ++ } ++ } ++ ++ *--ptr = '\0'; ++ closedir(dp); ++ ++ return boot_device_string; ++} ++ + int + grub_install_register_efi (const grub_disk_t *efidir_grub_disk, + const char *efifile_path, +@@ -242,6 +288,8 @@ grub_install_register_ieee1275 (int is_prep, const char *install_device, + } + *ptr = '\0'; + } ++ else if (grub_strstr(install_device, "nvme")) ++ boot_device = build_multi_boot_device(install_device); + else + boot_device = get_ofpathname (install_device); + +diff --git a/include/grub/util/install.h b/include/grub/util/install.h +index c144f3e4d..15f24efac 100644 +--- a/include/grub/util/install.h ++++ b/include/grub/util/install.h +@@ -240,6 +240,9 @@ grub_install_register_efi (const grub_disk_t *efidir_grub_disk, + const char *efi_distributor, + const char *force_disk); + ++char * ++build_multi_boot_device(const char *install_device); ++ + void + grub_install_register_ieee1275 (int is_prep, const char *install_device, + int partno, const char *relpath); +diff --git a/include/grub/util/ofpath.h b/include/grub/util/ofpath.h +index a0ec30620..5b1f6a56d 100644 +--- a/include/grub/util/ofpath.h ++++ b/include/grub/util/ofpath.h +@@ -32,4 +32,13 @@ void find_file(char* filename, char* directory, struct ofpath_files_list_root* r + + char* of_find_fc_host(char* host_wwpn); + ++char* nvme_get_syspath(const char *nvmedev); ++ ++char* block_device_get_sysfs_path_and_link(const char *devicenode); ++ ++char* xrealpath (const char *in); ++ ++unsigned int of_path_get_nvme_nsid(const char* devname); ++ ++ + #endif /* ! GRUB_OFPATH_MACHINE_UTIL_HEADER */ +-- +2.35.3 + diff --git a/0001-i386-pc-build-btrfs-zstd-support-into-separate-modul.patch b/0001-i386-pc-build-btrfs-zstd-support-into-separate-modul.patch new file mode 100644 index 0000000..1177ff9 --- /dev/null +++ b/0001-i386-pc-build-btrfs-zstd-support-into-separate-modul.patch @@ -0,0 +1,550 @@ +From e7fe15db1736e038a7705973424708d3151fde99 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Thu, 12 Aug 2021 21:43:22 +0800 +Subject: [PATCH] i386-pc: build btrfs zstd support into separate module + +The zstd support in btrfs brings significant size increment to the +on-disk image that it can no longer fit into btrfs bootloader area and +short mbr gap. + +In order to support grub update on outstanding i386-pc setup with these +size constraints remain in place, here we build the zstd suppprt of +btrfs into a separate module, named btrfs_zstd, to alleviate the size +change. Please note this only makes it's way to i386-pc, other +architecture is not affected. + +Therefore if the system has enough space of embedding area for grub then +zstd support for btrfs will be enabled automatically in the process of +running grub-install through inserting btrfs_zstd module to the on-disk +image, otherwise a warning will be logged on screen to indicate user +that zstd support for btrfs is disabled due to the size limit. + +Signed-off-by: Michael Chang +--- + Makefile.util.def | 1 + + grub-core/Makefile.core.def | 11 ++++ + grub-core/fs/btrfs.c | 114 +++++--------------------------- + grub-core/fs/btrfs_zstd.c | 36 +++++++++++ + grub-core/lib/zstd.c | 126 ++++++++++++++++++++++++++++++++++++ + include/grub/btrfs.h | 6 ++ + include/grub/lib/zstd.h | 26 ++++++++ + include/grub/util/install.h | 2 + + util/grub-install.c | 20 ++++++ + util/setup.c | 43 ++++++++++++ + 10 files changed, 288 insertions(+), 97 deletions(-) + create mode 100644 grub-core/fs/btrfs_zstd.c + create mode 100644 grub-core/lib/zstd.c + create mode 100644 include/grub/lib/zstd.h + +diff --git a/Makefile.util.def b/Makefile.util.def +index 2f2881cb7..ac2b6aab1 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -176,6 +176,7 @@ library = { + common = grub-core/lib/zstd/xxhash.c; + common = grub-core/lib/zstd/zstd_common.c; + common = grub-core/lib/zstd/zstd_decompress.c; ++ common = grub-core/lib/zstd.c; + }; + + program = { +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index dd1777bd3..b5328d7a0 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -1370,10 +1370,21 @@ module = { + name = btrfs; + common = fs/btrfs.c; + common = lib/crc.c; ++ nopc = lib/zstd.c; + cflags = '$(CFLAGS_POSIX) -Wno-undef'; ++ i386_pc_cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/minilzo -DMINILZO_HAVE_CONFIG_H'; + cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/minilzo -I$(srcdir)/lib/zstd -DMINILZO_HAVE_CONFIG_H'; + }; + ++module = { ++ name = btrfs_zstd; ++ common = fs/btrfs_zstd.c; ++ common = lib/zstd.c; ++ cflags = '$(CFLAGS_POSIX) -Wno-undef'; ++ cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/zstd'; ++ enable = i386_pc; ++}; ++ + module = { + name = archelp; + common = fs/archelp.c; +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index c908b460f..9625bdf16 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -17,14 +17,6 @@ + * along with GRUB. If not, see . + */ + +-/* +- * Tell zstd to expose functions that aren't part of the stable API, which +- * aren't safe to use when linking against a dynamic library. We vendor in a +- * specific zstd version, so we know what we're getting. We need these unstable +- * functions to provide our own allocator, which uses grub_malloc(), to zstd. +- */ +-#define ZSTD_STATIC_LINKING_ONLY +- + #include + #include + #include +@@ -35,7 +27,9 @@ + #include + #include + #include +-#include ++#ifndef GRUB_MACHINE_PCBIOS ++#include ++#endif + #include + #include + #include +@@ -61,12 +55,15 @@ GRUB_MOD_LICENSE ("GPLv3+"); + #define GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE (GRUB_BTRFS_LZO_BLOCK_SIZE + \ + (GRUB_BTRFS_LZO_BLOCK_SIZE / 16) + 64 + 3) + +-#define ZSTD_BTRFS_MAX_WINDOWLOG 17 +-#define ZSTD_BTRFS_MAX_INPUT (1 << ZSTD_BTRFS_MAX_WINDOWLOG) +- + typedef grub_uint8_t grub_btrfs_checksum_t[0x20]; + typedef grub_uint16_t grub_btrfs_uuid_t[8]; + ++#ifdef GRUB_MACHINE_PCBIOS ++grub_ssize_t (*grub_btrfs_zstd_decompress_func) (char *ibuf, ++ grub_size_t isize, grub_off_t off, ++ char *obuf, grub_size_t osize) = NULL; ++#endif ++ + struct grub_btrfs_device + { + grub_uint64_t device_id; +@@ -1392,94 +1389,17 @@ grub_btrfs_read_inode (struct grub_btrfs_data *data, + return grub_btrfs_read_logical (data, elemaddr, inode, sizeof (*inode), 0); + } + +-static void *grub_zstd_malloc (void *state __attribute__((unused)), size_t size) +-{ +- return grub_malloc (size); +-} +- +-static void grub_zstd_free (void *state __attribute__((unused)), void *address) +-{ +- return grub_free (address); +-} +- +-static ZSTD_customMem grub_zstd_allocator (void) +-{ +- ZSTD_customMem allocator; +- +- allocator.customAlloc = &grub_zstd_malloc; +- allocator.customFree = &grub_zstd_free; +- allocator.opaque = NULL; +- +- return allocator; +-} +- +-static grub_ssize_t ++static inline grub_ssize_t + grub_btrfs_zstd_decompress (char *ibuf, grub_size_t isize, grub_off_t off, + char *obuf, grub_size_t osize) + { +- void *allocated = NULL; +- char *otmpbuf = obuf; +- grub_size_t otmpsize = osize; +- ZSTD_DCtx *dctx = NULL; +- grub_size_t zstd_ret; +- grub_ssize_t ret = -1; +- +- /* +- * Zstd will fail if it can't fit the entire output in the destination +- * buffer, so if osize isn't large enough, allocate a temporary buffer. +- */ +- if (otmpsize < ZSTD_BTRFS_MAX_INPUT) +- { +- allocated = grub_malloc (ZSTD_BTRFS_MAX_INPUT); +- if (!allocated) +- { +- grub_error (GRUB_ERR_OUT_OF_MEMORY, "failed allocate a zstd buffer"); +- goto err; +- } +- otmpbuf = (char *) allocated; +- otmpsize = ZSTD_BTRFS_MAX_INPUT; +- } +- +- /* Create the ZSTD_DCtx. */ +- dctx = ZSTD_createDCtx_advanced (grub_zstd_allocator ()); +- if (!dctx) +- { +- /* ZSTD_createDCtx_advanced() only fails if it is out of memory. */ +- grub_error (GRUB_ERR_OUT_OF_MEMORY, "failed to create a zstd context"); +- goto err; +- } +- +- /* +- * Get the real input size, there may be junk at the +- * end of the frame. +- */ +- isize = ZSTD_findFrameCompressedSize (ibuf, isize); +- if (ZSTD_isError (isize)) +- { +- grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "zstd data corrupted"); +- goto err; +- } +- +- /* Decompress and check for errors. */ +- zstd_ret = ZSTD_decompressDCtx (dctx, otmpbuf, otmpsize, ibuf, isize); +- if (ZSTD_isError (zstd_ret)) +- { +- grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "zstd data corrupted"); +- goto err; +- } +- +- /* +- * Move the requested data into the obuf. obuf may be equal +- * to otmpbuf, which is why grub_memmove() is required. +- */ +- grub_memmove (obuf, otmpbuf + off, osize); +- ret = osize; +- +-err: +- grub_free (allocated); +- ZSTD_freeDCtx (dctx); +- +- return ret; ++#ifdef GRUB_MACHINE_PCBIOS ++ if (!grub_btrfs_zstd_decompress_func) ++ return -1; ++ return grub_btrfs_zstd_decompress_func (ibuf, isize, off, obuf, osize); ++#else ++ return grub_zstd_decompress (ibuf, isize, off, obuf, osize); ++#endif + } + + static grub_ssize_t +diff --git a/grub-core/fs/btrfs_zstd.c b/grub-core/fs/btrfs_zstd.c +new file mode 100644 +index 000000000..d5d1e013c +--- /dev/null ++++ b/grub-core/fs/btrfs_zstd.c +@@ -0,0 +1,36 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2008 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 . ++ */ ++ ++#include ++#include ++/* For NULL. */ ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++GRUB_MOD_INIT (btrfs_zstd) ++{ ++ grub_btrfs_zstd_decompress_func = grub_zstd_decompress; ++} ++ ++GRUB_MOD_FINI (btrfs_zstd) ++{ ++ grub_btrfs_zstd_decompress_func = NULL; ++} +diff --git a/grub-core/lib/zstd.c b/grub-core/lib/zstd.c +new file mode 100644 +index 000000000..643e90d84 +--- /dev/null ++++ b/grub-core/lib/zstd.c +@@ -0,0 +1,126 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2008 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 . ++ */ ++ ++/* ++ * Tell zstd to expose functions that aren't part of the stable API, which ++ * aren't safe to use when linking against a dynamic library. We vendor in a ++ * specific zstd version, so we know what we're getting. We need these unstable ++ * functions to provide our own allocator, which uses grub_malloc(), to zstd. ++ */ ++#define ZSTD_STATIC_LINKING_ONLY ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define ZSTD_MAX_WINDOWLOG 17 ++#define ZSTD_MAX_INPUT (1 << ZSTD_MAX_WINDOWLOG) ++ ++static void *grub_zstd_malloc (void *state __attribute__((unused)), size_t size) ++{ ++ return grub_malloc (size); ++} ++ ++static void grub_zstd_free (void *state __attribute__((unused)), void *address) ++{ ++ return grub_free (address); ++} ++ ++static ZSTD_customMem grub_zstd_allocator (void) ++{ ++ ZSTD_customMem allocator; ++ ++ allocator.customAlloc = &grub_zstd_malloc; ++ allocator.customFree = &grub_zstd_free; ++ allocator.opaque = NULL; ++ ++ return allocator; ++} ++ ++grub_ssize_t ++grub_zstd_decompress (char *ibuf, grub_size_t isize, grub_off_t off, ++ char *obuf, grub_size_t osize) ++{ ++ void *allocated = NULL; ++ char *otmpbuf = obuf; ++ grub_size_t otmpsize = osize; ++ ZSTD_DCtx *dctx = NULL; ++ grub_size_t zstd_ret; ++ grub_ssize_t ret = -1; ++ ++ /* ++ * Zstd will fail if it can't fit the entire output in the destination ++ * buffer, so if osize isn't large enough, allocate a temporary buffer. ++ */ ++ if (otmpsize < ZSTD_MAX_INPUT) ++ { ++ allocated = grub_malloc (ZSTD_MAX_INPUT); ++ if (!allocated) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, "failed allocate a zstd buffer"); ++ goto err; ++ } ++ otmpbuf = (char *) allocated; ++ otmpsize = ZSTD_MAX_INPUT; ++ } ++ ++ /* Create the ZSTD_DCtx. */ ++ dctx = ZSTD_createDCtx_advanced (grub_zstd_allocator ()); ++ if (!dctx) ++ { ++ /* ZSTD_createDCtx_advanced() only fails if it is out of memory. */ ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, "failed to create a zstd context"); ++ goto err; ++ } ++ ++ /* ++ * Get the real input size, there may be junk at the ++ * end of the frame. ++ */ ++ isize = ZSTD_findFrameCompressedSize (ibuf, isize); ++ if (ZSTD_isError (isize)) ++ { ++ grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "zstd data corrupted"); ++ goto err; ++ } ++ ++ /* Decompress and check for errors. */ ++ zstd_ret = ZSTD_decompressDCtx (dctx, otmpbuf, otmpsize, ibuf, isize); ++ if (ZSTD_isError (zstd_ret)) ++ { ++ grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "zstd data corrupted"); ++ goto err; ++ } ++ ++ /* ++ * Move the requested data into the obuf. obuf may be equal ++ * to otmpbuf, which is why grub_memmove() is required. ++ */ ++ grub_memmove (obuf, otmpbuf + off, osize); ++ ret = osize; ++ ++err: ++ grub_free (allocated); ++ ZSTD_freeDCtx (dctx); ++ ++ return ret; ++} ++ +diff --git a/include/grub/btrfs.h b/include/grub/btrfs.h +index 234ad9767..f8e551982 100644 +--- a/include/grub/btrfs.h ++++ b/include/grub/btrfs.h +@@ -69,4 +69,10 @@ struct grub_btrfs_inode_ref + char name[0]; + }; + ++#ifdef GRUB_MACHINE_PCBIOS ++extern grub_ssize_t (*EXPORT_VAR (grub_btrfs_zstd_decompress_func)) (char *ibuf, ++ grub_size_t isize, grub_off_t off, ++ char *obuf, grub_size_t osize); ++#endif ++ + #endif +diff --git a/include/grub/lib/zstd.h b/include/grub/lib/zstd.h +new file mode 100644 +index 000000000..0867b0c34 +--- /dev/null ++++ b/include/grub/lib/zstd.h +@@ -0,0 +1,26 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2008 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 . ++ */ ++ ++#ifndef GRUB_ZSTD_HEADER ++#define GRUB_ZSTD_HEADER 1 ++ ++grub_ssize_t ++grub_zstd_decompress (char *ibuf, grub_size_t isize, grub_off_t off, ++ char *obuf, grub_size_t osize); ++ ++#endif /* ! GRUB_ZSTD_HEADER */ +diff --git a/include/grub/util/install.h b/include/grub/util/install.h +index faf9ff1ab..9e83e1339 100644 +--- a/include/grub/util/install.h ++++ b/include/grub/util/install.h +@@ -208,6 +208,8 @@ grub_util_sparc_setup (const char *dir, + const char *dest, int force, + int fs_probe, int allow_floppy, + int add_rs_codes, int warn_short_mbr_gap); ++int ++grub_util_try_partmap_embed (const char *dest, unsigned int *nsec); + + char * + grub_install_get_image_targets_string (void); +diff --git a/util/grub-install.c b/util/grub-install.c +index 891e3ced8..a2286b3dd 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -1482,6 +1482,26 @@ main (int argc, char *argv[]) + } + } + ++ if (install_drive ++ && platform == GRUB_INSTALL_PLATFORM_I386_PC ++ && grub_strcmp (grub_fs->name, "btrfs") == 0) ++ { ++ char *mod; ++ mod = grub_util_path_concat (2, grub_install_source_directory, "btrfs_zstd.mod"); ++ if (grub_util_is_regular (mod)) ++ { ++ unsigned int nsec = GRUB_MIN_RECOMMENDED_MBR_GAP; ++ int ret = grub_util_try_partmap_embed (install_drive, &nsec); ++ if (ret == 0) ++ grub_install_push_module ("btrfs_zstd"); ++ else if (ret == 1) ++ grub_util_warn ("%s", _("btrfs zstd compression is disabled, please change install device to disk")); ++ else ++ grub_util_warn ("%s", _("btrfs zstd compression is disabled due to not enough space to embed image")); ++ } ++ grub_free (mod); ++ } ++ + if (!have_abstractions) + { + if ((disk_module && grub_strcmp (disk_module, "biosdisk") != 0) +diff --git a/util/setup.c b/util/setup.c +index 980e74374..6604d86bb 100644 +--- a/util/setup.c ++++ b/util/setup.c +@@ -241,6 +241,49 @@ identify_partmap (grub_disk_t disk __attribute__ ((unused)), + return 1; + } + ++#ifdef GRUB_SETUP_BIOS ++int ++grub_util_try_partmap_embed (const char *dest, unsigned int *nsec) ++{ ++ grub_device_t dest_dev; ++ ++ dest_dev = grub_device_open (dest); ++ if (! dest_dev) ++ grub_util_error ("%s", grub_errmsg); ++ ++ struct identify_partmap_ctx ctx = { ++ .dest_partmap = NULL, ++ .container = dest_dev->disk->partition, ++ .multiple_partmaps = 0 ++ }; ++ ++ grub_partition_iterate (dest_dev->disk, identify_partmap, &ctx); ++ ++ if (ctx.dest_partmap && ctx.dest_partmap->embed) ++ { ++ grub_err_t err; ++ ++ grub_disk_addr_t *sectors = NULL; ++ ++ err = ctx.dest_partmap->embed (dest_dev->disk, nsec, *nsec, ++ GRUB_EMBED_PCBIOS, §ors, 0); ++ if (err) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ goto no_embed; ++ } ++ grub_free (sectors); ++ return 0; ++ } ++ ++no_embed: ++ grub_device_close (dest_dev); ++ if (ctx.container) ++ return 1; ++ return 2; ++} ++#endif ++ + #ifdef GRUB_SETUP_BIOS + #define SETUP grub_util_bios_setup + #elif GRUB_SETUP_SPARC64 +-- +2.31.1 + diff --git a/0001-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch b/0001-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch new file mode 100644 index 0000000..7249e18 --- /dev/null +++ b/0001-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch @@ -0,0 +1,239 @@ +From 0d672e351e8fab646472aec174a587ddfda4dd1e Mon Sep 17 00:00:00 2001 +From: Stefan Berger +Date: Sun, 15 Mar 2020 12:37:10 -0400 +Subject: [PATCH 1/2] ibmvtpm: Add support for trusted boot using a vTPM 2.0 + +Add support for trusted boot using a vTPM 2.0 on the IBM IEEE1275 +PowerPC platform. With this patch grub now measures text and binary data +into the TPM's PCRs 8 and 9 in the same way as the x86_64 platform +does. + +This patch requires Daniel Axtens's patches for claiming more memory. + +For vTPM support to work on PowerVM, system driver levels 1010.30 +or 1020.00 are required. + +Note: Previous versions of firmware levels with the 2hash-ext-log +API call have a bug that, once this API call is invoked, has the +effect of disabling the vTPM driver under Linux causing an error +message to be displayed in the Linux kernel log. Those users will +have to update their machines to the firmware levels mentioned +above. + +Cc: Eric Snowberg +Signed-off-by: Stefan Berger +--- + docs/grub.texi | 3 +- + grub-core/Makefile.core.def | 7 ++ + grub-core/commands/ieee1275/ibmvtpm.c | 152 ++++++++++++++++++++++++++ + include/grub/ieee1275/ieee1275.h | 3 + + 4 files changed, 164 insertions(+), 1 deletion(-) + create mode 100644 grub-core/commands/ieee1275/ibmvtpm.c + +diff --git a/docs/grub.texi b/docs/grub.texi +index 4504bcabe..026aacacf 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -6204,7 +6204,8 @@ tpm module is loaded. As such it is recommended that the tpm module be built + into @file{core.img} in order to avoid a potential gap in measurement between + @file{core.img} being loaded and the tpm module being loaded. + +-Measured boot is currently only supported on EFI platforms. ++Measured boot is currently only supported on EFI and IBM IEEE1275 PowerPC ++platforms. + + @node Lockdown + @section Lockdown when booting on a secure setup +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index ae6f7698b..01ff5c1e0 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -1140,6 +1140,13 @@ module = { + enable = powerpc_ieee1275; + }; + ++module = { ++ name = tpm; ++ common = commands/tpm.c; ++ ieee1275 = commands/ieee1275/ibmvtpm.c; ++ enable = powerpc_ieee1275; ++}; ++ + module = { + name = terminal; + common = commands/terminal.c; +diff --git a/grub-core/commands/ieee1275/ibmvtpm.c b/grub-core/commands/ieee1275/ibmvtpm.c +new file mode 100644 +index 000000000..e68b8448b +--- /dev/null ++++ b/grub-core/commands/ieee1275/ibmvtpm.c +@@ -0,0 +1,152 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2021 Free Software Foundation, Inc. ++ * Copyright (C) 2021 IBM Corporation ++ * ++ * 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 . ++ * ++ * IBM vTPM support code. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static grub_ieee1275_ihandle_t tpm_ihandle; ++static grub_uint8_t tpm_version; ++ ++#define IEEE1275_IHANDLE_INVALID ((grub_ieee1275_ihandle_t)0) ++ ++static void ++tpm_get_tpm_version (void) ++{ ++ grub_ieee1275_phandle_t vtpm; ++ char buffer[20]; ++ ++ if (!grub_ieee1275_finddevice ("/vdevice/vtpm", &vtpm) && ++ !grub_ieee1275_get_property (vtpm, "compatible", buffer, ++ sizeof (buffer), NULL) && ++ !grub_strcmp (buffer, "IBM,vtpm20")) ++ tpm_version = 2; ++} ++ ++static grub_err_t ++tpm_init (void) ++{ ++ static int init_success = 0; ++ ++ if (!init_success) ++ { ++ if (grub_ieee1275_open ("/vdevice/vtpm", &tpm_ihandle) < 0) { ++ tpm_ihandle = IEEE1275_IHANDLE_INVALID; ++ return GRUB_ERR_UNKNOWN_DEVICE; ++ } ++ ++ init_success = 1; ++ ++ tpm_get_tpm_version (); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static int ++ibmvtpm_2hash_ext_log (grub_uint8_t pcrindex, ++ grub_uint32_t eventtype, ++ const char *description, ++ grub_size_t description_size, ++ void *buf, grub_size_t size) ++{ ++ struct tpm_2hash_ext_log ++ { ++ struct grub_ieee1275_common_hdr common; ++ grub_ieee1275_cell_t method; ++ grub_ieee1275_cell_t ihandle; ++ grub_ieee1275_cell_t size; ++ grub_ieee1275_cell_t buf; ++ grub_ieee1275_cell_t description_size; ++ grub_ieee1275_cell_t description; ++ grub_ieee1275_cell_t eventtype; ++ grub_ieee1275_cell_t pcrindex; ++ grub_ieee1275_cell_t catch_result; ++ grub_ieee1275_cell_t rc; ++ } ++ args; ++ ++ INIT_IEEE1275_COMMON (&args.common, "call-method", 8, 2); ++ args.method = (grub_ieee1275_cell_t) "2hash-ext-log"; ++ args.ihandle = tpm_ihandle; ++ args.pcrindex = pcrindex; ++ args.eventtype = eventtype; ++ args.description = (grub_ieee1275_cell_t) description; ++ args.description_size = description_size; ++ args.buf = (grub_ieee1275_cell_t) buf; ++ args.size = (grub_ieee1275_cell_t) size; ++ ++ if (IEEE1275_CALL_ENTRY_FN (&args) == -1) ++ return -1; ++ ++ /* ++ * catch_result is set if firmware does not support 2hash-ext-log ++ * rc is GRUB_IEEE1275_CELL_FALSE (0) on failure ++ */ ++ if ((args.catch_result) || args.rc == GRUB_IEEE1275_CELL_FALSE) ++ return -1; ++ ++ return 0; ++} ++ ++static grub_err_t ++tpm2_log_event (unsigned char *buf, ++ grub_size_t size, grub_uint8_t pcr, ++ const char *description) ++{ ++ static int error_displayed = 0; ++ int err; ++ ++ err = ibmvtpm_2hash_ext_log (pcr, EV_IPL, ++ description, ++ grub_strlen(description) + 1, ++ buf, size); ++ if (err && !error_displayed) ++ { ++ error_displayed++; ++ return grub_error (GRUB_ERR_BAD_DEVICE, ++ "2HASH-EXT-LOG failed: Firmware is likely too old.\n"); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, ++ const char *description) ++{ ++ grub_err_t err = tpm_init(); ++ ++ /* Absence of a TPM isn't a failure. */ ++ if (err != GRUB_ERR_NONE) ++ return GRUB_ERR_NONE; ++ ++ grub_dprintf ("tpm", "log_event, pcr = %d, size = 0x%" PRIxGRUB_SIZE ", %s\n", ++ pcr, size, description); ++ ++ if (tpm_version == 2) ++ return tpm2_log_event (buf, size, pcr, description); ++ ++ return GRUB_ERR_NONE; ++} +diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h +index 591f4f12c..8a621af7c 100644 +--- a/include/grub/ieee1275/ieee1275.h ++++ b/include/grub/ieee1275/ieee1275.h +@@ -24,6 +24,9 @@ + #include + #include + ++#define GRUB_IEEE1275_CELL_FALSE ((grub_ieee1275_cell_t) 0) ++#define GRUB_IEEE1275_CELL_TRUE ((grub_ieee1275_cell_t) -1) ++ + struct grub_ieee1275_mem_region + { + unsigned int start; +-- +2.35.3 + diff --git a/0001-ieee1275-Avoiding-many-unecessary-open-close.patch b/0001-ieee1275-Avoiding-many-unecessary-open-close.patch new file mode 100644 index 0000000..48af1d5 --- /dev/null +++ b/0001-ieee1275-Avoiding-many-unecessary-open-close.patch @@ -0,0 +1,147 @@ +From e9d3202d5cffb89223ff61ac93de86a0cac1b50c Mon Sep 17 00:00:00 2001 +From: Diego Domingos +Date: Thu, 19 Nov 2020 10:47:25 -0300 +Subject: [PATCH] ieee1275: Avoiding many unecessary open/close + +This patch aims to change the grub_ofdisk_open and grub_ofdisk_close behaviors. Since some devices (Fibre Channel and NVMe) can have a long time for shutdown notification, we should avoid open and close the disks as much as we can. + +So, we are changing how those functions works. The grub_ofdisk_close will take care of just changing the disk element status, by doing a soft close, i.e, the firmware will not be called. On the other hand, the grub_ofdisk_open will take care of closing the current disk opened only if the disk requested in the current call is different from the current one. This close will be responsible to request the firmware to actually close the disk. + +Yet, this patch modifies the grub_ofdisk_get_block_size function, avoiding open and close calls inside of it. + +Thank you Michael Chang (mchang@suse.com) for all support. + +Signed-off-by: Diego Domingos +--- + grub-core/disk/ieee1275/ofdisk.c | 64 +++++++++++++++++--------------- + 1 file changed, 35 insertions(+), 29 deletions(-) + +diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c +index 03674cb47..ea7f78ac7 100644 +--- a/grub-core/disk/ieee1275/ofdisk.c ++++ b/grub-core/disk/ieee1275/ofdisk.c +@@ -44,7 +44,7 @@ struct ofdisk_hash_ent + }; + + static grub_err_t +-grub_ofdisk_get_block_size (const char *device, grub_uint32_t *block_size, ++grub_ofdisk_get_block_size (grub_uint32_t *block_size, + struct ofdisk_hash_ent *op); + + #define OFDISK_HASH_SZ 8 +@@ -461,6 +461,7 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) + grub_ssize_t actual; + grub_uint32_t block_size = 0; + grub_err_t err; ++ struct ofdisk_hash_ent *op; + + if (grub_strncmp (name, "ieee1275/", sizeof ("ieee1275/") - 1) != 0) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, +@@ -471,6 +472,35 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) + + grub_dprintf ("disk", "Opening `%s'.\n", devpath); + ++ op = ofdisk_hash_find (devpath); ++ if (!op) ++ op = ofdisk_hash_add (devpath, NULL); ++ if (!op) ++ { ++ grub_free (devpath); ++ return grub_errno; ++ } ++ ++ /* Check if the call to open is the same to the last disk already opened */ ++ if (last_devpath && !grub_strcmp(op->open_path,last_devpath)) ++ { ++ goto finish; ++ } ++ ++ /* If not, we need to close the previous disk and open the new one */ ++ else { ++ if (last_ihandle){ ++ grub_ieee1275_close (last_ihandle); ++ } ++ last_ihandle = 0; ++ last_devpath = NULL; ++ ++ grub_ieee1275_open (op->open_path, &last_ihandle); ++ if (! last_ihandle) ++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); ++ last_devpath = op->open_path; ++ } ++ + if (grub_ieee1275_finddevice (devpath, &dev)) + { + grub_free (devpath); +@@ -491,25 +521,18 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a block device"); + } + ++ ++ finish: + /* XXX: There is no property to read the number of blocks. There + should be a property `#blocks', but it is not there. Perhaps it + is possible to use seek for this. */ + disk->total_sectors = GRUB_DISK_SIZE_UNKNOWN; + + { +- struct ofdisk_hash_ent *op; +- op = ofdisk_hash_find (devpath); +- if (!op) +- op = ofdisk_hash_add (devpath, NULL); +- if (!op) +- { +- grub_free (devpath); +- return grub_errno; +- } + disk->id = (unsigned long) op; + disk->data = op->open_path; + +- err = grub_ofdisk_get_block_size (devpath, &block_size, op); ++ err = grub_ofdisk_get_block_size (&block_size, op); + if (err) + { + grub_free (devpath); +@@ -532,13 +555,6 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) + static void + grub_ofdisk_close (grub_disk_t disk) + { +- if (disk->data == last_devpath) +- { +- if (last_ihandle) +- grub_ieee1275_close (last_ihandle); +- last_ihandle = 0; +- last_devpath = NULL; +- } + disk->data = 0; + } + +@@ -685,7 +701,7 @@ grub_ofdisk_init (void) + } + + static grub_err_t +-grub_ofdisk_get_block_size (const char *device, grub_uint32_t *block_size, ++grub_ofdisk_get_block_size (grub_uint32_t *block_size, + struct ofdisk_hash_ent *op) + { + struct size_args_ieee1275 +@@ -698,16 +714,6 @@ grub_ofdisk_get_block_size (const char *device, grub_uint32_t *block_size, + grub_ieee1275_cell_t size2; + } args_ieee1275; + +- if (last_ihandle) +- grub_ieee1275_close (last_ihandle); +- +- last_ihandle = 0; +- last_devpath = NULL; +- +- grub_ieee1275_open (device, &last_ihandle); +- if (! last_ihandle) +- return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); +- + *block_size = 0; + + if (op->block_size_fails >= 2) +-- +2.26.2 + diff --git a/0001-ieee1275-Drop-HEAP_MAX_ADDR-and-HEAP_MIN_SIZE-consta.patch b/0001-ieee1275-Drop-HEAP_MAX_ADDR-and-HEAP_MIN_SIZE-consta.patch new file mode 100644 index 0000000..f268fb3 --- /dev/null +++ b/0001-ieee1275-Drop-HEAP_MAX_ADDR-and-HEAP_MIN_SIZE-consta.patch @@ -0,0 +1,82 @@ +From 41589d37934c7e4c464a584939de0137af7a181b Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 20 Jul 2021 17:14:46 -0400 +Subject: [PATCH 01/23] ieee1275: Drop HEAP_MAX_ADDR and HEAP_MIN_SIZE + constants + +The HEAP_MAX_ADDR is confusing. Currently it is set to 32MB, except on +ieee1275 on x86, where it is 64MB. + +There is a comment which purports to explain it: + + /* If possible, we will avoid claiming heap above this address, because it + seems to cause relocation problems with OSes that link at 4 MiB */ + +This doesn't make a lot of sense when the constants are well above 4MB +already. It was not always this way. Prior to commit 7b5d0fe4440c +(Increase heap limit) in 2010, HEAP_MAX_SIZE and HEAP_MAX_ADDR were +indeed 4MB. However, when the constants were increased the comment was +left unchanged. + +It's been over a decade. It doesn't seem like we have problems with +claims over 4MB on powerpc or x86 ieee1275. The SPARC does things +completely differently and never used the constant. + +Drop the constant and the check. + +The only use of HEAP_MIN_SIZE was to potentially override the +HEAP_MAX_ADDR check. It is now unused. Remove it too. + +Signed-off-by: Daniel Axtens +Signed-off-by: Stefan Berger +Tested-by: Stefan Berger +Reviewed-by: Daniel Kiper +--- + grub-core/kern/ieee1275/init.c | 17 ----------------- + 1 file changed, 17 deletions(-) + +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index 1187492ae..c15d40e55 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -45,9 +45,6 @@ + #include + #endif + +-/* The minimal heap size we can live with. */ +-#define HEAP_MIN_SIZE (unsigned long) (2 * 1024 * 1024) +- + /* The maximum heap size we're going to claim */ + #ifdef __i386__ + #define HEAP_MAX_SIZE (unsigned long) (64 * 1024 * 1024) +@@ -55,14 +52,6 @@ + #define HEAP_MAX_SIZE (unsigned long) (32 * 1024 * 1024) + #endif + +-/* If possible, we will avoid claiming heap above this address, because it +- seems to cause relocation problems with OSes that link at 4 MiB */ +-#ifdef __i386__ +-#define HEAP_MAX_ADDR (unsigned long) (64 * 1024 * 1024) +-#else +-#define HEAP_MAX_ADDR (unsigned long) (32 * 1024 * 1024) +-#endif +- + extern char _start[]; + extern char _end[]; + +@@ -184,12 +173,6 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, + if (*total + len > HEAP_MAX_SIZE) + len = HEAP_MAX_SIZE - *total; + +- /* Avoid claiming anything above HEAP_MAX_ADDR, if possible. */ +- if ((addr < HEAP_MAX_ADDR) && /* if it's too late, don't bother */ +- (addr + len > HEAP_MAX_ADDR) && /* if it wasn't available anyway, don't bother */ +- (*total + (HEAP_MAX_ADDR - addr) > HEAP_MIN_SIZE)) /* only limit ourselves when we can afford to */ +- len = HEAP_MAX_ADDR - addr; +- + /* In theory, firmware should already prevent this from happening by not + listing our own image in /memory/available. The check below is intended + as a safeguard in case that doesn't happen. However, it doesn't protect +-- +2.31.1 + diff --git a/0001-ieee1275-Further-increase-initially-allocated-heap-f.patch b/0001-ieee1275-Further-increase-initially-allocated-heap-f.patch new file mode 100644 index 0000000..e62d740 --- /dev/null +++ b/0001-ieee1275-Further-increase-initially-allocated-heap-f.patch @@ -0,0 +1,46 @@ +From d44e0a892621a744e9a64e17ed5676470ef4f023 Mon Sep 17 00:00:00 2001 +From: Wen Xiong +Date: Mon, 20 Feb 2023 15:58:14 -0500 +Subject: [PATCH 1/2] ieee1275: Further increase initially allocated heap from + 1/3 to 1/2 + +The memory increase to 1/3 of 391MB (~127MB) was still insufficient +to boot the kernel and initrd of the SuSE distribution: + +initrd 2023-Jan-18 04:27 114.9M +linux 2023-Jan-17 05:23 45.9M + +Therefore, further increase the initially allocated heap to 1/2 +of 391MB to ~191MB, which now allows to boot the system from an +ISO. + +Signed-off-by: Stefan Berger +--- + grub-core/kern/ieee1275/init.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index 2a2409d45..e1dbff86a 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -47,7 +47,7 @@ + #include + + /* The maximum heap size we're going to claim. Not used by sparc. +- We allocate 1/3 of the available memory under 4G, up to this limit. */ ++ We allocate 1/2 of the available memory under 4G, up to this limit. */ + #ifdef __i386__ + #define HEAP_MAX_SIZE (unsigned long) (64 * 1024 * 1024) + #else // __powerpc__ +@@ -417,7 +417,7 @@ grub_claim_heap (void) + + grub_machine_mmap_iterate (heap_size, &total); + +- total = total / 3; ++ total = total / 2; + if (total > HEAP_MAX_SIZE) + total = HEAP_MAX_SIZE; + +-- +2.39.1 + diff --git a/0001-ieee1275-Increase-initially-allocated-heap-from-1-4-.patch b/0001-ieee1275-Increase-initially-allocated-heap-from-1-4-.patch new file mode 100644 index 0000000..d463c32 --- /dev/null +++ b/0001-ieee1275-Increase-initially-allocated-heap-from-1-4-.patch @@ -0,0 +1,49 @@ +From 41965e194599af42e77bcf2462bd9c0db2823b16 Mon Sep 17 00:00:00 2001 +From: Stefan Berger +Date: Tue, 1 Nov 2022 11:06:03 -0400 +Subject: [PATCH] ieee1275: Increase initially allocated heap from 1/4 to 1/3 + +The patch 'ieee1275: claim more memory' (commit 910676645d) states: + +"[...] This leaves us 381MB. 1/4 of 381MB is ~95MB. That should be enough +to verify a 30MB vmlinux and should eave plenty of space to load Linux +and the initrd." + +As it turns out the memory limit of ~95MB is insufficient for the FADUMP +use case as described here: + +https://bugzilla.redhat.com/show_bug.cgi?id=2139000#c1 + +Adjust the current memory limitation by increasing the allocation to +1/3 of 381 MB, so ~127MB. + +Signed-off-by: Stefan Berger +--- + grub-core/kern/ieee1275/init.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index 0bacc2348..f75a36493 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -47,7 +47,7 @@ + #include + + /* The maximum heap size we're going to claim. Not used by sparc. +- We allocate 1/4 of the available memory under 4G, up to this limit. */ ++ We allocate 1/3 of the available memory under 4G, up to this limit. */ + #ifdef __i386__ + #define HEAP_MAX_SIZE (unsigned long) (64 * 1024 * 1024) + #else // __powerpc__ +@@ -415,7 +415,7 @@ grub_claim_heap (void) + + grub_machine_mmap_iterate (heap_size, &total); + +- total = total / 4; ++ total = total / 3; + if (total > HEAP_MAX_SIZE) + total = HEAP_MAX_SIZE; + +-- +2.35.3 + diff --git a/0001-ieee1275-add-support-for-NVMeoFC.patch b/0001-ieee1275-add-support-for-NVMeoFC.patch new file mode 100644 index 0000000..3ce2a13 --- /dev/null +++ b/0001-ieee1275-add-support-for-NVMeoFC.patch @@ -0,0 +1,250 @@ +From 55d8d1273a5a8dd7ad03bfe2f042b496c1059f19 Mon Sep 17 00:00:00 2001 +From: Diego Domingos +Date: Tue, 15 Feb 2022 13:11:48 -0500 +Subject: [PATCH 1/4] ieee1275: add support for NVMeoFC + +Implements the functions to scan and discovery of NVMeoFC. +--- + grub-core/disk/ieee1275/ofdisk.c | 217 ++++++++++++++++++++++++++++++- + 1 file changed, 213 insertions(+), 4 deletions(-) + +diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c +index 410f4b849..852bb95be 100644 +--- a/grub-core/disk/ieee1275/ofdisk.c ++++ b/grub-core/disk/ieee1275/ofdisk.c +@@ -206,12 +206,10 @@ dev_iterate_real (const char *name, const char *path) + return; + } + ++ + static void +-dev_iterate (const struct grub_ieee1275_devalias *alias) ++dev_iterate_fcp_disks(const struct grub_ieee1275_devalias *alias) + { +- if (grub_strcmp (alias->type, "fcp") == 0) +- { +- + /* If we are dealing with fcp devices, we need + * to find the WWPNs and LUNs to iterate them */ + grub_ieee1275_ihandle_t ihandle; +@@ -323,6 +321,217 @@ dev_iterate (const struct grub_ieee1275_devalias *alias) + grub_free (buf); + return; + ++} ++ ++static void ++dev_iterate_fcp_nvmeof (const struct grub_ieee1275_devalias *alias) ++{ ++ ++ ++ char *bufptr; ++ grub_ieee1275_ihandle_t ihandle; ++ ++ ++ // Create the structs for the parameters passing to PFW ++ struct nvme_args_ ++ { ++ struct grub_ieee1275_common_hdr common; ++ grub_ieee1275_cell_t method; ++ grub_ieee1275_cell_t ihandle; ++ grub_ieee1275_cell_t catch_result; ++ grub_ieee1275_cell_t nentries; ++ grub_ieee1275_cell_t table; ++ } nvme_discovery_controllers_args, nvme_controllers_args, nvme_namespaces_args; ++ ++ ++ // Create the structs for the results from PFW ++ ++ struct discovery_controllers_table_struct_ ++ { ++ grub_uint64_t table[256]; ++ grub_uint32_t len; ++ } discovery_controllers_table; ++ ++ /* struct nvme_controllers_table_entry ++ * this the return of nvme-controllers method tables, containing: ++ * - 2-byte controller ID ++ * - 256-byte transport address string ++ * - 256-byte field containing null-terminated NVM subsystem NQN string up to 223 characters ++ */ ++ struct nvme_controllers_table_entry_ ++ { ++ grub_uint16_t id; ++ char wwpn[256]; ++ char nqn[256]; ++ }; ++ ++ struct nvme_controllers_table_entry_* nvme_controllers_table = grub_malloc(sizeof(struct nvme_controllers_table_entry_)*256); ++ ++ grub_uint32_t nvme_controllers_table_entries; ++ ++ struct nvme_controllers_table_entry_real ++ { ++ grub_uint16_t id; ++ char wwpn[256]; ++ char nqn[256]; ++ }; ++ ++ /* Allocate memory for building the NVMeoF path */ ++ char *buf = grub_malloc (grub_strlen (alias->path) + 512); ++ if (!buf) ++ { ++ grub_ieee1275_close(ihandle); ++ return; ++ } ++ ++ /* Copy the alias->path to buf so we can work with */ ++ bufptr = grub_stpcpy (buf, alias->path); ++ grub_snprintf (bufptr, 32, "/nvme-of"); ++ ++ /* ++ * Open the nvme-of layer ++ * Ex. /pci@bus/fibre-channel@@dev,func/nvme-of ++ */ ++ if(grub_ieee1275_open (buf, &ihandle)) ++ { ++ grub_dprintf("disk", "failed to open the disk while iterating FCP disk path=%s\n", buf); ++ return; ++ } ++ ++ /* ++ * Call to nvme-discovery-controllers method from the nvme-of layer ++ * to get a list of the NVMe discovery controllers per the binding ++ */ ++ ++ INIT_IEEE1275_COMMON (&nvme_discovery_controllers_args.common, "call-method", 2, 2); ++ nvme_discovery_controllers_args.method = (grub_ieee1275_cell_t) "nvme-discovery-controllers"; ++ nvme_discovery_controllers_args.ihandle = ihandle; ++ ++ if (IEEE1275_CALL_ENTRY_FN (&nvme_discovery_controllers_args) == -1) ++ { ++ grub_dprintf("disk", "failed to get the targets while iterating FCP disk path=%s\n", buf); ++ grub_ieee1275_close(ihandle); ++ return; ++ } ++ ++ /* After closing the device, the info is lost. So lets copy each buffer in the buffers table */ ++ ++ discovery_controllers_table.len = (grub_uint32_t) nvme_discovery_controllers_args.nentries; ++ ++ unsigned int i=0; ++ for(i = 0; i < discovery_controllers_table.len; i++){ ++ discovery_controllers_table.table[i] = ((grub_uint64_t*)nvme_discovery_controllers_args.table)[i]; ++ } ++ ++ grub_ieee1275_close(ihandle); ++ ++ grub_dprintf("ofdisk","NVMeoF: Found %d discovery controllers\n",discovery_controllers_table.len); ++ ++ /* For each nvme discovery controller */ ++ int current_buffer_index; ++ for(current_buffer_index = 0; current_buffer_index < (int) discovery_controllers_table.len; current_buffer_index++){ ++ ++ ++ grub_snprintf (bufptr, 64, "/nvme-of/controller@%" PRIxGRUB_UINT64_T ",ffff", ++ discovery_controllers_table.table[current_buffer_index]); ++ ++ grub_dprintf("ofdisk","nvmeof controller=%s\n",buf); ++ ++ if(grub_ieee1275_open (buf, &ihandle)) ++ { ++ grub_dprintf("ofdisk", "failed to open the disk while getting nvme-controllers path=%s\n", buf); ++ continue; ++ } ++ ++ ++ INIT_IEEE1275_COMMON (&nvme_controllers_args.common, "call-method", 2, 2); ++ nvme_controllers_args.method = (grub_ieee1275_cell_t) "nvme-controllers"; ++ nvme_controllers_args.ihandle = ihandle; ++ nvme_controllers_args.catch_result = 0; ++ ++ ++ if (IEEE1275_CALL_ENTRY_FN (&nvme_controllers_args) == -1) ++ { ++ grub_dprintf("ofdisk", "failed to get the nvme-controllers while iterating FCP disk path\n"); ++ grub_ieee1275_close(ihandle); ++ continue; ++ } ++ ++ ++ /* Copy the buffer list to nvme_controllers_table */ ++ nvme_controllers_table_entries = ((grub_uint32_t) nvme_controllers_args.nentries); ++ struct nvme_controllers_table_entry_* nvme_controllers_table_ = (struct nvme_controllers_table_entry_*) nvme_controllers_args.table; ++ ++ for(i = 0; i < nvme_controllers_table_entries; i++){ ++ nvme_controllers_table[i].id = (grub_uint16_t) nvme_controllers_table_[i].id; ++ grub_strcpy(nvme_controllers_table[i].wwpn, nvme_controllers_table_[i].wwpn); ++ grub_strcpy(nvme_controllers_table[i].nqn, nvme_controllers_table_[i].nqn); ++ } ++ ++ grub_ieee1275_close(ihandle); ++ ++ int nvme_controller_index; ++ int bufptr_pos2; ++ grub_dprintf("ofdisk","NVMeoF: found %d nvme controllers\n",(int) nvme_controllers_args.nentries); ++ ++ /* For each nvme controller */ ++ for(nvme_controller_index = 0; nvme_controller_index < (int) nvme_controllers_args.nentries; nvme_controller_index++){ ++ /* Open the nvme controller ++ * /pci@bus/fibre-channel@dev,func/nvme-of/controller@transport-addr,ctlr-id:nqn=tgt-subsystem-nqn ++ */ ++ ++ bufptr_pos2 = grub_snprintf (bufptr, 512, "/nvme-of/controller@%s,ffff:nqn=%s", ++ nvme_controllers_table[nvme_controller_index].wwpn, nvme_controllers_table[nvme_controller_index].nqn); ++ ++ grub_dprintf("ofdisk","NVMeoF: nvmeof controller=%s\n",buf); ++ ++ if(grub_ieee1275_open (buf, &ihandle)){ ++ grub_dprintf("ofdisk","failed to open the path=%s\n",buf); ++ continue; ++ } ++ ++ INIT_IEEE1275_COMMON (&nvme_namespaces_args.common, "call-method", 2, 2); ++ nvme_namespaces_args.method = (grub_ieee1275_cell_t) "get-namespace-list"; ++ nvme_namespaces_args.ihandle = ihandle; ++ nvme_namespaces_args.catch_result = 0; ++ ++ if (IEEE1275_CALL_ENTRY_FN (&nvme_namespaces_args) == -1) ++ { ++ grub_dprintf("ofdisk", "failed to get the nvme-namespace-list while iterating FCP disk path\n"); ++ grub_ieee1275_close(ihandle); ++ continue; ++ } ++ ++ grub_uint32_t *namespaces = (grub_uint32_t*) nvme_namespaces_args.table; ++ grub_dprintf("ofdisk","NVMeoF: found %d namespaces\n",(int)nvme_namespaces_args.nentries); ++ ++ grub_ieee1275_close(ihandle); ++ ++ grub_uint32_t namespace_index = 0; ++ for(namespace_index=0; namespace_index < nvme_namespaces_args.nentries; namespace_index++){ ++ grub_snprintf (bufptr+bufptr_pos2, 512, "/namespace@%"PRIxGRUB_UINT32_T,namespaces[namespace_index]); ++ grub_dprintf("ofdisk","NVMeoF: namespace=%s\n",buf); ++ dev_iterate_real(buf,buf); ++ } ++ ++ dev_iterate_real(buf,buf); ++ } ++ } ++ grub_free(buf); ++ return; ++} ++ ++static void ++dev_iterate (const struct grub_ieee1275_devalias *alias) ++{ ++ if (grub_strcmp (alias->type, "fcp") == 0) ++ { ++ // Iterate disks ++ dev_iterate_fcp_disks(alias); ++ ++ // Iterate NVMeoF ++ dev_iterate_fcp_nvmeof(alias); ++ + } + else if (grub_strcmp (alias->type, "vscsi") == 0) + { +-- +2.35.3 + diff --git a/0001-ieee1275-implement-FCP-methods-for-WWPN-and-LUNs.patch b/0001-ieee1275-implement-FCP-methods-for-WWPN-and-LUNs.patch new file mode 100644 index 0000000..28b9dbf --- /dev/null +++ b/0001-ieee1275-implement-FCP-methods-for-WWPN-and-LUNs.patch @@ -0,0 +1,146 @@ +From a37d0cc089edd66ab35f1a27b0da09dd2f02deb3 Mon Sep 17 00:00:00 2001 +From: Diego Domingos +Date: Mon, 24 Jun 2019 10:15:56 -0400 +Subject: [PATCH] ieee1275: implement FCP methods for WWPN and LUNs + +This patch enables the fcp-targets and fcp-luns methods which are +responsible to get WWPNs and LUNs for fibre channel devices. + +Those methods are specially necessary if the boot directory and grub +installation are in different FCP disks, allowing the dev_iterate() +to find the WWPNs and LUNs when called by searchfs.uuid tool. +--- + grub-core/disk/ieee1275/ofdisk.c | 117 ++++++++++++++++++++++++++++++- + 1 file changed, 116 insertions(+), 1 deletion(-) + +diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c +index ea7f78ac7..258a6e389 100644 +--- a/grub-core/disk/ieee1275/ofdisk.c ++++ b/grub-core/disk/ieee1275/ofdisk.c +@@ -209,7 +209,122 @@ dev_iterate_real (const char *name, const char *path) + static void + dev_iterate (const struct grub_ieee1275_devalias *alias) + { +- if (grub_strcmp (alias->type, "vscsi") == 0) ++ if (grub_strcmp (alias->type, "fcp") == 0) ++ { ++ ++ /* If we are dealing with fcp devices, we need ++ * to find the WWPNs and LUNs to iterate them */ ++ grub_ieee1275_ihandle_t ihandle; ++ grub_uint64_t *ptr_targets, *ptr_luns, k, l; ++ unsigned int i, j, pos; ++ char *buf, *bufptr; ++ ++ struct set_fcp_targets_args ++ { ++ struct grub_ieee1275_common_hdr common; ++ grub_ieee1275_cell_t method; ++ grub_ieee1275_cell_t ihandle; ++ grub_ieee1275_cell_t catch_result; ++ grub_ieee1275_cell_t nentries; ++ grub_ieee1275_cell_t table; ++ } args_targets; ++ ++ struct set_fcp_luns_args ++ { ++ struct grub_ieee1275_common_hdr common; ++ grub_ieee1275_cell_t method; ++ grub_ieee1275_cell_t ihandle; ++ grub_ieee1275_cell_t wwpn_h; ++ grub_ieee1275_cell_t wwpn_l; ++ grub_ieee1275_cell_t catch_result; ++ grub_ieee1275_cell_t nentries; ++ grub_ieee1275_cell_t table; ++ } args_luns; ++ ++ struct args_ret ++ { ++ grub_uint64_t addr; ++ grub_uint64_t len; ++ }; ++ ++ if(grub_ieee1275_open (alias->path, &ihandle)) ++ { ++ grub_dprintf("disk", "failed to open the disk while iterating FCP disk path=%s\n", alias->path); ++ return; ++ } ++ ++ /* Setup the fcp-targets method to call via pfw*/ ++ INIT_IEEE1275_COMMON (&args_targets.common, "call-method", 2, 3); ++ args_targets.method = (grub_ieee1275_cell_t) "fcp-targets"; ++ args_targets.ihandle = ihandle; ++ ++ /* Setup the fcp-luns method to call via pfw */ ++ INIT_IEEE1275_COMMON (&args_luns.common, "call-method", 4, 3); ++ args_luns.method = (grub_ieee1275_cell_t) "fcp-luns"; ++ args_luns.ihandle = ihandle; ++ ++ if (IEEE1275_CALL_ENTRY_FN (&args_targets) == -1) ++ { ++ grub_dprintf("disk", "failed to get the targets while iterating FCP disk path=%s\n", alias->path); ++ grub_ieee1275_close(ihandle); ++ return; ++ } ++ ++ buf = grub_malloc (grub_strlen (alias->path) + 32 + 32); ++ ++ if (!buf) ++ { ++ grub_ieee1275_close(ihandle); ++ return; ++ } ++ ++ bufptr = grub_stpcpy (buf, alias->path); ++ ++ /* Iterate over entries returned by pfw. Each entry contains a ++ * pointer to wwpn table and his length. */ ++ struct args_ret *targets_table = (struct args_ret *)(args_targets.table); ++ for (i=0; i< args_targets.nentries; i++) ++ { ++ ptr_targets = (grub_uint64_t*)(grub_uint32_t) targets_table[i].addr; ++ /* Iterate over all wwpns in given table */ ++ for(k=0;k> 32); ++ pos=grub_snprintf (bufptr, 32, "/disk@%" PRIxGRUB_UINT64_T, ++ *ptr_targets++); ++ /* Get the luns for given wwpn target */ ++ if (IEEE1275_CALL_ENTRY_FN (&args_luns) == -1) ++ { ++ grub_dprintf("disk", "failed to get the LUNS while iterating FCP disk path=%s\n", buf); ++ grub_ieee1275_close (ihandle); ++ grub_free (buf); ++ return; ++ } ++ ++ struct args_ret *luns_table = (struct args_ret *)(args_luns.table); ++ ++ /* Iterate over all LUNs */ ++ for(j=0;jtype, "vscsi") == 0) + { + static grub_ieee1275_ihandle_t ihandle; + struct set_color_args +-- +2.31.1 + diff --git a/0001-ieee1275-ofdisk-retry-on-open-and-read-failure.patch b/0001-ieee1275-ofdisk-retry-on-open-and-read-failure.patch new file mode 100644 index 0000000..4832692 --- /dev/null +++ b/0001-ieee1275-ofdisk-retry-on-open-and-read-failure.patch @@ -0,0 +1,172 @@ +From f4728ed5307b6be6377b7bdafcab55fd3676a761 Mon Sep 17 00:00:00 2001 +From: Mukesh Kumar Chaurasiya +Date: Mon, 17 Jul 2023 16:02:34 +0530 +Subject: [PATCH] ieee1275/ofdisk: retry on open and read failure + +Sometimes, when booting from a very busy SAN, the access to the +disk can fail and then grub will eventually drop to grub prompt. +This scenario is more frequent when deploying many machines at +the same time using the same SAN. +This patch aims to force the ofdisk module to retry the open or +read function for network disks excluding after it fails. We use +DEFAULT_RETRY_TIMEOUT, which is 15 seconds to specify the time it'll +retry to access the disk before it definitely fails. The timeout can be +changed by setting the environment variable ofdisk_retry_timeout. +If the environment variable fails to read, grub will consider the +default value of 15 seconds. + +Signed-off-by: Diego Domingos +Signed-off-by: Mukesh Kumar Chaurasiya +--- + docs/grub.texi | 8 ++++ + grub-core/disk/ieee1275/ofdisk.c | 80 +++++++++++++++++++++++++++++++- + 2 files changed, 86 insertions(+), 2 deletions(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index d3f0f6577..c8ebc083d 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -3315,6 +3315,7 @@ These variables have special meaning to GRUB. + * net_default_ip:: + * net_default_mac:: + * net_default_server:: ++* ofdisk_retry_timeout:: + * pager:: + * prefix:: + * pxe_blksize:: +@@ -3744,6 +3745,13 @@ The default is the value of @samp{color_normal} (@pxref{color_normal}). + @xref{Network}. + + ++@node ofdisk_retry_timeout ++@subsection ofdisk_retry_timeout ++ ++The time in seconds till which the grub will retry to open or read a disk in ++case of failure to do so. This value defaults to 15 seconds. ++ ++ + @node pager + @subsection pager + +diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c +index 7197d5401..f96bbb58c 100644 +--- a/grub-core/disk/ieee1275/ofdisk.c ++++ b/grub-core/disk/ieee1275/ofdisk.c +@@ -24,6 +24,9 @@ + #include + #include + #include ++#include ++ ++#define RETRY_DEFAULT_TIMEOUT 15 + + static char *last_devpath; + static grub_ieee1275_ihandle_t last_ihandle; +@@ -783,7 +786,7 @@ compute_dev_path (const char *name) + } + + static grub_err_t +-grub_ofdisk_open (const char *name, grub_disk_t disk) ++grub_ofdisk_open_real (const char *name, grub_disk_t disk) + { + grub_ieee1275_phandle_t dev; + char *devpath; +@@ -879,6 +882,56 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) + return 0; + } + ++static grub_uint64_t ++grub_ofdisk_disk_timeout (grub_disk_t disk) ++{ ++ grub_uint64_t retry; ++ const char *timeout = grub_env_get ("ofdisk_retry_timeout"); ++ ++ if (!(grub_strstr (disk->name, "fibre-channel@") || ++ grub_strstr (disk->name, "vfc-client")) || ++ grub_strstr(disk->name, "nvme-of")) ++ { ++ /* Do not retry in case of non network drives */ ++ return 0; ++ } ++ ++ if (timeout != NULL) ++ { ++ retry = grub_strtoul (timeout, 0, 10); ++ if (grub_errno != GRUB_ERR_NONE) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ return RETRY_DEFAULT_TIMEOUT; ++ } ++ if (retry) ++ return retry; ++ } ++ return RETRY_DEFAULT_TIMEOUT; ++} ++ ++static grub_err_t ++grub_ofdisk_open (const char *name, grub_disk_t disk) ++{ ++ grub_err_t err; ++ grub_uint64_t timeout = grub_get_time_ms () + (grub_ofdisk_disk_timeout (disk) * 1000); ++ _Bool cont; ++ do ++ { ++ err = grub_ofdisk_open_real (name, disk); ++ cont = grub_get_time_ms () < timeout; ++ if (err == GRUB_ERR_UNKNOWN_DEVICE && cont) ++ { ++ grub_dprintf ("ofdisk","Failed to open disk %s. Retrying...\n", name); ++ grub_errno = GRUB_ERR_NONE; ++ } ++ else ++ break; ++ grub_millisleep (1000); ++ } while (cont); ++ return err; ++} ++ + static void + grub_ofdisk_close (grub_disk_t disk) + { +@@ -915,7 +968,7 @@ grub_ofdisk_prepare (grub_disk_t disk, grub_disk_addr_t sector) + } + + static grub_err_t +-grub_ofdisk_read (grub_disk_t disk, grub_disk_addr_t sector, ++grub_ofdisk_read_real (grub_disk_t disk, grub_disk_addr_t sector, + grub_size_t size, char *buf) + { + grub_err_t err; +@@ -934,6 +987,29 @@ grub_ofdisk_read (grub_disk_t disk, grub_disk_addr_t sector, + return 0; + } + ++static grub_err_t ++grub_ofdisk_read (grub_disk_t disk, grub_disk_addr_t sector, ++ grub_size_t size, char *buf) ++{ ++ grub_err_t err; ++ grub_uint64_t timeout = grub_get_time_ms () + (grub_ofdisk_disk_timeout (disk) * 1000); ++ _Bool cont; ++ do ++ { ++ err = grub_ofdisk_read_real (disk, sector, size, buf); ++ cont = grub_get_time_ms () < timeout; ++ if (err == GRUB_ERR_UNKNOWN_DEVICE && cont) ++ { ++ grub_dprintf ("ofdisk","Failed to read disk %s. Retrying...\n", (char*)disk->data); ++ grub_errno = GRUB_ERR_NONE; ++ } ++ else ++ break; ++ grub_millisleep (1000); ++ } while (cont); ++ return err; ++} ++ + static grub_err_t + grub_ofdisk_write (grub_disk_t disk, grub_disk_addr_t sector, + grub_size_t size, const char *buf) +-- +2.41.0 + diff --git a/0001-ieee1275-powerpc-implements-fibre-channel-discovery-.patch b/0001-ieee1275-powerpc-implements-fibre-channel-discovery-.patch new file mode 100644 index 0000000..1eb3b5c --- /dev/null +++ b/0001-ieee1275-powerpc-implements-fibre-channel-discovery-.patch @@ -0,0 +1,90 @@ +From ca30b3c6fd8c848f510445316d0c4a8fca6061ba Mon Sep 17 00:00:00 2001 +From: Diego Domingos +Date: Wed, 24 Jun 2020 08:17:18 -0400 +Subject: [PATCH 1/2] ieee1275/powerpc: implements fibre channel discovery for + ofpathname + +grub-ofpathname doesn't work with fibre channel because there is no +function currently implemented for it. +This patch enables it by prividing a function that looks for the port +name, building the entire path for OF devices. +--- + grub-core/osdep/linux/ofpath.c | 48 ++++++++++++++++++++++++++++++++++ + 1 file changed, 48 insertions(+) + +diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c +index a6153d359..f2bc9fc5c 100644 +--- a/grub-core/osdep/linux/ofpath.c ++++ b/grub-core/osdep/linux/ofpath.c +@@ -399,6 +399,37 @@ of_path_of_nvme(const char *sys_devname __attribute__((unused)), + } + #endif + ++static void ++of_fc_port_name(const char *path, const char *subpath, char *port_name) ++{ ++ char *bname, *basepath, *p; ++ int fd; ++ ++ bname = xmalloc(sizeof(char)*150); ++ basepath = xmalloc(strlen(path)); ++ ++ /* Generate the path to get port name information from the drive */ ++ strncpy(basepath,path,subpath-path); ++ basepath[subpath-path-1] = '\0'; ++ p = get_basename(basepath); ++ snprintf(bname,sizeof(char)*150,"%s/fc_transport/%s/port_name",basepath,p); ++ ++ /* Read the information from the port name */ ++ fd = open (bname, O_RDONLY); ++ if (fd < 0) ++ grub_util_error (_("cannot open `%s': %s"), bname, strerror (errno)); ++ ++ if (read(fd,port_name,sizeof(char)*19) < 0) ++ grub_util_error (_("cannot read `%s': %s"), bname, strerror (errno)); ++ ++ sscanf(port_name,"0x%s",port_name); ++ ++ close(fd); ++ ++ free(bname); ++ free(basepath); ++} ++ + static int + vendor_is_ATA(const char *path) + { +@@ -577,6 +608,16 @@ of_path_of_scsi(const char *sys_devname __attribute__((unused)), const char *dev + digit_string = trailing_digits (device); + if (strncmp (of_path, "/vdevice/", sizeof ("/vdevice/") - 1) == 0) + { ++ if(strstr(of_path,"vfc-client")) ++ { ++ char * port_name = xmalloc(sizeof(char)*17); ++ of_fc_port_name(sysfs_path, p, port_name); ++ ++ snprintf(disk,sizeof(disk),"/%s@%s", disk_name, port_name); ++ free(port_name); ++ } ++ else ++ { + unsigned long id = 0x8000 | (tgt << 8) | (bus << 5) | lun; + if (*digit_string == '\0') + { +@@ -590,6 +631,13 @@ of_path_of_scsi(const char *sys_devname __attribute__((unused)), const char *dev + snprintf(disk, sizeof (disk), + "/%s@%04lx000000000000:%c", disk_name, id, 'a' + (part - 1)); + } ++ } ++ } else if (strstr(of_path,"fibre-channel")||(strstr(of_path,"vfc-client"))){ ++ char * port_name = xmalloc(sizeof(char)*17); ++ of_fc_port_name(sysfs_path, p, port_name); ++ ++ snprintf(disk,sizeof(disk),"/%s@%s", disk_name, port_name); ++ free(port_name); + } + else + { +-- +2.26.2 + diff --git a/0001-install-fix-software-raid1-on-esp.patch b/0001-install-fix-software-raid1-on-esp.patch new file mode 100644 index 0000000..5d3dede --- /dev/null +++ b/0001-install-fix-software-raid1-on-esp.patch @@ -0,0 +1,415 @@ +From 6444774dae24f439dae3b4bc8d73449d50f06240 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Thu, 31 Dec 2020 21:54:07 +0800 +Subject: [PATCH] install: fix software raid1 on esp + +While running grub-install on an efi system where efi system partition +is configured as mdadm software raid1, it fails with errors like this: + + grub2-install: info: copying `/boot/grub2/x86_64-efi/core.efi' -> `/boot/efi/EFI/opensuse/grubx64.efi'. + grub2-install: info: Registering with EFI: distributor = `opensuse', path = `\EFI\opensuse\grubx64.efi', ESP at mduuid/9182c46b9d469f79b48850b68f3371a5. + grub2-install: info: executing efibootmgr --version /dev/null. + grub2-install: info: executing modprobe -q efivars. + grub2-install: info: executing efibootmgr -c -d. + efibootmgr: option requires an argument -- 'd' + efibootmgr version 14 + usage: efibootmgr [options] + +This should work with mdadm raid1 with metadata 0.9 and 1.0 whose +superblocks are at the end of device. However +grub_install_register_efi() doesn't seem to work if the target is +multiple devices so that it errors out. + +The patch changes grub_install_register_efi() to accept multiple devices +that can be used to creating efi boot entries for probed raid1 member +devices on mounted efi system partition. + +This patch also adds check for metadata 0.9 or 1.0 or the validation +will fail to continue the install. + +Signed-off-by: Michael Chang +--- + grub-core/disk/diskfilter.c | 27 +++---- + grub-core/disk/mdraid1x_linux.c | 3 + + grub-core/osdep/basic/no_platform.c | 3 +- + grub-core/osdep/unix/platform.c | 57 +++++++++++---- + grub-core/osdep/windows/platform.c | 3 +- + include/grub/diskfilter.h | 3 +- + include/grub/util/install.h | 5 +- + util/grub-install.c | 107 ++++++++++++++++++++++++++-- + 8 files changed, 171 insertions(+), 37 deletions(-) + +diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c +index 39d74cb867..de0c02cf94 100644 +--- a/grub-core/disk/diskfilter.c ++++ b/grub-core/disk/diskfilter.c +@@ -159,8 +159,8 @@ scan_disk_partition_iter (grub_disk_t disk, grub_partition_t p, void *data) + for (m = arr->pvs; m; m = m->next) + if (m->disk && m->disk->id == disk->id + && m->disk->dev->id == disk->dev->id +- && m->part_start == grub_partition_get_start (disk->partition) +- && m->part_size == grub_disk_native_sectors (disk)) ++ && grub_partition_get_start (m->disk->partition) == grub_partition_get_start (disk->partition) ++ && grub_disk_native_sectors (m->disk) == grub_disk_native_sectors (disk)) + return 0; + } + +@@ -1330,19 +1330,23 @@ insert_array (grub_disk_t disk, const struct grub_diskfilter_pv_id *id, + ? (grub_memcmp (pv->id.uuid, id->uuid, id->uuidlen) == 0) + : (pv->id.id == id->id)) + { ++ char *part_name = NULL; + struct grub_diskfilter_lv *lv; + /* FIXME: Check whether the update time of the superblocks are + the same. */ +- if (pv->disk && grub_disk_native_sectors (disk) >= pv->part_size) ++ if (pv->disk && grub_disk_native_sectors (disk) >= grub_disk_native_sectors (pv->disk)) + return GRUB_ERR_NONE; +- pv->disk = grub_disk_open (disk->name); ++ if (disk->partition) ++ { ++ char *p = grub_partition_get_name (disk->partition); ++ if (p) ++ part_name = grub_xasprintf ("%s,%s", disk->name, p); ++ grub_free (p); ++ } ++ pv->disk = grub_disk_open (part_name ? : disk->name); ++ grub_free (part_name); + if (!pv->disk) + return grub_errno; +- /* This could happen to LVM on RAID, pv->disk points to the +- raid device, we shouldn't change it. */ +- pv->start_sector -= pv->part_start; +- pv->part_start = grub_partition_get_start (disk->partition); +- pv->part_size = grub_disk_native_sectors (disk); + + #ifdef GRUB_UTIL + { +@@ -1359,7 +1363,6 @@ insert_array (grub_disk_t disk, const struct grub_diskfilter_pv_id *id, + #endif + if (start_sector != (grub_uint64_t)-1) + pv->start_sector = start_sector; +- pv->start_sector += pv->part_start; + /* Add the device to the array. */ + for (lv = array->lvs; lv; lv = lv->next) + if (!lv->became_readable_at && lv->fullname && is_lv_readable (lv, 0)) +@@ -1447,8 +1450,8 @@ grub_diskfilter_get_pv_from_disk (grub_disk_t disk, + { + if (pv->disk && pv->disk->id == disk->id + && pv->disk->dev->id == disk->dev->id +- && pv->part_start == grub_partition_get_start (disk->partition) +- && pv->part_size == grub_disk_native_sectors (disk)) ++ && grub_partition_get_start (pv->disk->partition) == grub_partition_get_start (disk->partition) ++ && grub_disk_native_sectors (pv->disk) == grub_disk_native_sectors (disk)) + { + if (vg_out) + *vg_out = vg; +diff --git a/grub-core/disk/mdraid1x_linux.c b/grub-core/disk/mdraid1x_linux.c +index 38444b02c7..a2aafb69fb 100644 +--- a/grub-core/disk/mdraid1x_linux.c ++++ b/grub-core/disk/mdraid1x_linux.c +@@ -208,6 +208,9 @@ grub_mdraid_detect (grub_disk_t disk, + grub_le_to_cpu32 (sb.chunksize), + grub_le_to_cpu32 (sb.layout), + grub_le_to_cpu32 (sb.level)); ++#ifdef GRUB_UTIL ++ array->mdraid1x_minor_version = minor_version; ++#endif + + return array; + } +diff --git a/grub-core/osdep/basic/no_platform.c b/grub-core/osdep/basic/no_platform.c +index dfbdd58e4e..37b9570dbc 100644 +--- a/grub-core/osdep/basic/no_platform.c ++++ b/grub-core/osdep/basic/no_platform.c +@@ -33,7 +33,8 @@ grub_install_register_ieee1275 (int is_prep, const char *install_device, + void + grub_install_register_efi (grub_device_t efidir_grub_dev, + const char *efifile_path, +- const char *efi_distributor) ++ const char *efi_distributor, ++ const char *force_disk) + { + grub_util_error ("%s", _("no EFI routines are available for your platform")); + } +diff --git a/grub-core/osdep/unix/platform.c b/grub-core/osdep/unix/platform.c +index 68186480b2..c7cf74c677 100644 +--- a/grub-core/osdep/unix/platform.c ++++ b/grub-core/osdep/unix/platform.c +@@ -132,15 +132,14 @@ grub_install_remove_efi_entries_by_distributor (const char *efi_distributor) + } + + int +-grub_install_register_efi (grub_device_t efidir_grub_dev, ++grub_install_register_efi (const grub_disk_t *efidir_grub_disk, + const char *efifile_path, +- const char *efi_distributor) ++ const char *efi_distributor, ++ const char *force_disk) + { +- const char * efidir_disk; +- int efidir_part; + int ret; +- efidir_disk = grub_util_biosdisk_get_osdev (efidir_grub_dev->disk); +- efidir_part = efidir_grub_dev->disk->partition ? efidir_grub_dev->disk->partition->number + 1 : 1; ++ const grub_disk_t *curdisk; ++ int ndev = 0; + + if (grub_util_exec_redirect_null ((const char * []){ "efibootmgr", "--version", NULL })) + { +@@ -158,22 +157,50 @@ grub_install_register_efi (grub_device_t efidir_grub_dev, + if (ret) + return ret; + +- char *efidir_part_str = xasprintf ("%d", efidir_part); ++ for (curdisk = efidir_grub_disk; *curdisk; curdisk++) ++ ndev++; + +- if (!verbosity) +- ret = grub_util_exec ((const char * []){ "efibootmgr", "-q", ++ for (curdisk = efidir_grub_disk; *curdisk; curdisk++) ++ { ++ const char * efidir_disk; ++ int efidir_part; ++ char *efidir_part_str; ++ char *new_efi_distributor = NULL; ++ grub_disk_t disk = *curdisk; ++ ++ efidir_disk = force_disk ? : grub_util_biosdisk_get_osdev (disk); ++ if (!efidir_disk) ++ grub_util_error (_("%s: no device for efi"), disk->name); ++ ++ efidir_part = disk->partition ? disk->partition->number + 1 : 1; ++ efidir_part_str = xasprintf ("%d", efidir_part); ++ if (ndev > 1) ++ { ++ const char *p = grub_strrchr (efidir_disk, '/'); ++ new_efi_distributor = xasprintf ("%s (%s%d)\n", ++ efi_distributor, ++ p ? p + 1: efidir_disk, ++ efidir_part); ++ } ++ ++ if (!verbosity) ++ ret = grub_util_exec ((const char * []){ "efibootmgr", "-q", + "-c", "-d", efidir_disk, + "-p", efidir_part_str, "-w", +- "-L", efi_distributor, "-l", ++ "-L", new_efi_distributor ? : efi_distributor, "-l", + efifile_path, NULL }); +- else +- ret = grub_util_exec ((const char * []){ "efibootmgr", ++ else ++ ret = grub_util_exec ((const char * []){ "efibootmgr", + "-c", "-d", efidir_disk, + "-p", efidir_part_str, "-w", +- "-L", efi_distributor, "-l", ++ "-L", new_efi_distributor ? : efi_distributor, "-l", + efifile_path, NULL }); +- free (efidir_part_str); +- return ret; ++ free (efidir_part_str); ++ free (new_efi_distributor); ++ if (ret) ++ return ret; ++ } ++ return 0; + } + + void +diff --git a/grub-core/osdep/windows/platform.c b/grub-core/osdep/windows/platform.c +index 1d2e356e6b..3517803251 100644 +--- a/grub-core/osdep/windows/platform.c ++++ b/grub-core/osdep/windows/platform.c +@@ -204,7 +204,8 @@ set_efi_variable_bootn (grub_uint16_t n, void *in, grub_size_t len) + int + grub_install_register_efi (grub_device_t efidir_grub_dev, + const char *efifile_path, +- const char *efi_distributor) ++ const char *efi_distributor, ++ const char *force_disk) + { + grub_uint16_t *boot_order, *new_boot_order; + grub_uint16_t *distributor16; +diff --git a/include/grub/diskfilter.h b/include/grub/diskfilter.h +index 8deb1a8c30..94ed8673d7 100644 +--- a/include/grub/diskfilter.h ++++ b/include/grub/diskfilter.h +@@ -49,6 +49,7 @@ struct grub_diskfilter_vg { + + #ifdef GRUB_UTIL + struct grub_diskfilter *driver; ++ grub_uint8_t mdraid1x_minor_version; + #endif + }; + +@@ -66,8 +67,6 @@ struct grub_diskfilter_pv { + /* Optional. */ + char *name; + grub_disk_t disk; +- grub_disk_addr_t part_start; +- grub_disk_addr_t part_size; + grub_disk_addr_t start_sector; /* Sector number where the data area starts. */ + struct grub_diskfilter_pv *next; + /* Optional. */ +diff --git a/include/grub/util/install.h b/include/grub/util/install.h +index 456955c3d7..9f9e0b2ac1 100644 +--- a/include/grub/util/install.h ++++ b/include/grub/util/install.h +@@ -237,9 +237,10 @@ int + grub_install_get_powerpc_secure_boot (void); + + int +-grub_install_register_efi (grub_device_t efidir_grub_dev, ++grub_install_register_efi (const grub_disk_t *efidir_grub_disk, + const char *efifile_path, +- const char *efi_distributor); ++ const char *efi_distributor, ++ const char *force_disk); + + void + grub_install_register_ieee1275 (int is_prep, const char *install_device, +diff --git a/util/grub-install.c b/util/grub-install.c +index 213f54a782..0cabc79119 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -1694,6 +1694,40 @@ main (int argc, char *argv[]) + } + } + prefix_drive = xasprintf ("(%s)", grub_drives[0]); ++ ++ if (platform == GRUB_INSTALL_PLATFORM_X86_64_EFI ++ && grub_dev->disk ++ && grub_dev->disk->partition ++ && grub_fs->fs_uuid) ++ { ++ int raid_level; ++ char *uuid = NULL; ++ char *escaped_relpath = NULL; ++ ++ raid_level = probe_raid_level (grub_dev->disk); ++ if (raid_level != 1) ++ goto out; ++ ++ escaped_relpath = escape (relative_grubdir); ++ if (!escaped_relpath) ++ goto out; ++ ++ if (grub_fs->fs_uuid (grub_dev, &uuid) || !uuid) ++ { ++ grub_print_error (); ++ grub_errno = 0; ++ goto out; ++ } ++ ++ if (!load_cfg_f) ++ load_cfg_f = grub_util_fopen (load_cfg, "wb"); ++ have_load_cfg = 1; ++ fprintf (load_cfg_f, "search --no-floppy --fs-uuid --set=root --hint='%s' %s\n", grub_drives[0], uuid); ++ fprintf (load_cfg_f, "set prefix=($root)'%s'\n", escaped_relpath); ++ grub_install_push_module ("search"); ++ out: ++ grub_free (escaped_relpath); ++ } + } + + #ifdef __linux__ +@@ -2232,9 +2266,13 @@ main (int argc, char *argv[]) + { + /* Try to make this image bootable using the EFI Boot Manager, if available. */ + int ret; +- ret = grub_install_register_efi (efidir_grub_dev, ++ grub_disk_t efidir_grub_disk[2]; ++ efidir_grub_disk[0] = efidir_grub_dev->disk; ++ efidir_grub_disk[1] = NULL; ++ ret = grub_install_register_efi (efidir_grub_disk, + "\\System\\Library\\CoreServices", +- efi_distributor); ++ efi_distributor, ++ NULL); + if (ret) + grub_util_error (_("efibootmgr failed to register the boot entry: %s"), + strerror (ret)); +@@ -2287,7 +2325,11 @@ main (int argc, char *argv[]) + { + char * efifile_path; + char * part; ++ int raid_level; + int ret; ++ grub_disk_t *efidir_grub_disk; ++ grub_disk_memberlist_t list = NULL, cur; ++ char * force_disk = NULL; + + /* Try to make this image bootable using the EFI Boot Manager, if available. */ + if (!efi_distributor || efi_distributor[0] == '\0') +@@ -2304,8 +2346,65 @@ main (int argc, char *argv[]) + efidir_grub_dev->disk->name, + (part ? ",": ""), (part ? : "")); + grub_free (part); +- ret = grub_install_register_efi (efidir_grub_dev, +- efifile_path, efi_distributor); ++ ++ raid_level = probe_raid_level (efidir_grub_dev->disk); ++ if (raid_level >= 0 && raid_level != 1) ++ grub_util_warn (_("unsupported raid level %d detected for efi system partition"), raid_level); ++ if (raid_level == 1 && !efidir_grub_dev->disk->partition) ++ { ++ const char *raidname = NULL; ++ ++ if (efidir_grub_dev->disk->dev->disk_raidname) ++ raidname = efidir_grub_dev->disk->dev->disk_raidname (efidir_grub_dev->disk); ++ if (raidname ++ && (grub_strncmp (raidname, "mdraid09", sizeof ("mdraid09")) == 0 ++ || (grub_strcmp (raidname, "mdraid1x") == 0 ++ && ((struct grub_diskfilter_lv *) efidir_grub_dev->disk->data)->vg->mdraid1x_minor_version == 0))) ++ { ++ if (efidir_grub_dev->disk->dev->disk_memberlist) ++ list = efidir_grub_dev->disk->dev->disk_memberlist (efidir_grub_dev->disk); ++ } ++ else ++ { ++ grub_util_warn (_("this array has metadata at the start and may not be suitable as a efi system partition." ++ " please ensure that your firmware understands md/v1.x metadata, or use --metadata=0.90" ++ " to create the array.")); ++ /* Try to continue regardless metadata, nothing to lose here */ ++ if (efidir_grub_dev->disk->dev->disk_memberlist) ++ list = efidir_grub_dev->disk->dev->disk_memberlist (efidir_grub_dev->disk); ++ } ++ } ++ else if (raid_level == 1) ++ force_disk = grub_util_get_os_disk (install_device); ++ if (list) ++ { ++ int i; ++ int ndisk = 0; ++ ++ for (cur = list; cur; cur = cur->next) ++ ++ndisk; ++ efidir_grub_disk = xcalloc (ndisk + 1, sizeof (*efidir_grub_disk)); ++ for (cur = list, i = 0; i < ndisk; cur = cur->next, i++) ++ efidir_grub_disk[i] = cur->disk; ++ efidir_grub_disk[ndisk] = NULL; ++ } ++ else ++ { ++ efidir_grub_disk = xcalloc (2, sizeof (*efidir_grub_disk)); ++ efidir_grub_disk[0] = efidir_grub_dev->disk; ++ efidir_grub_disk[1] = NULL; ++ } ++ ret = grub_install_register_efi (efidir_grub_disk, ++ efifile_path, efi_distributor, ++ force_disk); ++ while (list) ++ { ++ cur = list; ++ list = list->next; ++ grub_free (cur); ++ } ++ grub_free (force_disk); ++ grub_free (efidir_grub_disk); + if (ret) + grub_util_error (_("efibootmgr failed to register the boot entry: %s"), + strerror (ret)); +-- +2.34.1 + diff --git a/0001-kern-ieee1275-init-Convert-plain-numbers-to-constant.patch b/0001-kern-ieee1275-init-Convert-plain-numbers-to-constant.patch new file mode 100644 index 0000000..d0d9763 --- /dev/null +++ b/0001-kern-ieee1275-init-Convert-plain-numbers-to-constant.patch @@ -0,0 +1,50 @@ +From 10f3a89078f9a6da7104e0978e385362e16af971 Mon Sep 17 00:00:00 2001 +From: Avnish Chouhan +Date: Mon, 27 Mar 2023 12:25:39 +0530 +Subject: [PATCH 1/2] kern/ieee1275/init: Convert plain numbers to constants in + Vec5 + +This patch converts the plain numbers used in Vec5 properties to constants. + +1. LPAR: Client program supports logical partitioning and + associated hcall()s. +2. SPLPAR: Client program supports the Shared + Processor LPAR Option. +3. CMO: Enables the Cooperative Memory Over-commitment Option. +4. MAX_CPU: Defines maximum number of CPUs supported. + +Signed-off-by: Avnish Chouhan +Reviewed-by: Daniel Kiper +--- + grub-core/kern/ieee1275/init.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index e1dbff86a..eaa25d0db 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -61,6 +61,12 @@ extern char _end[]; + grub_addr_t grub_ieee1275_original_stack; + #endif + ++#define LPAR 0x80 ++#define SPLPAR 0x40 ++#define BYTE2 (LPAR | SPLPAR) ++#define CMO 0x80 ++#define MAX_CPU 256 ++ + void + grub_exit (void) + { +@@ -378,7 +384,7 @@ grub_ieee1275_ibm_cas (void) + .vec4 = 0x0001, /* set required minimum capacity % to the lowest value */ + .vec5_size = 1 + sizeof (struct option_vector5) - 2, + .vec5 = { +- 0, 192, 0, 128, 0, 0, 0, 0, 256 ++ 0, BYTE2, 0, CMO, 0, 0, 0, 0, MAX_CPU + } + }; + +-- +2.39.2 + diff --git a/0001-kern-mm.c-Make-grub_calloc-inline.patch b/0001-kern-mm.c-Make-grub_calloc-inline.patch new file mode 100644 index 0000000..cfd265e --- /dev/null +++ b/0001-kern-mm.c-Make-grub_calloc-inline.patch @@ -0,0 +1,116 @@ +From c2475f1337dff2e2a3e45514119d5186e55753c1 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Thu, 13 Aug 2020 09:36:45 +0800 +Subject: [PATCH] kern/mm.c : Make grub_calloc inline + +To circumvent the situation that symbol 'grub_calloc' not found would +happen if system is using stray grub (ie not managed by system update) +as stage1 that can be too old to load updated modules. +--- + grub-core/kern/mm.c | 28 ---------------------------- + include/grub/mm.h | 32 +++++++++++++++++++++++++++++++- + 2 files changed, 31 insertions(+), 29 deletions(-) + +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index f2822a836..dacdaa239 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -60,14 +60,10 @@ + + #include + #include +-#include +-#include + #include + #include + #include +-#include + #include +-#include + + #ifdef MM_DEBUG + # undef grub_calloc +@@ -377,30 +373,6 @@ grub_memalign (grub_size_t align, grub_size_t size) + return 0; + } + +-/* +- * Allocate NMEMB instances of SIZE bytes and return the pointer, or error on +- * integer overflow. +- */ +-void * +-grub_calloc (grub_size_t nmemb, grub_size_t size) +-{ +- void *ret; +- grub_size_t sz = 0; +- +- if (grub_mul (nmemb, size, &sz)) +- { +- grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); +- return NULL; +- } +- +- ret = grub_memalign (0, sz); +- if (!ret) +- return NULL; +- +- grub_memset (ret, 0, sz); +- return ret; +-} +- + /* Allocate SIZE bytes and return the pointer. */ + void * + grub_malloc (grub_size_t size) +diff --git a/include/grub/mm.h b/include/grub/mm.h +index 9c38dd3ca..1754635e7 100644 +--- a/include/grub/mm.h ++++ b/include/grub/mm.h +@@ -29,7 +29,6 @@ + #endif + + void grub_mm_init_region (void *addr, grub_size_t size); +-void *EXPORT_FUNC(grub_calloc) (grub_size_t nmemb, grub_size_t size); + void *EXPORT_FUNC(grub_malloc) (grub_size_t size); + void *EXPORT_FUNC(grub_zalloc) (grub_size_t size); + void EXPORT_FUNC(grub_free) (void *ptr); +@@ -37,6 +36,37 @@ void *EXPORT_FUNC(grub_realloc) (void *ptr, grub_size_t size); + #ifndef GRUB_MACHINE_EMU + void *EXPORT_FUNC(grub_memalign) (grub_size_t align, grub_size_t size); + #endif ++#if !defined(GRUB_UTIL) && !defined (GRUB_MACHINE_EMU) ++#include ++#include ++#include ++#include ++/* ++ * Allocate NMEMB instances of SIZE bytes and return the pointer, or error on ++ * integer overflow. ++ */ ++static inline void * ++grub_calloc (grub_size_t nmemb, grub_size_t size) ++{ ++ void *ret; ++ grub_size_t sz = 0; ++ ++ if (grub_mul (nmemb, size, &sz)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); ++ return NULL; ++ } ++ ++ ret = grub_memalign (0, sz); ++ if (!ret) ++ return NULL; ++ ++ grub_memset (ret, 0, sz); ++ return ret; ++} ++#else ++void *EXPORT_FUNC(grub_calloc) (grub_size_t nmemb, grub_size_t size); ++#endif + + void grub_mm_check_real (const char *file, int line); + #define grub_mm_check() grub_mm_check_real (GRUB_FILE, __LINE__); +-- +2.26.2 + diff --git a/0001-luks2-Add-debug-message-to-align-with-luks-and-geli-.patch b/0001-luks2-Add-debug-message-to-align-with-luks-and-geli-.patch new file mode 100644 index 0000000..c65fa7b --- /dev/null +++ b/0001-luks2-Add-debug-message-to-align-with-luks-and-geli-.patch @@ -0,0 +1,31 @@ +From 8eae4c33a32d9951641e289d2809a92a223b1642 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:50 -0600 +Subject: [PATCH 01/14] luks2: Add debug message to align with luks and geli + modules + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/luks2.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c +index 371a53b837..fea196dd4a 100644 +--- a/grub-core/disk/luks2.c ++++ b/grub-core/disk/luks2.c +@@ -370,7 +370,10 @@ luks2_scan (grub_disk_t disk, const char *check_uuid, int check_boot) + uuid[j] = '\0'; + + if (check_uuid && grub_strcasecmp (check_uuid, uuid) != 0) +- return NULL; ++ { ++ grub_dprintf ("luks2", "%s != %s\n", uuid, check_uuid); ++ return NULL; ++ } + + cryptodisk = grub_zalloc (sizeof (*cryptodisk)); + if (!cryptodisk) +-- +2.34.1 + diff --git a/0001-ofdisk-improve-boot-time-by-lookup-boot-disk-first.patch b/0001-ofdisk-improve-boot-time-by-lookup-boot-disk-first.patch new file mode 100644 index 0000000..91b2c72 --- /dev/null +++ b/0001-ofdisk-improve-boot-time-by-lookup-boot-disk-first.patch @@ -0,0 +1,63 @@ +From b0f9dcabe96e5689ecfba9b6abcd27e685eabd48 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Wed, 11 May 2022 09:56:11 -0400 +Subject: [PATCH] ofdisk: improve boot time by lookup boot disk first + +While booting lvm, grub will try to build up logical volumes via hooks +to disk iteration where on-disk metadata can be read and parsed. However +the process can become very slow on multipath as reachable disks are +duplicated by multiple I/O paths and they all get inspected. + +Fortunately grub allows lvm to be lazy binding and opportunistic that +root volume can be created when it's needed using a smaller set of +discovered disks. The disk iteration can also be controlled by pull +methods to only returning specified disks. That said we may be able to +take advantage of existing design to cause less overhead in lvm +construction. + +This patch will return boot disks in OpenFirmware so they can be used +first. If lvm managed to create root volume out of those boot disks then +it is all very nice as they are readily available. Otherwise disk +scanning will be performed to present all discoverable disks to grub as +what it was done in the past. The result maybe again time consuming but +we have nothing to lose here. + +Signed-off-by: Michael Chang +--- + grub-core/disk/ieee1275/ofdisk.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c +index 258a6e3891..410f4b849f 100644 +--- a/grub-core/disk/ieee1275/ofdisk.c ++++ b/grub-core/disk/ieee1275/ofdisk.c +@@ -491,10 +491,11 @@ grub_ofdisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data, + { + unsigned i; + +- if (pull != GRUB_DISK_PULL_NONE) ++ if (pull > GRUB_DISK_PULL_REMOVABLE) + return 0; + +- scan (); ++ if (pull == GRUB_DISK_PULL_REMOVABLE) ++ scan (); + + for (i = 0; i < ARRAY_SIZE (ofdisk_hash); i++) + { +@@ -532,6 +533,12 @@ grub_ofdisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data, + if (!ent->is_boot && ent->is_removable) + continue; + ++ if (pull == GRUB_DISK_PULL_NONE && !ent->is_boot) ++ continue; ++ ++ if (pull == GRUB_DISK_PULL_REMOVABLE && ent->is_boot) ++ continue; ++ + if (hook (ent->grub_shortest, hook_data)) + return 1; + } +-- +2.34.1 + diff --git a/0001-openfw-Ensure-get_devargs-and-get_devname-functions-.patch b/0001-openfw-Ensure-get_devargs-and-get_devname-functions-.patch new file mode 100644 index 0000000..db5f897 --- /dev/null +++ b/0001-openfw-Ensure-get_devargs-and-get_devname-functions-.patch @@ -0,0 +1,52 @@ +From 468628bdc39800341e7aa6ff7795cc0d93cfaf3f Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Tue, 11 Apr 2023 10:59:34 +0800 +Subject: [PATCH 1/2] openfw: Ensure get_devargs and get_devname functions are + consistent + +Commit 165c9b234 changed the logic of ieee1275_get_devargs() to use the +first or second occurrence of a colon as a separator between device name +and arguments. However, this didn't align with the complementary +function ieee1275_get_devname, which uses the first occurrence of a +colon after the namespace keyword as arguments for the nvme-of device. + +This commit addresses the inconsistency by ensuring that both functions +follow a common logic. Now, get_devargs and get_devname functions are +consistent with each other, making it easier to understand and maintain +the codebase. + +Signed-off-by: Michael Chang +--- + grub-core/kern/ieee1275/openfw.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/grub-core/kern/ieee1275/openfw.c b/grub-core/kern/ieee1275/openfw.c +index e2ffec32d..3bbd07d95 100644 +--- a/grub-core/kern/ieee1275/openfw.c ++++ b/grub-core/kern/ieee1275/openfw.c +@@ -354,13 +354,16 @@ static char * + grub_ieee1275_get_devargs (const char *path) + { + char *colon = grub_strchr (path, ':'); +- char *colon_check = colon; + +- /* Find the last occurence of colon */ +- while(colon_check){ +- colon = colon_check; +- colon_check = grub_strchr (colon+1, ':'); +- } ++ /* Use the same logic in grub_ieee1275_get_devname for nvme-of arguments */ ++ if (grub_strstr(path, "nvme-of")) ++ { ++ char *namespace_split = grub_strstr(path,"/namespace@"); ++ if (namespace_split) ++ colon = grub_strchr (namespace_split, ':'); ++ else ++ colon = NULL; ++ } + + if (! colon) + return 0; +-- +2.39.2 + diff --git a/0001-osdep-Introduce-include-grub-osdep-major.h-and-use-i.patch b/0001-osdep-Introduce-include-grub-osdep-major.h-and-use-i.patch new file mode 100644 index 0000000..d84af84 --- /dev/null +++ b/0001-osdep-Introduce-include-grub-osdep-major.h-and-use-i.patch @@ -0,0 +1,158 @@ +From e94b4f23277f7572aacbbeae50b8927e03be148a Mon Sep 17 00:00:00 2001 +From: Petr Vorel +Date: Thu, 15 Jul 2021 17:35:27 +0200 +Subject: [PATCH 1/2] osdep: Introduce include/grub/osdep/major.h and use it + +... to factor out fix for glibc 2.25 introduced in 7a5b301e3 (build: Use +AC_HEADER_MAJOR to find device macros). + +Note: Once glibc 2.25 is old enough and this fix is not needed also +AC_HEADER_MAJOR in configure.ac should be removed. + +Signed-off-by: Petr Vorel +Reviewed-by: Daniel Kiper +[ upstream status: e94b4f232 ("osdep: Introduce include/grub/osdep/major.h and use it") ] +--- + configure.ac | 2 +- + grub-core/osdep/devmapper/getroot.c | 7 +----- + grub-core/osdep/devmapper/hostdisk.c | 7 +----- + grub-core/osdep/linux/getroot.c | 7 +----- + grub-core/osdep/unix/getroot.c | 7 +----- + include/grub/osdep/major.h | 33 ++++++++++++++++++++++++++++ + 6 files changed, 38 insertions(+), 25 deletions(-) + create mode 100644 include/grub/osdep/major.h + +diff --git a/configure.ac b/configure.ac +index b025e1e84..bee28dbeb 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -424,7 +424,7 @@ AC_CHECK_HEADERS(sys/param.h sys/mount.h sys/mnttab.h limits.h) + + # glibc 2.25 still includes sys/sysmacros.h in sys/types.h but emits deprecation + # warning which causes compilation failure later with -Werror. So use -Werror here +-# as well to force proper sys/sysmacros.h detection. ++# as well to force proper sys/sysmacros.h detection. Used in include/grub/osdep/major.h. + SAVED_CFLAGS="$CFLAGS" + CFLAGS="$HOST_CFLAGS -Werror" + AC_HEADER_MAJOR +diff --git a/grub-core/osdep/devmapper/getroot.c b/grub-core/osdep/devmapper/getroot.c +index a13a39c96..9ba5c9865 100644 +--- a/grub-core/osdep/devmapper/getroot.c ++++ b/grub-core/osdep/devmapper/getroot.c +@@ -40,12 +40,7 @@ + #include + #endif + +-#if defined(MAJOR_IN_MKDEV) +-#include +-#elif defined(MAJOR_IN_SYSMACROS) +-#include +-#endif +- ++#include + #include + + #include +diff --git a/grub-core/osdep/devmapper/hostdisk.c b/grub-core/osdep/devmapper/hostdisk.c +index a8afc0c94..c8053728b 100644 +--- a/grub-core/osdep/devmapper/hostdisk.c ++++ b/grub-core/osdep/devmapper/hostdisk.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -24,12 +25,6 @@ + #include + #include + +-#if defined(MAJOR_IN_MKDEV) +-#include +-#elif defined(MAJOR_IN_SYSMACROS) +-#include +-#endif +- + #ifdef HAVE_DEVICE_MAPPER + # include + +diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c +index 001b818fe..cd588588e 100644 +--- a/grub-core/osdep/linux/getroot.c ++++ b/grub-core/osdep/linux/getroot.c +@@ -35,12 +35,7 @@ + #include + #endif + +-#if defined(MAJOR_IN_MKDEV) +-#include +-#elif defined(MAJOR_IN_SYSMACROS) +-#include +-#endif +- ++#include + #include + #include /* ioctl */ + #include +diff --git a/grub-core/osdep/unix/getroot.c b/grub-core/osdep/unix/getroot.c +index 46d7116c6..74f69116d 100644 +--- a/grub-core/osdep/unix/getroot.c ++++ b/grub-core/osdep/unix/getroot.c +@@ -51,12 +51,7 @@ + #endif /* ! FLOPPY_MAJOR */ + #endif + +-#include +-#if defined(MAJOR_IN_MKDEV) +-#include +-#elif defined(MAJOR_IN_SYSMACROS) +-#include +-#endif ++#include + + #if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) + # include +diff --git a/include/grub/osdep/major.h b/include/grub/osdep/major.h +new file mode 100644 +index 000000000..84a9159af +--- /dev/null ++++ b/include/grub/osdep/major.h +@@ -0,0 +1,33 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2021 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 . ++ * ++ * Fix for glibc 2.25 which is deprecating the namespace pollution of ++ * sys/types.h injecting major(), minor(), and makedev() into the ++ * compilation environment. ++ */ ++ ++#ifndef GRUB_OSDEP_MAJOR_H ++#define GRUB_OSDEP_MAJOR_H 1 ++ ++#include ++ ++#ifdef MAJOR_IN_MKDEV ++# include ++#elif defined (MAJOR_IN_SYSMACROS) ++# include ++#endif ++#endif /* GRUB_OSDEP_MAJOR_H */ +-- +2.32.0 + diff --git a/0001-powerpc-do-CAS-in-a-more-compatible-way.patch b/0001-powerpc-do-CAS-in-a-more-compatible-way.patch new file mode 100644 index 0000000..691fc1c --- /dev/null +++ b/0001-powerpc-do-CAS-in-a-more-compatible-way.patch @@ -0,0 +1,113 @@ +From 91c9ff5515821fa579961a4c3a411a29384fbfd6 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 8 Apr 2022 12:35:28 +1000 +Subject: [PATCH] powerpc: do CAS in a more compatible way + +I wrongly assumed that the most compatible way to perform CAS +negotiation was to only set the minimum number of vectors required +to ask for more memory. It turns out that this messes up booting +if the minimum VP capacity would be less than the default 10% in +vector 4. + +Linux configures the minimum capacity to be 1%, so copy it for that +and for vector 3 which we now need to specify as well. + +Signed-off-by: Daniel Axtens +--- + grub-core/kern/ieee1275/init.c | 54 +++++++++++++++++++--------------- + 1 file changed, 31 insertions(+), 23 deletions(-) + +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index d77d896043..7d7178d3e1 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -298,33 +298,37 @@ grub_ieee1275_total_mem (grub_uint64_t *total) + + /* Based on linux - arch/powerpc/kernel/prom_init.c */ + struct option_vector2 { +- grub_uint8_t byte1; +- grub_uint16_t reserved; +- grub_uint32_t real_base; +- grub_uint32_t real_size; +- grub_uint32_t virt_base; +- grub_uint32_t virt_size; +- grub_uint32_t load_base; +- grub_uint32_t min_rma; +- grub_uint32_t min_load; +- grub_uint8_t min_rma_percent; +- grub_uint8_t max_pft_size; ++ grub_uint8_t byte1; ++ grub_uint16_t reserved; ++ grub_uint32_t real_base; ++ grub_uint32_t real_size; ++ grub_uint32_t virt_base; ++ grub_uint32_t virt_size; ++ grub_uint32_t load_base; ++ grub_uint32_t min_rma; ++ grub_uint32_t min_load; ++ grub_uint8_t min_rma_percent; ++ grub_uint8_t max_pft_size; + } __attribute__((packed)); + + struct pvr_entry { +- grub_uint32_t mask; +- grub_uint32_t entry; ++ grub_uint32_t mask; ++ grub_uint32_t entry; + }; + + struct cas_vector { +- struct { +- struct pvr_entry terminal; +- } pvr_list; +- grub_uint8_t num_vecs; +- grub_uint8_t vec1_size; +- grub_uint8_t vec1; +- grub_uint8_t vec2_size; +- struct option_vector2 vec2; ++ struct { ++ struct pvr_entry terminal; ++ } pvr_list; ++ grub_uint8_t num_vecs; ++ grub_uint8_t vec1_size; ++ grub_uint8_t vec1; ++ grub_uint8_t vec2_size; ++ struct option_vector2 vec2; ++ grub_uint8_t vec3_size; ++ grub_uint16_t vec3; ++ grub_uint8_t vec4_size; ++ grub_uint16_t vec4; + } __attribute__((packed)); + + /* Call ibm,client-architecture-support to try to get more RMA. +@@ -345,13 +349,17 @@ grub_ieee1275_ibm_cas (void) + } args; + struct cas_vector vector = { + .pvr_list = { { 0x00000000, 0xffffffff } }, /* any processor */ +- .num_vecs = 2 - 1, ++ .num_vecs = 4 - 1, + .vec1_size = 0, + .vec1 = 0x80, /* ignore */ + .vec2_size = 1 + sizeof(struct option_vector2) - 2, + .vec2 = { + 0, 0, -1, -1, -1, -1, -1, 512, -1, 0, 48 + }, ++ .vec3_size = 2 - 1, ++ .vec3 = 0x00e0, // ask for FP + VMX + DFP but don't halt if unsatisfied ++ .vec4_size = 2 - 1, ++ .vec4 = 0x0001, // set required minimum capacity % to the lowest value + }; + + INIT_IEEE1275_COMMON (&args.common, "call-method", 3, 2); +@@ -364,7 +372,7 @@ grub_ieee1275_ibm_cas (void) + args.ihandle = root; + args.cas_addr = (grub_ieee1275_cell_t)&vector; + +- grub_printf("Calling ibm,client-architecture-support..."); ++ grub_printf("Calling ibm,client-architecture-support from grub..."); + IEEE1275_CALL_ENTRY_FN (&args); + grub_printf("done\n"); + +-- +2.34.1 + diff --git a/0001-templates-Follow-the-path-of-usr-merged-kernel-confi.patch b/0001-templates-Follow-the-path-of-usr-merged-kernel-confi.patch new file mode 100644 index 0000000..67ca309 --- /dev/null +++ b/0001-templates-Follow-the-path-of-usr-merged-kernel-confi.patch @@ -0,0 +1,47 @@ +From 60d1d3b959e72c2cbd014be311c350a9b11b1289 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Tue, 7 Sep 2021 10:06:50 +0800 +Subject: [PATCH] templates: Follow the path of usr merged kernel config + +The background for usr merge can be found at: + +https://www.freedesktop.org/wiki/Software/systemd/TheCaseForTheUsrMerge/ + +This patch adapts related mkconfig scripts to follow the usr merge for +looking up kernel configs. + +Signed-off-by: Michael Chang +--- + util/grub.d/10_linux.in | 2 +- + util/grub.d/20_linux_xen.in | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 7f3e79b09..00e351802 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -307,7 +307,7 @@ while [ "x$list" != "x" ] ; do + fi + + config= +- for i in "${dirname}/config-${version}" "${dirname}/config-${alt_version}" "/etc/kernels/kernel-config-${version}" ; do ++ for i in "${dirname}/config-${version}" "${dirname}/config-${alt_version}" "/etc/kernels/kernel-config-${version}" "/usr/lib/modules/${version}/config" ; do + if test -e "${i}" ; then + config="${i}" + break +diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in +index 8813435b7..318b6d320 100644 +--- a/util/grub.d/20_linux_xen.in ++++ b/util/grub.d/20_linux_xen.in +@@ -304,7 +304,7 @@ for i in /boot/vmlinu[xz]-* /vmlinu[xz]-* /boot/kernel-*; do + version=$(echo $basename | sed -e "s,^[^0-9]*-,,g") + dirname=$(dirname $i) + config= +- for j in "${dirname}/config-${version}" "${dirname}/config-${alt_version}" "/etc/kernels/kernel-config-${version}" ; do ++ for j in "${dirname}/config-${version}" "${dirname}/config-${alt_version}" "/etc/kernels/kernel-config-${version}" "/usr/lib/modules/${version}/config" ; do + if test -e "${j}" ; then + config="${j}" + break +-- +2.33.0 + diff --git a/0001-tpm-Pass-unknown-error-as-non-fatal-but-debug-print-.patch b/0001-tpm-Pass-unknown-error-as-non-fatal-but-debug-print-.patch new file mode 100644 index 0000000..265db29 --- /dev/null +++ b/0001-tpm-Pass-unknown-error-as-non-fatal-but-debug-print-.patch @@ -0,0 +1,29 @@ +From 2cecb472ffba4dbc534f4ce3346a453762371c52 Mon Sep 17 00:00:00 2001 +From: Mathieu Trudel-Lapierre +Date: Fri, 25 Oct 2019 10:27:54 -0400 +Subject: [PATCH] tpm: Pass unknown error as non-fatal, but debug print the + error we got + +Signed-off-by: Mathieu Trudel-Lapierre +Patch-Name: ubuntu-tpm-unknown-error-non-fatal.patch +--- + grub-core/commands/efi/tpm.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c +index a97d85368..1e399a964 100644 +--- a/grub-core/commands/efi/tpm.c ++++ b/grub-core/commands/efi/tpm.c +@@ -145,7 +145,8 @@ grub_efi_log_event_status (grub_efi_status_t status) + case GRUB_EFI_NOT_FOUND: + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable")); + default: +- return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error")); ++ grub_dprintf("tpm", "Unknown TPM error: %" PRIdGRUB_SSIZE, status); ++ return 0; + } + } + +-- +2.31.1 + diff --git a/0001-video-Remove-trailing-whitespaces.patch b/0001-video-Remove-trailing-whitespaces.patch new file mode 100644 index 0000000..1eba736 --- /dev/null +++ b/0001-video-Remove-trailing-whitespaces.patch @@ -0,0 +1,686 @@ +From efa2ddca2c7167e98f12e9ad8963e9201fa87e75 Mon Sep 17 00:00:00 2001 +From: Elyes Haouas +Date: Fri, 4 Mar 2022 07:42:13 +0100 +Subject: [PATCH 01/32] video: Remove trailing whitespaces + +Signed-off-by: Elyes Haouas +Reviewed-by: Daniel Kiper +--- + grub-core/video/bochs.c | 2 +- + grub-core/video/capture.c | 2 +- + grub-core/video/cirrus.c | 4 ++-- + grub-core/video/coreboot/cbfb.c | 2 +- + grub-core/video/efi_gop.c | 22 +++++++++---------- + grub-core/video/fb/fbblit.c | 8 +++---- + grub-core/video/fb/video_fb.c | 10 ++++----- + grub-core/video/i386/pc/vbe.c | 34 ++++++++++++++--------------- + grub-core/video/i386/pc/vga.c | 6 ++--- + grub-core/video/ieee1275.c | 4 ++-- + grub-core/video/radeon_fuloong2e.c | 6 ++--- + grub-core/video/radeon_yeeloong3a.c | 6 ++--- + grub-core/video/readers/png.c | 2 +- + grub-core/video/readers/tga.c | 2 +- + grub-core/video/sis315_init.c | 2 +- + grub-core/video/sis315pro.c | 8 +++---- + grub-core/video/sm712.c | 10 ++++----- + grub-core/video/video.c | 8 +++---- + 18 files changed, 69 insertions(+), 69 deletions(-) + +diff --git a/grub-core/video/bochs.c b/grub-core/video/bochs.c +index 30ea1bd828..edc651697a 100644 +--- a/grub-core/video/bochs.c ++++ b/grub-core/video/bochs.c +@@ -212,7 +212,7 @@ find_card (grub_pci_device_t dev, grub_pci_id_t pciid, void *data) + + if (((class >> 16) & 0xffff) != 0x0300 || pciid != 0x11111234) + return 0; +- ++ + addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0); + framebuffer.base = grub_pci_read (addr) & GRUB_PCI_ADDR_MEM_MASK; + if (!framebuffer.base) +diff --git a/grub-core/video/capture.c b/grub-core/video/capture.c +index 4d3195e017..c653d89f91 100644 +--- a/grub-core/video/capture.c ++++ b/grub-core/video/capture.c +@@ -92,7 +92,7 @@ grub_video_capture_start (const struct grub_video_mode_info *mode_info, + framebuffer.ptr = grub_calloc (framebuffer.mode_info.height, framebuffer.mode_info.pitch); + if (!framebuffer.ptr) + return grub_errno; +- ++ + err = grub_video_fb_create_render_target_from_pointer (&framebuffer.render_target, + &framebuffer.mode_info, + framebuffer.ptr); +diff --git a/grub-core/video/cirrus.c b/grub-core/video/cirrus.c +index e2149e8ced..f5542ccdc6 100644 +--- a/grub-core/video/cirrus.c ++++ b/grub-core/video/cirrus.c +@@ -354,11 +354,11 @@ grub_video_cirrus_setup (unsigned int width, unsigned int height, + grub_uint8_t sr_ext = 0, hidden_dac = 0; + + grub_vga_set_geometry (&config, grub_vga_cr_write); +- ++ + grub_vga_gr_write (GRUB_VGA_GR_MODE_256_COLOR | GRUB_VGA_GR_MODE_READ_MODE1, + GRUB_VGA_GR_MODE); + grub_vga_gr_write (GRUB_VGA_GR_GR6_GRAPHICS_MODE, GRUB_VGA_GR_GR6); +- ++ + grub_vga_sr_write (GRUB_VGA_SR_MEMORY_MODE_NORMAL, GRUB_VGA_SR_MEMORY_MODE); + + grub_vga_cr_write ((config.pitch >> CIRRUS_CR_EXTENDED_DISPLAY_PITCH_SHIFT) +diff --git a/grub-core/video/coreboot/cbfb.c b/grub-core/video/coreboot/cbfb.c +index 9af81fa5b0..986003c516 100644 +--- a/grub-core/video/coreboot/cbfb.c ++++ b/grub-core/video/coreboot/cbfb.c +@@ -106,7 +106,7 @@ grub_video_cbfb_setup (unsigned int width, unsigned int height, + + grub_video_fb_set_palette (0, GRUB_VIDEO_FBSTD_NUMCOLORS, + grub_video_fbstd_colors); +- ++ + return err; + } + +diff --git a/grub-core/video/efi_gop.c b/grub-core/video/efi_gop.c +index 5a37385398..cdf0e100fa 100644 +--- a/grub-core/video/efi_gop.c ++++ b/grub-core/video/efi_gop.c +@@ -273,7 +273,7 @@ grub_video_gop_iterate (int (*hook) (const struct grub_video_mode_info *info, vo + grub_efi_status_t status; + struct grub_efi_gop_mode_info *info = NULL; + struct grub_video_mode_info mode_info; +- ++ + status = efi_call_4 (gop->query_mode, gop, mode, &size, &info); + + if (status) +@@ -402,7 +402,7 @@ again: + found = 1; + } + } +- ++ + if (!found) + { + unsigned mode; +@@ -411,7 +411,7 @@ again: + { + grub_efi_uintn_t size; + grub_efi_status_t status; +- ++ + status = efi_call_4 (gop->query_mode, gop, mode, &size, &info); + if (status) + { +@@ -489,11 +489,11 @@ again: + framebuffer.ptr = (void *) (grub_addr_t) gop->mode->fb_base; + framebuffer.offscreen + = grub_malloc (framebuffer.mode_info.height +- * framebuffer.mode_info.width ++ * framebuffer.mode_info.width + * sizeof (struct grub_efi_gop_blt_pixel)); + + buffer = framebuffer.offscreen; +- ++ + if (!buffer) + { + grub_dprintf ("video", "GOP: couldn't allocate shadow\n"); +@@ -502,11 +502,11 @@ again: + &framebuffer.mode_info); + buffer = framebuffer.ptr; + } +- ++ + grub_dprintf ("video", "GOP: initialising FB @ %p %dx%dx%d\n", + framebuffer.ptr, framebuffer.mode_info.width, + framebuffer.mode_info.height, framebuffer.mode_info.bpp); +- ++ + err = grub_video_fb_create_render_target_from_pointer + (&framebuffer.render_target, &framebuffer.mode_info, buffer); + +@@ -515,15 +515,15 @@ again: + grub_dprintf ("video", "GOP: Couldn't create FB target\n"); + return err; + } +- ++ + err = grub_video_fb_set_active_render_target (framebuffer.render_target); +- ++ + if (err) + { + grub_dprintf ("video", "GOP: Couldn't set FB target\n"); + return err; + } +- ++ + err = grub_video_fb_set_palette (0, GRUB_VIDEO_FBSTD_NUMCOLORS, + grub_video_fbstd_colors); + +@@ -531,7 +531,7 @@ again: + grub_dprintf ("video", "GOP: Couldn't set palette\n"); + else + grub_dprintf ("video", "GOP: Success\n"); +- ++ + return err; + } + +diff --git a/grub-core/video/fb/fbblit.c b/grub-core/video/fb/fbblit.c +index d55924837d..1010ef3930 100644 +--- a/grub-core/video/fb/fbblit.c ++++ b/grub-core/video/fb/fbblit.c +@@ -466,7 +466,7 @@ grub_video_fbblit_replace_24bit_indexa (struct grub_video_fbblit_info *dst, + for (i = 0; i < width; i++) + { + register grub_uint32_t col; +- if (*srcptr == 0xf0) ++ if (*srcptr == 0xf0) + col = palette[16]; + else + col = palette[*srcptr & 0xf]; +@@ -478,7 +478,7 @@ grub_video_fbblit_replace_24bit_indexa (struct grub_video_fbblit_info *dst, + *dstptr++ = col >> 0; + *dstptr++ = col >> 8; + *dstptr++ = col >> 16; +-#endif ++#endif + srcptr++; + } + +@@ -651,7 +651,7 @@ grub_video_fbblit_blend_24bit_indexa (struct grub_video_fbblit_info *dst, + for (i = 0; i < width; i++) + { + register grub_uint32_t col; +- if (*srcptr != 0xf0) ++ if (*srcptr != 0xf0) + { + col = palette[*srcptr & 0xf]; + #ifdef GRUB_CPU_WORDS_BIGENDIAN +@@ -662,7 +662,7 @@ grub_video_fbblit_blend_24bit_indexa (struct grub_video_fbblit_info *dst, + *dstptr++ = col >> 0; + *dstptr++ = col >> 8; + *dstptr++ = col >> 16; +-#endif ++#endif + } + else + dstptr += 3; +diff --git a/grub-core/video/fb/video_fb.c b/grub-core/video/fb/video_fb.c +index ae6b89f9ae..fa4ebde260 100644 +--- a/grub-core/video/fb/video_fb.c ++++ b/grub-core/video/fb/video_fb.c +@@ -754,7 +754,7 @@ grub_video_fb_unmap_color_int (struct grub_video_fbblit_info * source, + *alpha = 0; + return; + } +- ++ + /* If we have an out-of-bounds color, return transparent black. */ + if (color > 255) + { +@@ -1141,7 +1141,7 @@ grub_video_fb_scroll (grub_video_color_t color, int dx, int dy) + /* If everything is aligned on 32-bit use 32-bit copy. */ + if ((grub_addr_t) grub_video_fb_get_video_ptr (&target, src_x, src_y) + % sizeof (grub_uint32_t) == 0 +- && (grub_addr_t) grub_video_fb_get_video_ptr (&target, dst_x, dst_y) ++ && (grub_addr_t) grub_video_fb_get_video_ptr (&target, dst_x, dst_y) + % sizeof (grub_uint32_t) == 0 + && linelen % sizeof (grub_uint32_t) == 0 + && linedelta % sizeof (grub_uint32_t) == 0) +@@ -1155,7 +1155,7 @@ grub_video_fb_scroll (grub_video_color_t color, int dx, int dy) + else if ((grub_addr_t) grub_video_fb_get_video_ptr (&target, src_x, src_y) + % sizeof (grub_uint16_t) == 0 + && (grub_addr_t) grub_video_fb_get_video_ptr (&target, +- dst_x, dst_y) ++ dst_x, dst_y) + % sizeof (grub_uint16_t) == 0 + && linelen % sizeof (grub_uint16_t) == 0 + && linedelta % sizeof (grub_uint16_t) == 0) +@@ -1170,7 +1170,7 @@ grub_video_fb_scroll (grub_video_color_t color, int dx, int dy) + { + grub_uint8_t *src, *dst; + DO_SCROLL +- } ++ } + } + + /* 4. Fill empty space with specified color. In this implementation +@@ -1615,7 +1615,7 @@ grub_video_fb_setup (unsigned int mode_type, unsigned int mode_mask, + framebuffer.render_target = framebuffer.back_target; + return GRUB_ERR_NONE; + } +- ++ + mode_info->mode_type &= ~(GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED + | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP); + +diff --git a/grub-core/video/i386/pc/vbe.c b/grub-core/video/i386/pc/vbe.c +index 8c8cbf07eb..8b72810f85 100644 +--- a/grub-core/video/i386/pc/vbe.c ++++ b/grub-core/video/i386/pc/vbe.c +@@ -219,7 +219,7 @@ grub_vbe_disable_mtrr (int mtrr) + } + + /* Call VESA BIOS 0x4f09 to set palette data, return status. */ +-static grub_vbe_status_t ++static grub_vbe_status_t + grub_vbe_bios_set_palette_data (grub_uint32_t color_count, + grub_uint32_t start_index, + struct grub_vbe_palette_data *palette_data) +@@ -237,7 +237,7 @@ grub_vbe_bios_set_palette_data (grub_uint32_t color_count, + } + + /* Call VESA BIOS 0x4f00 to get VBE Controller Information, return status. */ +-grub_vbe_status_t ++grub_vbe_status_t + grub_vbe_bios_get_controller_info (struct grub_vbe_info_block *ci) + { + struct grub_bios_int_registers regs; +@@ -251,7 +251,7 @@ grub_vbe_bios_get_controller_info (struct grub_vbe_info_block *ci) + } + + /* Call VESA BIOS 0x4f01 to get VBE Mode Information, return status. */ +-grub_vbe_status_t ++grub_vbe_status_t + grub_vbe_bios_get_mode_info (grub_uint32_t mode, + struct grub_vbe_mode_info_block *mode_info) + { +@@ -285,7 +285,7 @@ grub_vbe_bios_set_mode (grub_uint32_t mode, + } + + /* Call VESA BIOS 0x4f03 to return current VBE Mode, return status. */ +-grub_vbe_status_t ++grub_vbe_status_t + grub_vbe_bios_get_mode (grub_uint32_t *mode) + { + struct grub_bios_int_registers regs; +@@ -298,7 +298,7 @@ grub_vbe_bios_get_mode (grub_uint32_t *mode) + return regs.eax & 0xffff; + } + +-grub_vbe_status_t ++grub_vbe_status_t + grub_vbe_bios_getset_dac_palette_width (int set, int *dac_mask_size) + { + struct grub_bios_int_registers regs; +@@ -346,7 +346,7 @@ grub_vbe_bios_get_memory_window (grub_uint32_t window, + } + + /* Call VESA BIOS 0x4f06 to set scanline length (in bytes), return status. */ +-grub_vbe_status_t ++grub_vbe_status_t + grub_vbe_bios_set_scanline_length (grub_uint32_t length) + { + struct grub_bios_int_registers regs; +@@ -354,14 +354,14 @@ grub_vbe_bios_set_scanline_length (grub_uint32_t length) + regs.ecx = length; + regs.eax = 0x4f06; + /* BL = 2, Set Scan Line in Bytes. */ +- regs.ebx = 0x0002; ++ regs.ebx = 0x0002; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); + return regs.eax & 0xffff; + } + + /* Call VESA BIOS 0x4f06 to return scanline length (in bytes), return status. */ +-grub_vbe_status_t ++grub_vbe_status_t + grub_vbe_bios_get_scanline_length (grub_uint32_t *length) + { + struct grub_bios_int_registers regs; +@@ -377,7 +377,7 @@ grub_vbe_bios_get_scanline_length (grub_uint32_t *length) + } + + /* Call VESA BIOS 0x4f07 to set display start, return status. */ +-static grub_vbe_status_t ++static grub_vbe_status_t + grub_vbe_bios_set_display_start (grub_uint32_t x, grub_uint32_t y) + { + struct grub_bios_int_registers regs; +@@ -390,7 +390,7 @@ grub_vbe_bios_set_display_start (grub_uint32_t x, grub_uint32_t y) + regs.edx = y; + regs.eax = 0x4f07; + /* BL = 80h, Set Display Start during Vertical Retrace. */ +- regs.ebx = 0x0080; ++ regs.ebx = 0x0080; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); + +@@ -401,7 +401,7 @@ grub_vbe_bios_set_display_start (grub_uint32_t x, grub_uint32_t y) + } + + /* Call VESA BIOS 0x4f07 to get display start, return status. */ +-grub_vbe_status_t ++grub_vbe_status_t + grub_vbe_bios_get_display_start (grub_uint32_t *x, + grub_uint32_t *y) + { +@@ -419,7 +419,7 @@ grub_vbe_bios_get_display_start (grub_uint32_t *x, + } + + /* Call VESA BIOS 0x4f0a. */ +-grub_vbe_status_t ++grub_vbe_status_t + grub_vbe_bios_get_pm_interface (grub_uint16_t *segment, grub_uint16_t *offset, + grub_uint16_t *length) + { +@@ -896,7 +896,7 @@ vbe2videoinfo (grub_uint32_t mode, + case GRUB_VBE_MEMORY_MODEL_YUV: + mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_YUV; + break; +- ++ + case GRUB_VBE_MEMORY_MODEL_DIRECT_COLOR: + mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_RGB; + break; +@@ -923,10 +923,10 @@ vbe2videoinfo (grub_uint32_t mode, + break; + case 8: + mode_info->bytes_per_pixel = 1; +- break; ++ break; + case 4: + mode_info->bytes_per_pixel = 0; +- break; ++ break; + } + + if (controller_info.version >= 0x300) +@@ -976,7 +976,7 @@ grub_video_vbe_iterate (int (*hook) (const struct grub_video_mode_info *info, vo + + static grub_err_t + grub_video_vbe_setup (unsigned int width, unsigned int height, +- grub_video_mode_type_t mode_type, ++ grub_video_mode_type_t mode_type, + grub_video_mode_type_t mode_mask) + { + grub_uint16_t *p; +@@ -1208,7 +1208,7 @@ grub_video_vbe_print_adapter_specific_info (void) + controller_info.version & 0xFF, + controller_info.oem_software_rev >> 8, + controller_info.oem_software_rev & 0xFF); +- ++ + /* The total_memory field is in 64 KiB units. */ + grub_printf_ (N_(" total memory: %d KiB\n"), + (controller_info.total_memory << 6)); +diff --git a/grub-core/video/i386/pc/vga.c b/grub-core/video/i386/pc/vga.c +index b2f776c997..50d0b5e028 100644 +--- a/grub-core/video/i386/pc/vga.c ++++ b/grub-core/video/i386/pc/vga.c +@@ -48,7 +48,7 @@ static struct + int back_page; + } framebuffer; + +-static unsigned char ++static unsigned char + grub_vga_set_mode (unsigned char mode) + { + struct grub_bios_int_registers regs; +@@ -182,10 +182,10 @@ grub_video_vga_setup (unsigned int width, unsigned int height, + + is_target = 1; + err = grub_video_fb_set_active_render_target (framebuffer.render_target); +- ++ + if (err) + return err; +- ++ + err = grub_video_fb_set_palette (0, GRUB_VIDEO_FBSTD_NUMCOLORS, + grub_video_fbstd_colors); + +diff --git a/grub-core/video/ieee1275.c b/grub-core/video/ieee1275.c +index b8e4b3feb3..0a89fa334d 100644 +--- a/grub-core/video/ieee1275.c ++++ b/grub-core/video/ieee1275.c +@@ -234,7 +234,7 @@ grub_video_ieee1275_setup (unsigned int width, unsigned int height, + /* TODO. */ + return grub_error (GRUB_ERR_IO, "can't set mode %dx%d", width, height); + } +- ++ + err = grub_video_ieee1275_fill_mode_info (dev, &framebuffer.mode_info); + if (err) + { +@@ -261,7 +261,7 @@ grub_video_ieee1275_setup (unsigned int width, unsigned int height, + + grub_video_ieee1275_set_palette (0, framebuffer.mode_info.number_of_colors, + grub_video_fbstd_colors); +- ++ + return err; + } + +diff --git a/grub-core/video/radeon_fuloong2e.c b/grub-core/video/radeon_fuloong2e.c +index b4da34b5ee..40917acb76 100644 +--- a/grub-core/video/radeon_fuloong2e.c ++++ b/grub-core/video/radeon_fuloong2e.c +@@ -75,7 +75,7 @@ find_card (grub_pci_device_t dev, grub_pci_id_t pciid, void *data) + if (((class >> 16) & 0xffff) != GRUB_PCI_CLASS_SUBCLASS_VGA + || pciid != 0x515a1002) + return 0; +- ++ + *found = 1; + + addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0); +@@ -139,7 +139,7 @@ grub_video_radeon_fuloong2e_setup (unsigned int width, unsigned int height, + framebuffer.mapped = 1; + + /* Prevent garbage from appearing on the screen. */ +- grub_memset (framebuffer.ptr, 0x55, ++ grub_memset (framebuffer.ptr, 0x55, + framebuffer.mode_info.height * framebuffer.mode_info.pitch); + + #ifndef TEST +@@ -152,7 +152,7 @@ grub_video_radeon_fuloong2e_setup (unsigned int width, unsigned int height, + return err; + + err = grub_video_fb_set_active_render_target (framebuffer.render_target); +- ++ + if (err) + return err; + +diff --git a/grub-core/video/radeon_yeeloong3a.c b/grub-core/video/radeon_yeeloong3a.c +index 52614feb69..48631c1815 100644 +--- a/grub-core/video/radeon_yeeloong3a.c ++++ b/grub-core/video/radeon_yeeloong3a.c +@@ -74,7 +74,7 @@ find_card (grub_pci_device_t dev, grub_pci_id_t pciid, void *data) + if (((class >> 16) & 0xffff) != GRUB_PCI_CLASS_SUBCLASS_VGA + || pciid != 0x96151002) + return 0; +- ++ + *found = 1; + + addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0); +@@ -137,7 +137,7 @@ grub_video_radeon_yeeloong3a_setup (unsigned int width, unsigned int height, + #endif + + /* Prevent garbage from appearing on the screen. */ +- grub_memset (framebuffer.ptr, 0, ++ grub_memset (framebuffer.ptr, 0, + framebuffer.mode_info.height * framebuffer.mode_info.pitch); + + #ifndef TEST +@@ -150,7 +150,7 @@ grub_video_radeon_yeeloong3a_setup (unsigned int width, unsigned int height, + return err; + + err = grub_video_fb_set_active_render_target (framebuffer.render_target); +- ++ + if (err) + return err; + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index 0157ff7420..54dfedf435 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -916,7 +916,7 @@ grub_png_convert_image (struct grub_png_data *data) + } + return; + } +- ++ + if (data->is_gray) + { + switch (data->bpp) +diff --git a/grub-core/video/readers/tga.c b/grub-core/video/readers/tga.c +index 7cb9d1d2a0..a9ec3a1b6e 100644 +--- a/grub-core/video/readers/tga.c ++++ b/grub-core/video/readers/tga.c +@@ -127,7 +127,7 @@ tga_load_palette (struct tga_data *data) + + if (len > sizeof (data->palette)) + len = sizeof (data->palette); +- ++ + if (grub_file_read (data->file, &data->palette, len) + != (grub_ssize_t) len) + return grub_errno; +diff --git a/grub-core/video/sis315_init.c b/grub-core/video/sis315_init.c +index ae5c1419c1..09c3c7bbea 100644 +--- a/grub-core/video/sis315_init.c ++++ b/grub-core/video/sis315_init.c +@@ -1,4 +1,4 @@ +-static const struct { grub_uint8_t reg; grub_uint8_t val; } sr_dump [] = ++static const struct { grub_uint8_t reg; grub_uint8_t val; } sr_dump [] = + { + { 0x28, 0x81 }, + { 0x2a, 0x00 }, +diff --git a/grub-core/video/sis315pro.c b/grub-core/video/sis315pro.c +index 22a0c85a64..4d2f9999a9 100644 +--- a/grub-core/video/sis315pro.c ++++ b/grub-core/video/sis315pro.c +@@ -103,7 +103,7 @@ find_card (grub_pci_device_t dev, grub_pci_id_t pciid, void *data) + if (((class >> 16) & 0xffff) != GRUB_PCI_CLASS_SUBCLASS_VGA + || pciid != GRUB_SIS315PRO_PCIID) + return 0; +- ++ + *found = 1; + + addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0); +@@ -218,7 +218,7 @@ grub_video_sis315pro_setup (unsigned int width, unsigned int height, + + #ifndef TEST + /* Prevent garbage from appearing on the screen. */ +- grub_memset (framebuffer.ptr, 0, ++ grub_memset (framebuffer.ptr, 0, + framebuffer.mode_info.height * framebuffer.mode_info.pitch); + grub_arch_sync_dma_caches (framebuffer.ptr, + framebuffer.mode_info.height +@@ -231,7 +231,7 @@ grub_video_sis315pro_setup (unsigned int width, unsigned int height, + | GRUB_VGA_IO_MISC_EXTERNAL_CLOCK_0 + | GRUB_VGA_IO_MISC_28MHZ + | GRUB_VGA_IO_MISC_ENABLE_VRAM_ACCESS +- | GRUB_VGA_IO_MISC_COLOR, ++ | GRUB_VGA_IO_MISC_COLOR, + GRUB_VGA_IO_MISC_WRITE + GRUB_MACHINE_PCI_IO_BASE); + + grub_vga_sr_write (0x86, 5); +@@ -335,7 +335,7 @@ grub_video_sis315pro_setup (unsigned int width, unsigned int height, + { + if (read_sis_cmd (0x5) != 0xa1) + write_sis_cmd (0x86, 0x5); +- ++ + write_sis_cmd (read_sis_cmd (0x20) | 0xa1, 0x20); + write_sis_cmd (read_sis_cmd (0x1e) | 0xda, 0x1e); + +diff --git a/grub-core/video/sm712.c b/grub-core/video/sm712.c +index 10c46eb654..65f59f84b1 100644 +--- a/grub-core/video/sm712.c ++++ b/grub-core/video/sm712.c +@@ -167,7 +167,7 @@ enum + GRUB_SM712_CR_SHADOW_VGA_VBLANK_START = 0x46, + GRUB_SM712_CR_SHADOW_VGA_VBLANK_END = 0x47, + GRUB_SM712_CR_SHADOW_VGA_VRETRACE_START = 0x48, +- GRUB_SM712_CR_SHADOW_VGA_VRETRACE_END = 0x49, ++ GRUB_SM712_CR_SHADOW_VGA_VRETRACE_END = 0x49, + GRUB_SM712_CR_SHADOW_VGA_OVERFLOW = 0x4a, + GRUB_SM712_CR_SHADOW_VGA_CELL_HEIGHT = 0x4b, + GRUB_SM712_CR_SHADOW_VGA_HDISPLAY_END = 0x4c, +@@ -375,7 +375,7 @@ find_card (grub_pci_device_t dev, grub_pci_id_t pciid, void *data) + if (((class >> 16) & 0xffff) != GRUB_PCI_CLASS_SUBCLASS_VGA + || pciid != GRUB_SM712_PCIID) + return 0; +- ++ + *found = 1; + + addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0); +@@ -471,7 +471,7 @@ grub_video_sm712_setup (unsigned int width, unsigned int height, + + #if !defined (TEST) && !defined(GENINIT) + /* Prevent garbage from appearing on the screen. */ +- grub_memset ((void *) framebuffer.cached_ptr, 0, ++ grub_memset ((void *) framebuffer.cached_ptr, 0, + framebuffer.mode_info.height * framebuffer.mode_info.pitch); + #endif + +@@ -482,7 +482,7 @@ grub_video_sm712_setup (unsigned int width, unsigned int height, + grub_sm712_sr_write (0x2, 0x6b); + grub_sm712_write_reg (0, GRUB_VGA_IO_PIXEL_MASK); + grub_sm712_sr_write (GRUB_VGA_SR_RESET_ASYNC, GRUB_VGA_SR_RESET); +- grub_sm712_write_reg (GRUB_VGA_IO_MISC_NEGATIVE_VERT_POLARITY ++ grub_sm712_write_reg (GRUB_VGA_IO_MISC_NEGATIVE_VERT_POLARITY + | GRUB_VGA_IO_MISC_NEGATIVE_HORIZ_POLARITY + | GRUB_VGA_IO_MISC_UPPER_64K + | GRUB_VGA_IO_MISC_EXTERNAL_CLOCK_0 +@@ -694,7 +694,7 @@ grub_video_sm712_setup (unsigned int width, unsigned int height, + for (i = 0; i < ARRAY_SIZE (dda_lookups); i++) + grub_sm712_write_dda_lookup (i, dda_lookups[i].compare, dda_lookups[i].dda, + dda_lookups[i].vcentering); +- ++ + /* Undocumented */ + grub_sm712_cr_write (0, 0x9c); + grub_sm712_cr_write (0, 0x9d); +diff --git a/grub-core/video/video.c b/grub-core/video/video.c +index 983424107c..8937da745d 100644 +--- a/grub-core/video/video.c ++++ b/grub-core/video/video.c +@@ -491,13 +491,13 @@ parse_modespec (const char *current_mode, int *width, int *height, int *depth) + current_mode); + + param++; +- ++ + *width = grub_strtoul (value, 0, 0); + if (grub_errno != GRUB_ERR_NONE) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("invalid video mode specification `%s'"), + current_mode); +- ++ + /* Find height value. */ + value = param; + param = grub_strchr(param, 'x'); +@@ -513,13 +513,13 @@ parse_modespec (const char *current_mode, int *width, int *height, int *depth) + { + /* We have optional color depth value. */ + param++; +- ++ + *height = grub_strtoul (value, 0, 0); + if (grub_errno != GRUB_ERR_NONE) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("invalid video mode specification `%s'"), + current_mode); +- ++ + /* Convert color depth value. */ + value = param; + *depth = grub_strtoul (value, 0, 0); +-- +2.34.1 + diff --git a/0002-AUDIT-0-http-boot-tracker-bug.patch b/0002-AUDIT-0-http-boot-tracker-bug.patch new file mode 100644 index 0000000..8c74ed8 --- /dev/null +++ b/0002-AUDIT-0-http-boot-tracker-bug.patch @@ -0,0 +1,65 @@ +From b5c3492f31a98f5ef0f9bec2c0665ad0b71ad5cb Mon Sep 17 00:00:00 2001 +From: Sebastian Krahmer +Date: Tue, 28 Nov 2017 17:24:38 +0800 +Subject: [PATCH] AUDIT-0: http boot tracker bug + +Fixing a memory leak in case of error, and a integer overflow, leading to a +heap overflow due to overly large chunk sizes. + +We need to check against some maximum value, otherwise values like 0xffffffff +will eventually lead in the allocation functions to small sized buffers, since +the len is rounded up to the next reasonable alignment. The following memcpy +will then smash the heap, leading to RCE. + +This is no big issue for pure http boot, since its going to execute an +untrusted kernel anyway, but it will break trusted boot scenarios, where only +signed code is allowed to be executed. + +Signed-off-by: Michael Chang +--- + grub-core/net/efi/net.c | 4 +++- + grub-core/net/http.c | 5 ++++- + 2 files changed, 7 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c +index 0bac343b4..5bc604ff0 100644 +--- a/grub-core/net/efi/net.c ++++ b/grub-core/net/efi/net.c +@@ -645,8 +645,10 @@ grub_efihttp_chunk_read (grub_file_t file, char *buf, + + rd = efi_net_interface (read, file, chunk, sz); + +- if (rd <= 0) ++ if (rd <= 0) { ++ grub_free (chunk); + return rd; ++ } + + if (buf) + { +diff --git a/grub-core/net/http.c b/grub-core/net/http.c +index f182d7b87..5004ecfee 100644 +--- a/grub-core/net/http.c ++++ b/grub-core/net/http.c +@@ -31,7 +31,8 @@ GRUB_MOD_LICENSE ("GPLv3+"); + + enum + { +- HTTP_PORT = 80 ++ HTTP_PORT = 80, ++ HTTP_MAX_CHUNK_SIZE = 0x80000000 + }; + + +@@ -78,6 +79,8 @@ parse_line (grub_file_t file, http_data_t data, char *ptr, grub_size_t len) + if (data->in_chunk_len == 2) + { + data->chunk_rem = grub_strtoul (ptr, 0, 16); ++ if (data->chunk_rem > HTTP_MAX_CHUNK_SIZE) ++ return GRUB_ERR_NET_PACKET_TOO_BIG; + grub_errno = GRUB_ERR_NONE; + if (data->chunk_rem == 0) + { +-- +2.12.0 + diff --git a/0002-Add-grub_disk_write_tail-helper-function.patch b/0002-Add-grub_disk_write_tail-helper-function.patch new file mode 100644 index 0000000..74d5ae8 --- /dev/null +++ b/0002-Add-grub_disk_write_tail-helper-function.patch @@ -0,0 +1,60 @@ +From c0d00403a297d6023eab6189ba87dc8a3f6d1e85 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Mon, 7 Feb 2022 20:44:40 +0800 +Subject: [PATCH 2/5] Add grub_disk_write_tail helper function + +This helps in writing data to partition where the end of buffer is +aligned to end of partition. + +Signed-off-by: Michael Chang +--- + grub-core/lib/disk.c | 18 ++++++++++++++++++ + include/grub/disk.h | 3 +++ + 2 files changed, 21 insertions(+) + +diff --git a/grub-core/lib/disk.c b/grub-core/lib/disk.c +index b4eb064a81..08e24485f0 100644 +--- a/grub-core/lib/disk.c ++++ b/grub-core/lib/disk.c +@@ -51,6 +51,24 @@ grub_disk_cache_invalidate (unsigned long dev_id, unsigned long disk_id, + } + } + ++grub_err_t ++grub_disk_write_tail (grub_disk_t disk, grub_size_t size, const void *buf) ++{ ++ grub_partition_t part; ++ grub_disk_addr_t sector; ++ grub_off_t offset; ++ ++ if (!disk->partition) ++ return GRUB_ERR_NONE; ++ ++ part = disk->partition; ++ sector = part->len; ++ sector -= (size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS; ++ offset = size & (GRUB_DISK_SECTOR_SIZE - 1); ++ ++ return grub_disk_write (disk, sector, offset, size, buf); ++} ++ + grub_err_t + grub_disk_write (grub_disk_t disk, grub_disk_addr_t sector, + grub_off_t offset, grub_size_t size, const void *buf) +diff --git a/include/grub/disk.h b/include/grub/disk.h +index f95aca929a..6d656c4315 100644 +--- a/include/grub/disk.h ++++ b/include/grub/disk.h +@@ -232,6 +232,9 @@ grub_err_t EXPORT_FUNC(grub_disk_read) (grub_disk_t disk, + grub_off_t offset, + grub_size_t size, + void *buf); ++grub_err_t grub_disk_write_tail (grub_disk_t disk, ++ grub_size_t size, ++ const void *buf); + grub_err_t grub_disk_write (grub_disk_t disk, + grub_disk_addr_t sector, + grub_off_t offset, +-- +2.34.1 + diff --git a/0002-Arm-check-for-the-PE-magic-for-the-compiled-arch.patch b/0002-Arm-check-for-the-PE-magic-for-the-compiled-arch.patch new file mode 100644 index 0000000..7c64fed --- /dev/null +++ b/0002-Arm-check-for-the-PE-magic-for-the-compiled-arch.patch @@ -0,0 +1,66 @@ +From 337b3d963d28b3544e8817428fb68ca559613a39 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 9 Sep 2021 10:59:28 -0400 +Subject: [PATCH 2/2] Arm: check for the PE magic for the compiled arch + +In "arm64: Fix EFI loader kernel image allocation", Ben fixed the kernel +alignment to match the alignment given in the PE header. In doing so, a +check for valid PE magic was added, which was hard-coded to the value +seen on Aarch64 (GRUB_PE32_PE64_MAGIC). + +Unfortunately, this code is shared between 64-bit and 32-bit, and so +that value broke 32-bit Arm systems. + +This patch adds a constant definition for GRUB_PE32_PEXX_MAGIC, which is +either GRUB_PE32_PE64_MAGIC or GRUB_PE32_PE32_MAGIC, depending on which +platform is being built, and uses it in the header magic check. + +Resolves: rhbz#2000756 + +Signed-off-by: Peter Jones +--- + grub-core/loader/arm64/efi/linux.c | 2 +- + include/grub/arm/linux.h | 1 + + include/grub/arm64/linux.h | 1 + + 3 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/grub-core/loader/arm64/efi/linux.c b/grub-core/loader/arm64/efi/linux.c +index 4da49a182..87cb2f97c 100644 +--- a/grub-core/loader/arm64/efi/linux.c ++++ b/grub-core/loader/arm64/efi/linux.c +@@ -376,7 +376,7 @@ parse_pe_header (void *kernel, grub_uint64_t *total_size, + + pe = (void *)((unsigned long)kernel + lh->hdr_offset); + +- if (pe->opt.magic != GRUB_PE32_PE64_MAGIC) ++ if (pe->opt.magic != GRUB_PE32_PEXX_MAGIC) + return grub_error(GRUB_ERR_BAD_OS, "Invalid PE optional header magic"); + + *total_size = pe->opt.image_size; +diff --git a/include/grub/arm/linux.h b/include/grub/arm/linux.h +index b582f67f6..966a5074f 100644 +--- a/include/grub/arm/linux.h ++++ b/include/grub/arm/linux.h +@@ -44,6 +44,7 @@ struct grub_arm_linux_pe_header + + #if defined(__arm__) + # define GRUB_LINUX_ARMXX_MAGIC_SIGNATURE GRUB_LINUX_ARM_MAGIC_SIGNATURE ++# define GRUB_PE32_PEXX_MAGIC GRUB_PE32_PE32_MAGIC + # define linux_arch_kernel_header linux_arm_kernel_header + # define grub_armxx_linux_pe_header grub_arm_linux_pe_header + #endif +diff --git a/include/grub/arm64/linux.h b/include/grub/arm64/linux.h +index de99d39c0..b4b91473a 100644 +--- a/include/grub/arm64/linux.h ++++ b/include/grub/arm64/linux.h +@@ -48,6 +48,7 @@ struct grub_arm64_linux_pe_header + + #if defined(__aarch64__) + # define GRUB_LINUX_ARMXX_MAGIC_SIGNATURE GRUB_LINUX_ARM64_MAGIC_SIGNATURE ++# define GRUB_PE32_PEXX_MAGIC GRUB_PE32_PE64_MAGIC + # define linux_arch_kernel_header linux_arm64_kernel_header + # define grub_armxx_linux_pe_header grub_arm64_linux_pe_header + #endif +-- +2.31.1 + diff --git a/0002-Fix-race-in-EFI-validation.patch b/0002-Fix-race-in-EFI-validation.patch new file mode 100644 index 0000000..4a8bc7c --- /dev/null +++ b/0002-Fix-race-in-EFI-validation.patch @@ -0,0 +1,92 @@ +From e72dcb40356f56efd86ab88c2f5cb7411d1e898b Mon Sep 17 00:00:00 2001 +From: Matthew Garrett +Date: Tue, 14 Jul 2015 16:58:51 -0700 +Subject: [PATCH 02/11] Fix race in EFI validation + +--- + grub-core/loader/i386/efi/linux.c | 40 +++++++------------------------ + 1 file changed, 9 insertions(+), 31 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 06814cae3..1e09c88ab 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -154,7 +154,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_file_t file = 0; + struct linux_i386_kernel_header lh; + grub_ssize_t len, start, filelen; +- void *kernel; ++ void *kernel = NULL; + grub_err_t err; + + grub_dl_ref (my_mod); +@@ -185,10 +185,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- grub_file_seek (file, 0); +- +- grub_free(kernel); +- + params = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(16384)); + + if (! params) +@@ -199,13 +195,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + grub_memset (params, 0, 16384); + +- if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) +- { +- if (!grub_errno) +- grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), +- argv[0]); +- goto fail; +- } ++ grub_memcpy (&lh, kernel, sizeof (lh)); + + if (lh.boot_flag != grub_cpu_to_le16 (0xaa55)) + { +@@ -271,26 +261,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- if (grub_file_seek (file, start) == (grub_off_t) -1) +- { +- grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), +- argv[0]); +- goto fail; +- } +- +- if (grub_file_read (file, kernel_mem, len) != len && !grub_errno) +- { +- grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), +- argv[0]); +- } +- +- if (grub_errno == GRUB_ERR_NONE) +- { +- grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); +- loaded = 1; +- lh.code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem; +- } ++ grub_memcpy (kernel_mem, (char *)kernel + start, len); ++ grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); ++ loaded=1; + ++ lh.code32_start = (grub_uint32_t)(grub_uint64_t) kernel_mem; + /* Grub linuxefi erroneously initialize linux's boot_params with non-zero values. (bsc#1025563) + + From https://www.kernel.org/doc/Documentation/x86/boot.txt: +@@ -307,6 +282,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + if (file) + grub_file_close (file); + ++ if (kernel) ++ grub_free (kernel); ++ + if (grub_errno != GRUB_ERR_NONE) + { + grub_dl_unref (my_mod); +-- +2.31.1 + diff --git a/0002-arm64-make-sure-fdt-has-address-cells-and-size-cells.patch b/0002-arm64-make-sure-fdt-has-address-cells-and-size-cells.patch new file mode 100644 index 0000000..f9cd0bc --- /dev/null +++ b/0002-arm64-make-sure-fdt-has-address-cells-and-size-cells.patch @@ -0,0 +1,45 @@ +From e27acddebd30175587155613042abffd2e9a5de8 Mon Sep 17 00:00:00 2001 +From: Mark Salter +Date: Mon, 17 Apr 2017 08:44:29 -0400 +Subject: [PATCH 2/9] arm64: make sure fdt has #address-cells and #size-cells + properties + +Recent upstream changes to kexec-tools relies on #address-cells +and #size-cells properties in the FDT. If grub2 needs to create +a chosen node, it is likely because firmware did not provide one. +In that case, set #address-cells and #size-cells properties to +make sure they exist. +--- + grub-core/loader/arm64/efi/linux.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/grub-core/loader/arm64/efi/linux.c b/grub-core/loader/arm64/efi/linux.c +index d81a6d843..98c4f038b 100644 +--- a/grub-core/loader/arm64/efi/linux.c ++++ b/grub-core/loader/arm64/efi/linux.c +@@ -126,7 +126,21 @@ finalize_params_linux (void) + + node = grub_fdt_find_subnode (fdt, 0, "chosen"); + if (node < 0) +- node = grub_fdt_add_subnode (fdt, 0, "chosen"); ++ { ++ /* ++ * If we have to create a chosen node, Make sure we ++ * have #address-cells and #size-cells properties. ++ */ ++ retval = grub_fdt_set_prop32(fdt, 0, "#address-cells", 2); ++ if (retval) ++ goto failure; ++ ++ retval = grub_fdt_set_prop32(fdt, 0, "#size-cells", 2); ++ if (retval) ++ goto failure; ++ ++ node = grub_fdt_add_subnode (fdt, 0, "chosen"); ++ } + + if (node < 1) + goto failure; +-- +2.26.2 + diff --git a/0002-cmdline-Provide-cmdline-functions-as-module.patch b/0002-cmdline-Provide-cmdline-functions-as-module.patch new file mode 100644 index 0000000..089a92e --- /dev/null +++ b/0002-cmdline-Provide-cmdline-functions-as-module.patch @@ -0,0 +1,54 @@ +From 42cb0ebbffd660608612f9e32150a6596c6933c4 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Mon, 17 Aug 2020 17:25:56 +0800 +Subject: [PATCH 2/2] cmdline: Provide cmdline functions as module + +The command line processing is needed by many loader modules, hence we should +make it a sharable one rather than belonging to linux loader. This can cut the +dependency to linux module among multiple loaders like multiboot linuxefi and +so on to make custom boot image much more flexible to compose. + +Signed-off-by: Michael Chang +--- + grub-core/Makefile.core.def | 6 +++++- + grub-core/lib/cmdline.c | 3 +++ + 2 files changed, 8 insertions(+), 1 deletion(-) + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index c413267a0..6045da47b 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -1790,7 +1790,6 @@ module = { + riscv64 = loader/riscv/linux.c; + emu = loader/emu/linux.c; + common = loader/linux.c; +- common = lib/cmdline.c; + }; + + module = { +@@ -2518,3 +2517,8 @@ module = { + common = commands/i386/wrmsr.c; + enable = x86; + }; ++ ++module = { ++ name = cmdline; ++ common = lib/cmdline.c; ++}; +diff --git a/grub-core/lib/cmdline.c b/grub-core/lib/cmdline.c +index ed0b149dc..bd392e30f 100644 +--- a/grub-core/lib/cmdline.c ++++ b/grub-core/lib/cmdline.c +@@ -19,6 +19,9 @@ + + #include + #include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); + + static unsigned int check_arg (char *c, int *has_space) + { +-- +2.26.2 + diff --git a/0002-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch b/0002-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch new file mode 100644 index 0000000..6af5890 --- /dev/null +++ b/0002-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch @@ -0,0 +1,40 @@ +From 974b90795cae39ced3f8d5652caafbeb16899b07 Mon Sep 17 00:00:00 2001 +From: Lu Ken +Date: Wed, 13 Jul 2022 10:06:11 +0800 +Subject: [PATCH 2/3] commands/efi/tpm: Use grub_strcpy() instead of + grub_memcpy() + +The event description is a string, so using grub_strcpy() is cleaner than +using grub_memcpy(). + +Signed-off-by: Lu Ken +Reviewed-by: Daniel Kiper +--- + grub-core/commands/efi/tpm.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c +index e6953e3f5..8fe3101f3 100644 +--- a/grub-core/commands/efi/tpm.c ++++ b/grub-core/commands/efi/tpm.c +@@ -176,7 +176,7 @@ grub_tpm1_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf, + event->PCRIndex = pcr; + event->EventType = EV_IPL; + event->EventSize = grub_strlen (description) + 1; +- grub_memcpy (event->Event, description, event->EventSize); ++ grub_strcpy ((char *) event->Event, description); + + algorithm = TCG_ALG_SHA; + status = efi_call_7 (tpm->log_extend_event, tpm, (grub_addr_t) buf, (grub_uint64_t) size, +@@ -213,7 +213,7 @@ grub_tpm2_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf, + event->Header.EventType = EV_IPL; + event->Size = + sizeof (*event) - sizeof (event->Event) + grub_strlen (description) + 1; +- grub_memcpy (event->Event, description, grub_strlen (description) + 1); ++ grub_strcpy ((char *) event->Event, description); + + status = efi_call_5 (tpm->hash_log_extend_event, tpm, 0, (grub_addr_t) buf, + (grub_uint64_t) size, event); +-- +2.35.3 + diff --git a/0002-cryptodisk-Refactor-to-discard-have_it-global.patch b/0002-cryptodisk-Refactor-to-discard-have_it-global.patch new file mode 100644 index 0000000..6d61c67 --- /dev/null +++ b/0002-cryptodisk-Refactor-to-discard-have_it-global.patch @@ -0,0 +1,187 @@ +From 4ace73cc192bc63a00f4208b34981a6d91947811 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:51 -0600 +Subject: [PATCH 02/14] cryptodisk: Refactor to discard have_it global + +The global "have_it" was never used by the crypto-backends, but was used to +determine if a crypto-backend successfully mounted a cryptodisk with a given +UUID. This is not needed however, because grub_device_iterate() will return +1 if and only if grub_cryptodisk_scan_device() returns 1. And +grub_cryptodisk_scan_device() will now only return 1 if a search_uuid has +been specified and a cryptodisk was successfully setup by a crypto-backend or +a cryptodisk of the requested UUID is already open. + +To implement this grub_cryptodisk_scan_device_real() is modified to return +a cryptodisk or NULL on failure and having the appropriate grub_errno set to +indicated failure. Note that grub_cryptodisk_scan_device_real() will fail now +with a new errno GRUB_ERR_BAD_MODULE when none of the cryptodisk backend +modules succeed in identifying the source disk. + +With this change grub_device_iterate() will return 1 when a crypto device is +successfully decrypted or when the source device has already been successfully +opened. Prior to this change, trying to mount an already successfully opened +device would trigger an error with the message "no such cryptodisk found", +which is at best misleading. The mount should silently succeed in this case, +which is what happens with this patch. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 56 +++++++++++++++++++++++-------------- + 1 file changed, 35 insertions(+), 21 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 90f82b2d39..9df3d310fe 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -983,7 +983,7 @@ grub_util_cryptodisk_get_uuid (grub_disk_t disk) + + #endif + +-static int check_boot, have_it; ++static int check_boot; + static char *search_uuid; + + static void +@@ -995,7 +995,7 @@ cryptodisk_close (grub_cryptodisk_t dev) + grub_free (dev); + } + +-static grub_err_t ++static grub_cryptodisk_t + grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source) + { + grub_err_t err; +@@ -1005,13 +1005,13 @@ grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source) + dev = grub_cryptodisk_get_by_source_disk (source); + + if (dev) +- return GRUB_ERR_NONE; ++ return dev; + + FOR_CRYPTODISK_DEVS (cr) + { + dev = cr->scan (source, search_uuid, check_boot); + if (grub_errno) +- return grub_errno; ++ return NULL; + if (!dev) + continue; + +@@ -1019,16 +1019,16 @@ grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source) + if (err) + { + cryptodisk_close (dev); +- return err; ++ return NULL; + } + + grub_cryptodisk_insert (dev, name, source); + +- have_it = 1; +- +- return GRUB_ERR_NONE; ++ return dev; + } +- return GRUB_ERR_NONE; ++ ++ grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk module can handle this device"); ++ return NULL; + } + + #ifdef GRUB_UTIL +@@ -1082,8 +1082,10 @@ static int + grub_cryptodisk_scan_device (const char *name, + void *data __attribute__ ((unused))) + { +- grub_err_t err; ++ int ret = 0; + grub_disk_t source; ++ grub_cryptodisk_t dev; ++ grub_errno = GRUB_ERR_NONE; + + /* Try to open disk. */ + source = grub_disk_open (name); +@@ -1093,13 +1095,26 @@ grub_cryptodisk_scan_device (const char *name, + return 0; + } + +- err = grub_cryptodisk_scan_device_real (name, source); ++ dev = grub_cryptodisk_scan_device_real (name, source); ++ if (dev) ++ { ++ ret = (search_uuid != NULL && grub_strcasecmp (search_uuid, dev->uuid) == 0); ++ goto cleanup; ++ } + +- grub_disk_close (source); +- +- if (err) ++ /* ++ * Do not print error when err is GRUB_ERR_BAD_MODULE to avoid many unhelpful ++ * error messages. ++ */ ++ if (grub_errno == GRUB_ERR_BAD_MODULE) ++ grub_error_pop (); ++ ++ if (grub_errno != GRUB_ERR_NONE) + grub_print_error (); +- return have_it && search_uuid ? 1 : 0; ++ ++ cleanup: ++ grub_disk_close (source); ++ return ret; + } + + static grub_err_t +@@ -1110,9 +1125,9 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + if (argc < 1 && !state[1].set && !state[2].set) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); + +- have_it = 0; + if (state[0].set) + { ++ int found_uuid; + grub_cryptodisk_t dev; + + dev = grub_cryptodisk_get_by_uuid (args[0]); +@@ -1125,10 +1140,10 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + + check_boot = state[2].set; + search_uuid = args[0]; +- grub_device_iterate (&grub_cryptodisk_scan_device, NULL); ++ found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, NULL); + search_uuid = NULL; + +- if (!have_it) ++ if (!found_uuid) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found"); + return GRUB_ERR_NONE; + } +@@ -1142,7 +1157,6 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + } + else + { +- grub_err_t err; + grub_disk_t disk; + grub_cryptodisk_t dev; + char *diskname; +@@ -1178,13 +1192,13 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + return GRUB_ERR_NONE; + } + +- err = grub_cryptodisk_scan_device_real (diskname, disk); ++ dev = grub_cryptodisk_scan_device_real (diskname, disk); + + grub_disk_close (disk); + if (disklast) + *disklast = ')'; + +- return err; ++ return (dev == NULL) ? grub_errno : GRUB_ERR_NONE; + } + } + +-- +2.34.1 + diff --git a/0002-devmapper-getroot-Set-up-cheated-LUKS2-cryptodisk-mo.patch b/0002-devmapper-getroot-Set-up-cheated-LUKS2-cryptodisk-mo.patch new file mode 100644 index 0000000..f1c01da --- /dev/null +++ b/0002-devmapper-getroot-Set-up-cheated-LUKS2-cryptodisk-mo.patch @@ -0,0 +1,127 @@ +From a25627c13b7e1e6998a14b5dd23b04b28465d737 Mon Sep 17 00:00:00 2001 +From: Josselin Poiret via Grub-devel +Date: Tue, 14 Jun 2022 15:47:30 +0200 +Subject: [PATCH 02/10] devmapper/getroot: Set up cheated LUKS2 cryptodisk + mount from DM parameters + +This lets a LUKS2 cryptodisk have its cipher and hash filled out, +otherwise they wouldn't be initialized if cheat mounted. +--- + grub-core/osdep/devmapper/getroot.c | 91 +++++++++++++++++++++++++++++++++++- + 1 file changed, 90 insertions(+), 1 deletion(-) + +--- a/grub-core/osdep/devmapper/getroot.c ++++ b/grub-core/osdep/devmapper/getroot.c +@@ -51,6 +51,8 @@ + #include + #include + ++#include ++ + static int + grub_util_open_dm (const char *os_dev, struct dm_tree **tree, + struct dm_tree_node **node) +@@ -186,7 +188,6 @@ + && lastsubdev) + { + char *grdev = grub_util_get_grub_dev (lastsubdev); +- dm_tree_free (tree); + if (grdev) + { + grub_err_t err; +@@ -194,7 +195,95 @@ + if (err) + grub_util_error (_("can't mount encrypted volume `%s': %s"), + lastsubdev, grub_errmsg); ++ if (strncmp (uuid, "CRYPT-LUKS2-", sizeof ("CRYPT-LUKS2-") - 1) == 0) ++ { ++ /* set LUKS2 cipher from dm parameters, since it is not ++ * possible to determine the correct one without ++ * unlocking, as there might be multiple segments. ++ */ ++ grub_disk_t source; ++ grub_cryptodisk_t cryptodisk; ++ grub_uint64_t start, length; ++ char *target_type; ++ char *params; ++ const char *name; ++ char *cipher, *cipher_mode; ++ struct dm_task *dmt; ++ char *seek_head, *c; ++ unsigned int remaining; ++ ++ source = grub_disk_open (grdev); ++ cryptodisk = grub_cryptodisk_get_by_source_disk (source); ++ grub_disk_close (source); ++ ++ name = dm_tree_node_get_name (node); ++ ++ grub_util_info ("populating parameters of cryptomount `%s' from DM device `%s'", ++ uuid, name); ++ ++ dmt = dm_task_create (DM_DEVICE_TABLE); ++ if (dmt == 0) ++ grub_util_error (_("can't create dm task DM_DEVICE_TABLE")); ++ if (dm_task_set_name (dmt, name) == 0) ++ grub_util_error (_("can't set dm task name to `%s'"), name); ++ if (dm_task_run (dmt) == 0) ++ grub_util_error (_("can't run dm task for `%s'"), name); ++ /* dm_get_next_target doesn't have any error modes, everything has ++ * been handled by dm_task_run. ++ */ ++ dm_get_next_target (dmt, NULL, &start, &length, ++ &target_type, ¶ms); ++ if (strncmp (target_type, "crypt", sizeof ("crypt")) != 0) ++ grub_util_error (_("dm target of type `%s' is not `crypt'"), ++ target_type); ++ ++ /* dm target parameters for dm-crypt is ++ * [<#opt_params> ...] ++ */ ++ c = params; ++ remaining = grub_strlen (c); ++ ++ /* first, get the cipher name from the cipher */ ++ if (!(seek_head = grub_memchr (c, '-', remaining))) ++ grub_util_error (_("can't get cipher from dm-crypt parameters `%s'"), ++ params); ++ cipher = grub_strndup (c, seek_head - c); ++ remaining -= seek_head - c + 1; ++ c = seek_head + 1; ++ ++ /* now, the cipher mode */ ++ if (!(seek_head = grub_memchr (c, ' ', remaining))) ++ grub_util_error (_("can't get cipher mode from dm-crypt parameters `%s'"), ++ params); ++ cipher_mode = grub_strndup (c, seek_head - c); ++ remaining -= seek_head - c + 1; ++ c = seek_head + 1; ++ ++ err = grub_cryptodisk_setcipher (cryptodisk, cipher, cipher_mode); ++ if (err) ++ { ++ grub_util_error (_("can't set cipher of cryptodisk `%s' to `%s' with mode `%s'"), ++ uuid, cipher, cipher_mode); ++ } ++ ++ grub_free (cipher); ++ grub_free (cipher_mode); ++ ++ /* This is the only hash usable by PBKDF2, and we don't ++ * have Argon2 support yet, so set it by default, ++ * otherwise grub-probe would miss the required ++ * abstraction ++ */ ++ cryptodisk->hash = grub_crypto_lookup_md_by_name ("sha256"); ++ if (cryptodisk->hash == 0) ++ { ++ grub_util_error (_("can't lookup hash sha256 by name")); ++ } ++ ++ dm_task_destroy (dmt); ++ } + } ++ dm_tree_free (tree); + grub_free (grdev); + } + else diff --git a/0002-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch b/0002-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch new file mode 100644 index 0000000..453f233 --- /dev/null +++ b/0002-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch @@ -0,0 +1,113 @@ +From 84c4323c004b495993a3d0dbfa94d8675ae06f03 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Fri, 5 Aug 2022 00:51:20 +0800 +Subject: [PATCH 02/12] font: Fix size overflow in + grub_font_get_glyph_internal() + +The length of memory allocation and file read may overflow. This patch +fixes the problem by using safemath macros. + +There is a lot of code repetition like "(x * y + 7) / 8". It is unsafe +if overflow happens. This patch introduces grub_video_bitmap_calc_1bpp_bufsz(). +It is safe replacement for such code. It has safemath-like prototype. + +This patch also introduces grub_cast(value, pointer), it casts value to +typeof(*pointer) then store the value to *pointer. It returns true when +overflow occurs or false if there is no overflow. The semantics of arguments +and return value are designed to be consistent with other safemath macros. + +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +--- + grub-core/font/font.c | 17 +++++++++++++---- + include/grub/bitmap.h | 18 ++++++++++++++++++ + include/grub/safemath.h | 2 ++ + 3 files changed, 33 insertions(+), 4 deletions(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index 2f09a4a55..6a3fbebbd 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -739,7 +739,8 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code) + grub_int16_t xoff; + grub_int16_t yoff; + grub_int16_t dwidth; +- int len; ++ grub_ssize_t len; ++ grub_size_t sz; + + if (index_entry->glyph) + /* Return cached glyph. */ +@@ -768,9 +769,17 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code) + return 0; + } + +- len = (width * height + 7) / 8; +- glyph = grub_malloc (sizeof (struct grub_font_glyph) + len); +- if (!glyph) ++ /* Calculate real struct size of current glyph. */ ++ if (grub_video_bitmap_calc_1bpp_bufsz (width, height, &len) || ++ grub_add (sizeof (struct grub_font_glyph), len, &sz)) ++ { ++ remove_font (font); ++ return 0; ++ } ++ ++ /* Allocate and initialize the glyph struct. */ ++ glyph = grub_malloc (sz); ++ if (glyph == NULL) + { + remove_font (font); + return 0; +diff --git a/include/grub/bitmap.h b/include/grub/bitmap.h +index 5728f8ca3..0d9603f61 100644 +--- a/include/grub/bitmap.h ++++ b/include/grub/bitmap.h +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + struct grub_video_bitmap + { +@@ -79,6 +80,23 @@ grub_video_bitmap_get_height (struct grub_video_bitmap *bitmap) + return bitmap->mode_info.height; + } + ++/* ++ * Calculate and store the size of data buffer of 1bit bitmap in result. ++ * Equivalent to "*result = (width * height + 7) / 8" if no overflow occurs. ++ * Return true when overflow occurs or false if there is no overflow. ++ * This function is intentionally implemented as a macro instead of ++ * an inline function. Although a bit awkward, it preserves data types for ++ * safemath macros and reduces macro side effects as much as possible. ++ * ++ * XXX: Will report false overflow if width * height > UINT64_MAX. ++ */ ++#define grub_video_bitmap_calc_1bpp_bufsz(width, height, result) \ ++({ \ ++ grub_uint64_t _bitmap_pixels; \ ++ grub_mul ((width), (height), &_bitmap_pixels) ? 1 : \ ++ grub_cast (_bitmap_pixels / GRUB_CHAR_BIT + !!(_bitmap_pixels % GRUB_CHAR_BIT), (result)); \ ++}) ++ + void EXPORT_FUNC (grub_video_bitmap_get_mode_info) (struct grub_video_bitmap *bitmap, + struct grub_video_mode_info *mode_info); + +diff --git a/include/grub/safemath.h b/include/grub/safemath.h +index c17b89bba..bb0f826de 100644 +--- a/include/grub/safemath.h ++++ b/include/grub/safemath.h +@@ -30,6 +30,8 @@ + #define grub_sub(a, b, res) __builtin_sub_overflow(a, b, res) + #define grub_mul(a, b, res) __builtin_mul_overflow(a, b, res) + ++#define grub_cast(a, res) grub_add ((a), 0, (res)) ++ + #else + #error gcc 5.1 or newer or clang 3.8 or newer is required + #endif +-- +2.35.3 + diff --git a/0002-fs-ntfs-Fix-an-OOB-read-when-reading-data-from-the-r.patch b/0002-fs-ntfs-Fix-an-OOB-read-when-reading-data-from-the-r.patch new file mode 100644 index 0000000..32359f4 --- /dev/null +++ b/0002-fs-ntfs-Fix-an-OOB-read-when-reading-data-from-the-r.patch @@ -0,0 +1,58 @@ +From 0ed2458cc4eff6d9a9199527e2a0b6d445802f94 Mon Sep 17 00:00:00 2001 +From: Maxim Suhanov +Date: Mon, 28 Aug 2023 16:32:33 +0300 +Subject: [PATCH 2/6] fs/ntfs: Fix an OOB read when reading data from the + resident $DATA attribute + +When reading a file containing resident data, i.e., the file data is stored in +the $DATA attribute within the NTFS file record, not in external clusters, +there are no checks that this resident data actually fits the corresponding +file record segment. + +When parsing a specially-crafted file system image, the current NTFS code will +read the file data from an arbitrary, attacker-chosen memory offset and of +arbitrary, attacker-chosen length. + +This allows an attacker to display arbitrary chunks of memory, which could +contain sensitive information like password hashes or even plain-text, +obfuscated passwords from BS EFI variables. + +This fix implements a check to ensure that resident data is read from the +corresponding file record segment only. + +Fixes: CVE-2023-4693 + +Reported-by: Maxim Suhanov +Signed-off-by: Maxim Suhanov +Reviewed-by: Daniel Kiper +--- + grub-core/fs/ntfs.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index c3c4db117..a68e173d8 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -401,7 +401,18 @@ read_data (struct grub_ntfs_attr *at, grub_uint8_t *pa, grub_uint8_t *dest, + { + if (ofs + len > u32at (pa, 0x10)) + return grub_error (GRUB_ERR_BAD_FS, "read out of range"); +- grub_memcpy (dest, pa + u32at (pa, 0x14) + ofs, len); ++ ++ if (u32at (pa, 0x10) > (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) ++ return grub_error (GRUB_ERR_BAD_FS, "resident attribute too large"); ++ ++ if (pa >= at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) ++ return grub_error (GRUB_ERR_BAD_FS, "resident attribute out of range"); ++ ++ if (u16at (pa, 0x14) + u32at (pa, 0x10) > ++ (grub_addr_t) at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR) - (grub_addr_t) pa) ++ return grub_error (GRUB_ERR_BAD_FS, "resident attribute out of range"); ++ ++ grub_memcpy (dest, pa + u16at (pa, 0x14) + ofs, len); + return 0; + } + +-- +2.42.0 + diff --git a/0002-ieee1275-claim-more-memory.patch b/0002-ieee1275-claim-more-memory.patch new file mode 100644 index 0000000..d4e69cc --- /dev/null +++ b/0002-ieee1275-claim-more-memory.patch @@ -0,0 +1,242 @@ +From 7f2590e8715b634ffea9cb7b538ac076d86fab40 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Wed, 15 Apr 2020 23:28:29 +1000 +Subject: [PATCH 02/23] ieee1275: claim more memory + +On powerpc-ieee1275, we are running out of memory trying to verify +anything. This is because: + + - we have to load an entire file into memory to verify it. This is + extremely difficult to change with appended signatures. + - We only have 32MB of heap. + - Distro kernels are now often around 30MB. + +So we want to claim more memory from OpenFirmware for our heap. + +There are some complications: + + - The grub mm code isn't the only thing that will make claims on + memory from OpenFirmware: + + * PFW/SLOF will have claimed some for their own use. + + * The ieee1275 loader will try to find other bits of memory that we + haven't claimed to place the kernel and initrd when we go to boot. + + * Once we load Linux, it will also try to claim memory. It claims + memory without any reference to /memory/available, it just starts + at min(top of RMO, 768MB) and works down. So we need to avoid this + area. See arch/powerpc/kernel/prom_init.c as of v5.11. + + - The smallest amount of memory a ppc64 KVM guest can have is 256MB. + It doesn't work with distro kernels but can work with custom kernels. + We should maintain support for that. (ppc32 can boot with even less, + and we shouldn't break that either.) + + - Even if a VM has more memory, the memory OpenFirmware makes available + as Real Memory Area can be restricted. A freshly created LPAR on a + PowerVM machine is likely to have only 256MB available to OpenFirmware + even if it has many gigabytes of memory allocated. + +EFI systems will attempt to allocate 1/4th of the available memory, +clamped to between 1M and 1600M. That seems like a good sort of +approach, we just need to figure out if 1/4 is the right fraction +for us. + +We don't know in advance how big the kernel and initrd are going to be, +which makes figuring out how much memory we can take a bit tricky. + +To figure out how much memory we should leave unused, I looked at: + + - an Ubuntu 20.04.1 ppc64le pseries KVM guest: + vmlinux: ~30MB + initrd: ~50MB + + - a RHEL8.2 ppc64le pseries KVM guest: + vmlinux: ~30MB + initrd: ~30MB + +Ubuntu VMs struggle to boot with just 256MB under SLOF. +RHEL likewise has a higher minimum supported memory figure. +So lets first consider a distro kernel and 512MB of addressible memory. +(This is the default case for anything booting under PFW.) Say we lose +131MB to PFW (based on some tests). This leaves us 381MB. 1/4 of 381MB +is ~95MB. That should be enough to verify a 30MB vmlinux and should +leave plenty of space to load Linux and the initrd. + +If we consider 256MB of RMA under PFW, we have just 125MB remaining. 1/4 +of that is a smidge under 32MB, which gives us very poor odds of verifying +a distro-sized kernel. However, if we need 80MB just to put the kernel +and initrd in memory, we can't claim any more than 45MB anyway. So 1/4 +will do. We'll come back to this later. + +grub is always built as a 32-bit binary, even if it's loading a ppc64 +kernel. So we can't address memory beyond 4GB. This gives a natural cap +of 1GB for powerpc-ieee1275. + +Also apply this 1/4 approach to i386-ieee1275, but keep the 32MB cap. + +make check still works for both i386 and powerpc and I've booted +powerpc grub with this change under SLOF and PFW. + +Signed-off-by: Daniel Axtens +--- + docs/grub-dev.texi | 6 ++- + grub-core/kern/ieee1275/init.c | 70 ++++++++++++++++++++++++++++------ + 2 files changed, 62 insertions(+), 14 deletions(-) + +diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi +index 6c629a23e..c11f1ac46 100644 +--- a/docs/grub-dev.texi ++++ b/docs/grub-dev.texi +@@ -1047,7 +1047,9 @@ space is limited to 4GiB. GRUB allocates pages from EFI for its heap, at most + 1.6 GiB. + + On i386-ieee1275 and powerpc-ieee1275 GRUB uses same stack as IEEE1275. +-It allocates at most 32MiB for its heap. ++ ++On i386-ieee1275, GRUB allocates at most 32MiB for its heap. On ++powerpc-ieee1275, GRUB allocates up to 1GiB. + + On sparc64-ieee1275 stack is 256KiB and heap is 2MiB. + +@@ -1075,7 +1077,7 @@ In short: + @item i386-qemu @tab 60 KiB @tab < 4 GiB + @item *-efi @tab ? @tab < 1.6 GiB + @item i386-ieee1275 @tab ? @tab < 32 MiB +-@item powerpc-ieee1275 @tab ? @tab < 32 MiB ++@item powerpc-ieee1275 @tab ? @tab < 1 GiB + @item sparc64-ieee1275 @tab 256KiB @tab 2 MiB + @item arm-uboot @tab 256KiB @tab 2 MiB + @item mips(el)-qemu_mips @tab 2MiB @tab 253 MiB +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index c15d40e55..d661a8da5 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -45,11 +45,12 @@ + #include + #endif + +-/* The maximum heap size we're going to claim */ ++/* The maximum heap size we're going to claim. Not used by sparc. ++ We allocate 1/4 of the available memory under 4G, up to this limit. */ + #ifdef __i386__ + #define HEAP_MAX_SIZE (unsigned long) (64 * 1024 * 1024) +-#else +-#define HEAP_MAX_SIZE (unsigned long) (32 * 1024 * 1024) ++#else // __powerpc__ ++#define HEAP_MAX_SIZE (unsigned long) (1 * 1024 * 1024 * 1024) + #endif + + extern char _start[]; +@@ -146,16 +147,45 @@ grub_claim_heap (void) + + GRUB_KERNEL_MACHINE_STACK_SIZE), 0x200000); + } + #else +-/* Helper for grub_claim_heap. */ ++/* Helper for grub_claim_heap on powerpc. */ ++static int ++heap_size (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, ++ void *data) ++{ ++ grub_uint32_t total = *(grub_uint32_t *)data; ++ ++ if (type != GRUB_MEMORY_AVAILABLE) ++ return 0; ++ ++ /* Do not consider memory beyond 4GB */ ++ if (addr > 0xffffffffUL) ++ return 0; ++ ++ if (addr + len > 0xffffffffUL) ++ len = 0xffffffffUL - addr; ++ ++ total += len; ++ *(grub_uint32_t *)data = total; ++ ++ return 0; ++} ++ + static int + heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, + void *data) + { +- unsigned long *total = data; ++ grub_uint32_t total = *(grub_uint32_t *)data; + + if (type != GRUB_MEMORY_AVAILABLE) + return 0; + ++ /* Do not consider memory beyond 4GB */ ++ if (addr > 0xffffffffUL) ++ return 0; ++ ++ if (addr + len > 0xffffffffUL) ++ len = 0xffffffffUL - addr; ++ + if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_PRE1_5M_CLAIM)) + { + if (addr + len <= 0x180000) +@@ -169,10 +199,6 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, + } + len -= 1; /* Required for some firmware. */ + +- /* Never exceed HEAP_MAX_SIZE */ +- if (*total + len > HEAP_MAX_SIZE) +- len = HEAP_MAX_SIZE - *total; +- + /* In theory, firmware should already prevent this from happening by not + listing our own image in /memory/available. The check below is intended + as a safeguard in case that doesn't happen. However, it doesn't protect +@@ -184,6 +210,18 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, + len = 0; + } + ++ /* If this block contains 0x30000000 (768MB), do not claim below that. ++ Linux likes to claim memory at min(RMO top, 768MB) and works down ++ without reference to /memory/available. */ ++ if ((addr < 0x30000000) && ((addr + len) > 0x30000000)) ++ { ++ len = len - (0x30000000 - addr); ++ addr = 0x30000000; ++ } ++ ++ if (len > total) ++ len = total; ++ + if (len) + { + grub_err_t err; +@@ -192,10 +230,12 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, + if (err) + return err; + grub_mm_init_region ((void *) (grub_addr_t) addr, len); ++ total -= len; + } + +- *total += len; +- if (*total >= HEAP_MAX_SIZE) ++ *(grub_uint32_t *)data = total; ++ ++ if (total == 0) + return 1; + + return 0; +@@ -204,7 +244,13 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, + static void + grub_claim_heap (void) + { +- unsigned long total = 0; ++ grub_uint32_t total = 0; ++ ++ grub_machine_mmap_iterate (heap_size, &total); ++ ++ total = total / 4; ++ if (total > HEAP_MAX_SIZE) ++ total = HEAP_MAX_SIZE; + + if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_FORCE_CLAIM)) + heap_init (GRUB_IEEE1275_STATIC_HEAP_START, GRUB_IEEE1275_STATIC_HEAP_LEN, +-- +2.31.1 + diff --git a/0002-ieee1275-implement-vec5-for-cas-negotiation.patch b/0002-ieee1275-implement-vec5-for-cas-negotiation.patch new file mode 100644 index 0000000..23191f9 --- /dev/null +++ b/0002-ieee1275-implement-vec5-for-cas-negotiation.patch @@ -0,0 +1,83 @@ +From 03056f35a73258fa68a809fba4aeab654ff35734 Mon Sep 17 00:00:00 2001 +From: Diego Domingos +Date: Thu, 25 Aug 2022 11:37:56 -0400 +Subject: [PATCH] ieee1275: implement vec5 for cas negotiation + +As a legacy support, if the vector 5 is not implemented, Power Hypervisor will +consider the max CPUs as 64 instead 256 currently supported during +client-architecture-support negotiation. + +This patch implements the vector 5 and set the MAX CPUs to 256 while setting the +others values to 0 (default). + +Signed-off-by: Diego Domingos +Acked-by: Daniel Axtens +Signed-off-by: Stefan Berger +Signed-off-by: Avnish Chouhan +--- + grub-core/kern/ieee1275/init.c | 28 ++++++++++++++++++++++++---- + 1 file changed, 24 insertions(+), 4 deletions(-) + +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index 7d7178d3e..0e902ff62 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -311,7 +311,21 @@ struct option_vector2 { + grub_uint8_t max_pft_size; + } __attribute__((packed)); + +-struct pvr_entry { ++struct option_vector5 ++{ ++ grub_uint8_t byte1; ++ grub_uint8_t byte2; ++ grub_uint8_t byte3; ++ grub_uint8_t cmo; ++ grub_uint8_t associativity; ++ grub_uint8_t bin_opts; ++ grub_uint8_t micro_checkpoint; ++ grub_uint8_t reserved0; ++ grub_uint32_t max_cpus; ++} GRUB_PACKED; ++ ++struct pvr_entry ++{ + grub_uint32_t mask; + grub_uint32_t entry; + }; +@@ -329,7 +343,9 @@ struct cas_vector { + grub_uint16_t vec3; + grub_uint8_t vec4_size; + grub_uint16_t vec4; +-} __attribute__((packed)); ++ grub_uint8_t vec5_size; ++ struct option_vector5 vec5; ++} GRUB_PACKED; + + /* Call ibm,client-architecture-support to try to get more RMA. + We ask for 512MB which should be enough to verify a distro kernel. +@@ -349,7 +365,7 @@ grub_ieee1275_ibm_cas (void) + } args; + struct cas_vector vector = { + .pvr_list = { { 0x00000000, 0xffffffff } }, /* any processor */ +- .num_vecs = 4 - 1, ++ .num_vecs = 5 - 1, + .vec1_size = 0, + .vec1 = 0x80, /* ignore */ + .vec2_size = 1 + sizeof(struct option_vector2) - 2, +@@ -359,7 +375,11 @@ grub_ieee1275_ibm_cas (void) + .vec3_size = 2 - 1, + .vec3 = 0x00e0, // ask for FP + VMX + DFP but don't halt if unsatisfied + .vec4_size = 2 - 1, +- .vec4 = 0x0001, // set required minimum capacity % to the lowest value ++ .vec4 = 0x0001, /* set required minimum capacity % to the lowest value */ ++ .vec5_size = 1 + sizeof (struct option_vector5) - 2, ++ .vec5 = { ++ 0, 192, 0, 128, 0, 0, 0, 0, 256 ++ } + }; + + INIT_IEEE1275_COMMON (&args.common, "call-method", 3, 2); +-- +2.39.1 + diff --git a/0002-ieee1275-ofpath-enable-NVMeoF-logical-device-transla.patch b/0002-ieee1275-ofpath-enable-NVMeoF-logical-device-transla.patch new file mode 100644 index 0000000..38d09bf --- /dev/null +++ b/0002-ieee1275-ofpath-enable-NVMeoF-logical-device-transla.patch @@ -0,0 +1,373 @@ +From 98229f1f42d0d5ffa4fb2d1bc8b830120b7214a5 Mon Sep 17 00:00:00 2001 +From: Diego Domingos +Date: Tue, 15 Mar 2022 15:59:41 -0400 +Subject: [PATCH 2/4] ieee1275/ofpath: enable NVMeoF logical device translation + +This patch add code to enable the translation of logical devices to the of NVMeoFC paths. +--- + grub-core/osdep/linux/ofpath.c | 260 +++++++++++++++++++++++++++++++-- + include/grub/util/ofpath.h | 29 ++++ + 2 files changed, 280 insertions(+), 9 deletions(-) + +diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c +index d1040c4e6..10f2c1117 100644 +--- a/grub-core/osdep/linux/ofpath.c ++++ b/grub-core/osdep/linux/ofpath.c +@@ -137,7 +137,7 @@ trim_newline (char *path) + *end-- = '\0'; + } + +-#define MAX_DISK_CAT 64 ++#define MAX_DISK_CAT 512 + + static char * + find_obppath (const char *sysfs_path_orig) +@@ -313,6 +313,69 @@ get_basename(char *p) + return ret; + } + ++ ++void ++add_filename_to_pile(char *filename, struct ofpath_files_list_root* root){ ++ struct ofpath_files_list_node* file; ++ ++ file = malloc(sizeof(struct ofpath_files_list_node)); ++ ++ file->filename = filename; ++ ++ if(root->first == NULL){ ++ root->items = 1; ++ root->first = file; ++ file->next = NULL; ++ } else { ++ root->items++; ++ file->next = root->first; ++ root->first = file; ++ } ++} ++ ++ ++void ++find_file(char* filename, char* directory, struct ofpath_files_list_root* root, int max_depth, int depth){ ++ struct dirent *ep; ++ struct stat statbuf; ++ DIR *dp; ++ ++ if(depth > max_depth){ ++ return; ++ } ++ ++ if((dp = opendir(directory)) == NULL){ ++ ++ return; ++ } ++ ++ while((ep = readdir(dp)) != NULL){ ++ ++ char* full_path = malloc(1024*sizeof(char)); ++ snprintf(full_path,1024,"%s/%s",directory,ep->d_name); ++ ++ lstat(full_path,&statbuf); ++ ++ if(S_ISLNK(statbuf.st_mode)){ ++ ++ continue; ++ } ++ ++ if(!strcmp(ep->d_name,".") || !strcmp(ep->d_name,"..")){ ++ continue; ++ } ++ ++ if(!strcmp(ep->d_name,filename)){ ++ add_filename_to_pile(full_path, root); ++ } ++ ++ find_file(filename, full_path, root, max_depth, depth+1); ++ ++ } ++ closedir(dp); ++} ++ ++ + static char * + of_path_of_vdisk(const char *sys_devname __attribute__((unused)), + const char *device, +@@ -351,7 +414,142 @@ of_path_of_ide(const char *sys_devname __attribute__((unused)), const char *devi + return ret; + } + +-#ifdef __sparc__ ++char* ++of_find_fc_host(char* host_wwpn){ ++ ++ FILE* fp; ++ char *buf; ++ char portname_filename[sizeof("port_name")] = "port_name"; ++ char devices_path[sizeof("/sys/devices")] = "/sys/devices"; ++ ++ struct ofpath_files_list_root* portnames_file_list; ++ ++ portnames_file_list=malloc(sizeof(portnames_file_list)); ++ portnames_file_list->items=0; ++ portnames_file_list->first=NULL; ++ ++ find_file(portname_filename, devices_path, portnames_file_list, 10, 0); ++ ++ struct ofpath_files_list_node* node = portnames_file_list->first; ++ while(node != NULL){ ++ fp = fopen(node->filename,"r"); ++ buf = malloc(sizeof(char)*512); ++ fscanf(fp, "%s", buf); ++ fclose(fp); ++ if((strcmp(buf,host_wwpn) == 0) && grub_strstr(node->filename, "fc_host")){ ++ return node->filename; ++ } ++ node = node->next; ++ } ++ ++ return NULL; ++} ++ ++void ++of_path_get_nvmeof_adapter_info(char* sysfs_path, ++ struct ofpath_nvmeof_info* nvmeof_info){ ++ ++ FILE *fp; ++ char *buf, *buf2, *buf3; ++ ++ nvmeof_info->host_wwpn = malloc(sizeof(char)*256); ++ nvmeof_info->target_wwpn = malloc(sizeof(char)*256); ++ nvmeof_info->nqn = malloc(sizeof(char)*256); ++ ++ buf = malloc(sizeof(char)*512); ++ snprintf(buf,512,"%s/subsysnqn",sysfs_path); ++ fp = fopen(buf,"r"); ++ fscanf(fp, "%s", nvmeof_info->nqn); ++ fclose(fp); ++ ++ snprintf(buf,512,"%s/cntlid",sysfs_path); ++ fp = fopen(buf,"r"); ++ fscanf(fp, "%u", &(nvmeof_info->cntlid)); ++ fclose(fp); ++ ++ //snprintf(buf,512,"%s/nsid",sysfs_path); ++ //fp = fopen(buf,"r"); ++ //fscanf(fp, "%u", &(nvmeof_info->nsid)); ++ //fclose(fp); ++ ++ snprintf(buf,512,"%s/address",sysfs_path); ++ fp = fopen(buf,"r"); ++ buf2 = malloc(sizeof(char)*512); ++ fscanf(fp, "%s", buf2); ++ fclose(fp); ++ ++ nvmeof_info->host_wwpn = strrchr(buf2,'-')+1; ++ ++ buf3=strchr(buf2,'-')+1; ++ buf3=strchr(buf3,'-')+1; ++ nvmeof_info->target_wwpn = buf3; ++ buf3 = strchr(nvmeof_info->target_wwpn,','); ++ *buf3 = '\0'; ++ ++ ++ free(buf); ++ ++ return; ++} ++ ++#define MAX_NVME_NSID_DIGITS 6 ++ ++static char * ++of_path_get_nvme_controller_name_node(const char* devname) ++{ ++ char *controller_node, *end; ++ ++ controller_node = strdup(devname); ++ ++ end = grub_strchr(controller_node+1, 'n'); ++ ++ if(end != NULL){ ++ *end = '\0'; ++ } ++ ++ return controller_node; ++} ++ ++unsigned int ++of_path_get_nvme_nsid(const char* devname) ++{ ++ unsigned int nsid; ++ char *sysfs_path, *buf; ++ FILE *fp; ++ ++ buf=malloc(sizeof(char)*512); ++ ++ sysfs_path = block_device_get_sysfs_path_and_link (devname); ++ ++ snprintf(buf,512,"%s/%s/nsid",sysfs_path,devname); ++ fp = fopen(buf,"r"); ++ fscanf(fp, "%u", &(nsid)); ++ fclose(fp); ++ ++ free(sysfs_path); ++ free(buf); ++ ++ return nsid; ++ ++} ++ ++static char * ++nvme_get_syspath(const char *nvmedev) ++{ ++ char *sysfs_path, *controller_node; ++ sysfs_path = block_device_get_sysfs_path_and_link (nvmedev); ++ ++ if(strstr(sysfs_path,"nvme-subsystem")){ ++ controller_node = of_path_get_nvme_controller_name_node(nvmedev); ++ strcat(sysfs_path,"/"); ++ strcat(sysfs_path,controller_node); ++ sysfs_path = xrealpath(sysfs_path); ++ } ++ ++ return sysfs_path; ++} ++ ++ + static char * + of_path_of_nvme(const char *sys_devname __attribute__((unused)), + const char *device, +@@ -360,6 +558,7 @@ of_path_of_nvme(const char *sys_devname __attribute__((unused)), + { + char *sysfs_path, *of_path, disk[MAX_DISK_CAT]; + const char *digit_string, *part_end; ++ int chars_written; + + digit_string = trailing_digits (device); + part_end = devicenode + strlen (devicenode) - 1; +@@ -379,15 +578,61 @@ of_path_of_nvme(const char *sys_devname __attribute__((unused)), + /* Remove the p. */ + *end = '\0'; + sscanf (digit_string, "%d", &part); +- snprintf (disk, sizeof (disk), "/disk@1:%c", 'a' + (part - 1)); +- sysfs_path = block_device_get_sysfs_path_and_link (nvmedev); ++ ++ sysfs_path = nvme_get_syspath(nvmedev); ++ ++ /* If is a NVMeoF */ ++ if(strstr(sysfs_path,"nvme-fabrics")){ ++ struct ofpath_nvmeof_info* nvmeof_info; ++ nvmeof_info = malloc(sizeof(nvmeof_info)); ++ ++ of_path_get_nvmeof_adapter_info(sysfs_path, nvmeof_info); ++ ++ sysfs_path = of_find_fc_host(nvmeof_info->host_wwpn); ++ ++ chars_written = snprintf(disk,sizeof(disk),"/nvme-of/controller@%s,%x:nqn=%s", ++ nvmeof_info->target_wwpn, ++ 0xffff, ++ nvmeof_info->nqn); ++ ++ unsigned int nsid = of_path_get_nvme_nsid(nvmedev); ++ ++ if(nsid){ ++ snprintf(disk+chars_written,sizeof(disk) - chars_written, ++ "/namespace@%x:%d",nsid, part); ++ } ++ ++ } else { ++ snprintf (disk, sizeof (disk), "/disk@1:%c", 'a' + (part - 1)); ++ } + free (nvmedev); + } + else + { + /* We do not have the parition. */ +- snprintf (disk, sizeof (disk), "/disk@1"); +- sysfs_path = block_device_get_sysfs_path_and_link (device); ++ sysfs_path = nvme_get_syspath (device); ++ if(strstr(sysfs_path,"nvme-fabrics")){ ++ struct ofpath_nvmeof_info* nvmeof_info; ++ nvmeof_info = malloc(sizeof(nvmeof_info)); ++ ++ of_path_get_nvmeof_adapter_info(sysfs_path, nvmeof_info); ++ ++ sysfs_path = of_find_fc_host(nvmeof_info->host_wwpn); ++ ++ chars_written = snprintf(disk,sizeof(disk),"/nvme-of/controller@%s,%x:nqn=%s", ++ nvmeof_info->target_wwpn, ++ 0xffff, ++ nvmeof_info->nqn); ++ ++ unsigned int nsid = of_path_get_nvme_nsid(device); ++ if(nsid){ ++ snprintf(disk+chars_written,sizeof(disk) - chars_written, ++ "/namespace@%x",nsid); ++ } ++ } else { ++ snprintf (disk, sizeof (disk), "/disk@1"); ++ } ++ + } + + of_path = find_obppath (sysfs_path); +@@ -398,7 +643,6 @@ of_path_of_nvme(const char *sys_devname __attribute__((unused)), + free (sysfs_path); + return of_path; + } +-#endif + + static void + of_fc_port_name(const char *path, const char *subpath, char *port_name) +@@ -840,11 +1084,9 @@ grub_util_devname_to_ofpath (const char *sys_devname) + /* All the models I've seen have a devalias "floppy". + New models have no floppy at all. */ + ofpath = xstrdup ("floppy"); +-#ifdef __sparc__ + else if (device[0] == 'n' && device[1] == 'v' && device[2] == 'm' + && device[3] == 'e') + ofpath = of_path_of_nvme (name_buf, device, devnode, devicenode); +-#endif + else + { + grub_util_warn (_("unknown device type %s"), device); +diff --git a/include/grub/util/ofpath.h b/include/grub/util/ofpath.h +index b43c523cb..a0ec30620 100644 +--- a/include/grub/util/ofpath.h ++++ b/include/grub/util/ofpath.h +@@ -3,4 +3,33 @@ + + char *grub_util_devname_to_ofpath (const char *devname); + ++struct ofpath_files_list_node { ++ char* filename; ++ struct ofpath_files_list_node* next; ++}; ++ ++struct ofpath_files_list_root { ++ int items; ++ struct ofpath_files_list_node* first; ++}; ++ ++struct ofpath_nvmeof_info { ++ char* host_wwpn; ++ char* target_wwpn; ++ char* nqn; ++ int cntlid; ++ int nsid; ++}; ++ ++void of_path_get_nvmeof_adapter_info(char* sysfs_path, ++ struct ofpath_nvmeof_info* nvmeof_info); ++ ++unsigned int of_path_get_nvme_nsid(const char* devname); ++ ++void add_filename_to_pile(char *filename, struct ofpath_files_list_root* root); ++ ++void find_file(char* filename, char* directory, struct ofpath_files_list_root* root, int max_depth, int depth); ++ ++char* of_find_fc_host(char* host_wwpn); ++ + #endif /* ! GRUB_OFPATH_MACHINE_UTIL_HEADER */ +-- +2.35.3 + diff --git a/0002-ieee1275-powerpc-enables-device-mapper-discovery.patch b/0002-ieee1275-powerpc-enables-device-mapper-discovery.patch new file mode 100644 index 0000000..0d7ab7d --- /dev/null +++ b/0002-ieee1275-powerpc-enables-device-mapper-discovery.patch @@ -0,0 +1,107 @@ +From 8b31ebfa42eb5af0633191d26fcdcea8c539e521 Mon Sep 17 00:00:00 2001 +From: Diego Domingos +Date: Wed, 24 Jun 2020 08:22:50 -0400 +Subject: [PATCH 2/2] ieee1275/powerpc: enables device mapper discovery + +this patch enables the device mapper discovery on ofpath.c. Currently, +when we are dealing with a device like /dev/dm-* the ofpath returns null +since there is no function implemented to handle this case. + +This patch implements a function that will look into /sys/block/dm-* +devices and search recursively inside slaves directory to find the root +disk. +--- + grub-core/osdep/linux/ofpath.c | 64 +++++++++++++++++++++++++++++++++- + 1 file changed, 63 insertions(+), 1 deletion(-) + +diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c +index f2bc9fc5c..d1040c4e6 100644 +--- a/grub-core/osdep/linux/ofpath.c ++++ b/grub-core/osdep/linux/ofpath.c +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + + #ifdef __sparc__ + typedef enum +@@ -754,13 +755,74 @@ strip_trailing_digits (const char *p) + return new; + } + ++static char * ++get_slave_from_dm(const char * device){ ++ char *curr_device, *tmp; ++ char *directory; ++ char *ret = NULL; ++ ++ directory = grub_strdup (device); ++ tmp = get_basename(directory); ++ curr_device = grub_strdup (tmp); ++ *tmp = '\0'; ++ ++ /* Recursively check for slaves devices so we can find the root device */ ++ while ((curr_device[0] == 'd') && (curr_device[1] == 'm') && (curr_device[2] == '-')){ ++ DIR *dp; ++ struct dirent *ep; ++ char* device_path; ++ ++ device_path = grub_xasprintf ("/sys/block/%s/slaves", curr_device); ++ dp = opendir(device_path); ++ free(device_path); ++ ++ if (dp != NULL) ++ { ++ ep = readdir (dp); ++ while (ep != NULL){ ++ ++ /* avoid some system directories */ ++ if (!strcmp(ep->d_name,".")) ++ goto next_dir; ++ if (!strcmp(ep->d_name,"..")) ++ goto next_dir; ++ ++ free (curr_device); ++ free (ret); ++ curr_device = grub_strdup (ep->d_name); ++ ret = grub_xasprintf ("%s%s", directory, curr_device); ++ break; ++ ++ next_dir: ++ ep = readdir (dp); ++ continue; ++ } ++ closedir (dp); ++ } ++ else ++ grub_util_warn (_("cannot open directory `%s'"), device_path); ++ } ++ ++ free (directory); ++ free (curr_device); ++ ++ return ret; ++} ++ + char * + grub_util_devname_to_ofpath (const char *sys_devname) + { +- char *name_buf, *device, *devnode, *devicenode, *ofpath; ++ char *name_buf, *device, *devnode, *devicenode, *ofpath, *realname; + + name_buf = xrealpath (sys_devname); + ++ realname = get_slave_from_dm (name_buf); ++ if (realname) ++ { ++ free (name_buf); ++ name_buf = realname; ++ } ++ + device = get_basename (name_buf); + devnode = strip_trailing_digits (name_buf); + devicenode = strip_trailing_digits (device); +-- +2.26.2 + diff --git a/0002-kern-ieee1275-init-Extended-support-in-Vec5.patch b/0002-kern-ieee1275-init-Extended-support-in-Vec5.patch new file mode 100644 index 0000000..8bfccbc --- /dev/null +++ b/0002-kern-ieee1275-init-Extended-support-in-Vec5.patch @@ -0,0 +1,129 @@ +From 6c9a76053006f7532d9fb3e0e80eb11ebd80df98 Mon Sep 17 00:00:00 2001 +From: Avnish Chouhan +Date: Mon, 27 Mar 2023 12:25:40 +0530 +Subject: [PATCH 2/2] kern/ieee1275/init: Extended support in Vec5 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch enables multiple options in Vec5 which are required and +solves the boot issues seen on some machines which are looking for +these specific options. + +1. LPAR: Client program supports logical partitioning and + associated hcall()s. +2. SPLPAR: Client program supports the Shared + Processor LPAR Option. +3. DYN_RCON_MEM: Client program supports the + “ibm,dynamic-reconfiguration-memory” property and it may be + presented in the device tree. +4. LARGE_PAGES: Client supports pages larger than 4 KB. +5. DONATE_DCPU_CLS: Client supports donating dedicated processor cycles. +6. PCI_EXP: Client supports PCI Express implementations + utilizing Message Signaled Interrupts (MSIs). + +7. CMOC: Enables the Cooperative Memory Over-commitment Option. +8. EXT_CMO: Enables the Extended Cooperative Memory Over-commit Option. + +9. ASSOC_REF: Enables “ibm,associativity” and + “ibm,associativity-reference-points” properties. +10. AFFINITY: Enables Platform Resource Reassignment Notification. +11. NUMA: Supports NUMA Distance Lookup Table Option. + +12. HOTPLUG_INTRPT: Supports Hotplug Interrupts. +13. HPT_RESIZE: Enable Hash Page Table Resize Option. + +14. MAX_CPU: Defines maximum number of CPUs supported. + +15. PFO_HWRNG: Supports Random Number Generator. +16. PFO_HW_COMP: Supports Compression Engine. +17. PFO_ENCRYPT: Supports Encryption Engine. + +18. SUB_PROCESSORS: Supports Sub-Processors. + +19. DY_MEM_V2: Client program supports the “ibm,dynamic-memory-v2” property in the + “ibm,dynamic-reconfiguration-memory” node and it may be presented in the device tree. +20. DRC_INFO: Client program supports the “ibm,drc-info” property definition and it may be + presented in the device tree. + +Signed-off-by: Avnish Chouhan +Reviewed-by: Daniel Kiper +--- + grub-core/kern/ieee1275/init.c | 47 +++++++++++++++++++++++++++++----- + 1 file changed, 41 insertions(+), 6 deletions(-) + +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index eaa25d0db..00f892ebe 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -61,11 +61,41 @@ extern char _end[]; + grub_addr_t grub_ieee1275_original_stack; + #endif + +-#define LPAR 0x80 +-#define SPLPAR 0x40 +-#define BYTE2 (LPAR | SPLPAR) +-#define CMO 0x80 +-#define MAX_CPU 256 ++/* Options vector5 properties. */ ++ ++#define LPAR 0x80 ++#define SPLPAR 0x40 ++#define DYN_RCON_MEM 0x20 ++#define LARGE_PAGES 0x10 ++#define DONATE_DCPU_CLS 0x02 ++#define PCI_EXP 0x01 ++#define BYTE2 (LPAR | SPLPAR | DYN_RCON_MEM | LARGE_PAGES | DONATE_DCPU_CLS | PCI_EXP) ++ ++#define CMOC 0x80 ++#define EXT_CMO 0x40 ++#define CMO (CMOC | EXT_CMO) ++ ++#define ASSOC_REF 0x80 ++#define AFFINITY 0x40 ++#define NUMA 0x20 ++#define ASSOCIATIVITY (ASSOC_REF | AFFINITY | NUMA) ++ ++#define HOTPLUG_INTRPT 0x04 ++#define HPT_RESIZE 0x01 ++#define BIN_OPTS (HOTPLUG_INTRPT | HPT_RESIZE) ++ ++#define MAX_CPU 256 ++ ++#define PFO_HWRNG 0x80000000 ++#define PFO_HW_COMP 0x40000000 ++#define PFO_ENCRYPT 0x20000000 ++#define PLATFORM_FACILITIES (PFO_HWRNG | PFO_HW_COMP | PFO_ENCRYPT) ++ ++#define SUB_PROCESSORS 1 ++ ++#define DY_MEM_V2 0x80 ++#define DRC_INFO 0x40 ++#define BYTE22 (DY_MEM_V2 | DRC_INFO) + + void + grub_exit (void) +@@ -328,6 +358,11 @@ struct option_vector5 + grub_uint8_t micro_checkpoint; + grub_uint8_t reserved0; + grub_uint32_t max_cpus; ++ grub_uint16_t base_papr; ++ grub_uint16_t mem_reference; ++ grub_uint32_t platform_facilities; ++ grub_uint8_t sub_processors; ++ grub_uint8_t byte22; + } GRUB_PACKED; + + struct pvr_entry +@@ -384,7 +419,7 @@ grub_ieee1275_ibm_cas (void) + .vec4 = 0x0001, /* set required minimum capacity % to the lowest value */ + .vec5_size = 1 + sizeof (struct option_vector5) - 2, + .vec5 = { +- 0, BYTE2, 0, CMO, 0, 0, 0, 0, MAX_CPU ++ 0, BYTE2, 0, CMO, ASSOCIATIVITY, BIN_OPTS, 0, 0, MAX_CPU, 0, 0, PLATFORM_FACILITIES, SUB_PROCESSORS, BYTE22 + } + }; + +-- +2.39.2 + diff --git a/0002-loader-efi-chainloader-Simplify-the-loader-state.patch b/0002-loader-efi-chainloader-Simplify-the-loader-state.patch new file mode 100644 index 0000000..c460e61 --- /dev/null +++ b/0002-loader-efi-chainloader-Simplify-the-loader-state.patch @@ -0,0 +1,125 @@ +From c111176648717645284865e15d7c6713cf29e982 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Tue, 5 Apr 2022 10:02:04 +0100 +Subject: [PATCH 02/32] loader/efi/chainloader: Simplify the loader state + +The chainloader command retains the source buffer and device path passed +to LoadImage(), requiring the unload hook passed to grub_loader_set() to +free them. It isn't required to retain this state though - they aren't +required by StartImage() or anything else in the boot hook, so clean them +up before grub_cmd_chainloader() finishes. + +Signed-off-by: Chris Coulson +Reviewed-by: Daniel Kiper +--- + grub-core/loader/efi/chainloader.c | 37 ++++++++++++++++-------------- + 1 file changed, 20 insertions(+), 17 deletions(-) + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index 625f1d26da..1ec09a166c 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -53,12 +53,8 @@ GRUB_MOD_LICENSE ("GPLv3+"); + + static grub_dl_t my_mod; + +-static grub_efi_physical_address_t address; +-static grub_efi_uintn_t pages; + static grub_ssize_t fsize; +-static grub_efi_device_path_t *file_path; + static grub_efi_handle_t image_handle; +-static grub_efi_char16_t *cmdline; + static grub_ssize_t cmdline_len; + static grub_efi_handle_t dev_handle; + +@@ -70,16 +66,16 @@ static grub_efi_status_t (*entry_point) (grub_efi_handle_t image_handle, grub_e + static grub_err_t + grub_chainloader_unload (void) + { ++ grub_efi_loaded_image_t *loaded_image; + grub_efi_boot_services_t *b; + ++ loaded_image = grub_efi_get_loaded_image (image_handle); ++ if (loaded_image != NULL) ++ grub_free (loaded_image->load_options); ++ + b = grub_efi_system_table->boot_services; + efi_call_1 (b->unload_image, image_handle); +- efi_call_2 (b->free_pages, address, pages); + +- grub_free (file_path); +- grub_free (cmdline); +- cmdline = 0; +- file_path = 0; + dev_handle = 0; + + grub_dl_unref (my_mod); +@@ -158,7 +154,7 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename) + char *dir_start; + char *dir_end; + grub_size_t size; +- grub_efi_device_path_t *d; ++ grub_efi_device_path_t *d, *file_path; + + dir_start = grub_strchr (filename, ')'); + if (! dir_start) +@@ -641,10 +637,13 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_efi_status_t status; + grub_efi_boot_services_t *b; + grub_device_t dev = 0; +- grub_efi_device_path_t *dp = 0; ++ grub_efi_device_path_t *dp = NULL, *file_path = NULL; + grub_efi_loaded_image_t *loaded_image; + char *filename; + void *boot_image = 0; ++ grub_efi_physical_address_t address = 0; ++ grub_efi_uintn_t pages = 0; ++ grub_efi_char16_t *cmdline = NULL; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); +@@ -652,10 +651,6 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + + grub_dl_ref (my_mod); + +- /* Initialize some global variables. */ +- address = 0; +- image_handle = 0; +- file_path = 0; + dev_handle = 0; + + b = grub_efi_system_table->boot_services; +@@ -857,6 +852,10 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_file_close (file); + grub_device_close (dev); + ++ /* We're finished with the source image buffer and file path now. */ ++ efi_call_2 (b->free_pages, address, pages); ++ grub_free (file_path); ++ + grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0); + return 0; + +@@ -868,13 +867,17 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + if (file) + grub_file_close (file); + ++ grub_free (cmdline); + grub_free (file_path); + + if (address) + efi_call_2 (b->free_pages, address, pages); + +- if (cmdline) +- grub_free (cmdline); ++ if (image_handle != NULL) ++ { ++ efi_call_1 (b->unload_image, image_handle); ++ image_handle = NULL; ++ } + + grub_dl_unref (my_mod); + +-- +2.34.1 + diff --git a/0002-net-read-bracketed-ipv6-addrs-and-port-numbers.patch b/0002-net-read-bracketed-ipv6-addrs-and-port-numbers.patch new file mode 100644 index 0000000..0028a98 --- /dev/null +++ b/0002-net-read-bracketed-ipv6-addrs-and-port-numbers.patch @@ -0,0 +1,246 @@ +From 4a00be0176a459fa6e199f2709eabbe8dc0d7979 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Fri, 29 Jul 2016 17:41:38 +0800 +Subject: [PATCH 2/8] net: read bracketed ipv6 addrs and port numbers + +From: Aaron Miller + +Allow specifying port numbers for http and tftp paths, and allow ipv6 addresses +to be recognized with brackets around them, which is required to specify a port +number +--- + grub-core/net/http.c | 21 ++++++++++--- + grub-core/net/net.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++--- + grub-core/net/tftp.c | 6 +++- + include/grub/net.h | 1 + + 4 files changed, 104 insertions(+), 10 deletions(-) + +Index: grub-2.06~rc1/grub-core/net/http.c +=================================================================== +--- grub-2.06~rc1.orig/grub-core/net/http.c ++++ grub-2.06~rc1/grub-core/net/http.c +@@ -312,12 +312,14 @@ http_establish (struct grub_file *file, + int i; + struct grub_net_buff *nb; + grub_err_t err; ++ char* server = file->device->net->server; ++ int port = file->device->net->port; + + nb = grub_netbuff_alloc (GRUB_NET_TCP_RESERVE_SIZE + + sizeof ("GET ") - 1 + + grub_strlen (data->filename) + + sizeof (" HTTP/1.1\r\nHost: ") - 1 +- + grub_strlen (file->device->net->server) ++ + grub_strlen (server) + sizeof (":XXXXXXXXXX") + + sizeof ("\r\nUser-Agent: " PACKAGE_STRING + "\r\n") - 1 + + sizeof ("Range: bytes=XXXXXXXXXXXXXXXXXXXX" +@@ -356,7 +358,7 @@ http_establish (struct grub_file *file, + sizeof (" HTTP/1.1\r\nHost: ") - 1); + + ptr = nb->tail; +- err = grub_netbuff_put (nb, grub_strlen (file->device->net->server)); ++ err = grub_netbuff_put (nb, grub_strlen (server)); + if (err) + { + grub_netbuff_free (nb); +@@ -365,6 +367,15 @@ http_establish (struct grub_file *file, + grub_memcpy (ptr, file->device->net->server, + grub_strlen (file->device->net->server)); + ++ if (port) ++ { ++ ptr = nb->tail; ++ grub_snprintf ((char *) ptr, ++ sizeof (":XXXXXXXXXX"), ++ ":%d", ++ port); ++ } ++ + ptr = nb->tail; + err = grub_netbuff_put (nb, + sizeof ("\r\nUser-Agent: " PACKAGE_STRING "\r\n") +@@ -390,8 +401,10 @@ http_establish (struct grub_file *file, + grub_netbuff_put (nb, 2); + grub_memcpy (ptr, "\r\n", 2); + +- data->sock = grub_net_tcp_open (file->device->net->server, +- HTTP_PORT, http_receive, ++ grub_dprintf ("http", "opening path %s on host %s TCP port %d\n", ++ data->filename, server, port ? port : HTTP_PORT); ++ data->sock = grub_net_tcp_open (server, ++ port ? port : HTTP_PORT, http_receive, + http_err, NULL, + file); + if (!data->sock) +Index: grub-2.06~rc1/grub-core/net/net.c +=================================================================== +--- grub-2.06~rc1.orig/grub-core/net/net.c ++++ grub-2.06~rc1/grub-core/net/net.c +@@ -442,6 +442,12 @@ parse_ip6 (const char *val, grub_uint64_ + grub_uint16_t newip[8]; + const char *ptr = val; + int word, quaddot = -1; ++ int bracketed = 0; ++ ++ if (ptr[0] == '[') { ++ bracketed = 1; ++ ptr++; ++ } + + if (ptr[0] == ':' && ptr[1] != ':') + return 0; +@@ -480,6 +486,9 @@ parse_ip6 (const char *val, grub_uint64_ + grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0])); + } + grub_memcpy (ip, newip, 16); ++ if (bracketed && *ptr == ']') { ++ ptr++; ++ } + if (rest) + *rest = ptr; + return 1; +@@ -1265,8 +1274,10 @@ grub_net_open_real (const char *name) + { + grub_net_app_level_t proto; + const char *protname, *server; ++ char *host; + grub_size_t protnamelen; + int try; ++ int port = 0; + + if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0) + { +@@ -1304,6 +1315,72 @@ grub_net_open_real (const char *name) + return NULL; + } + ++ char* port_start; ++ /* ipv6 or port specified? */ ++ if ((port_start = grub_strchr (server, ':'))) ++ { ++ char* ipv6_begin; ++ if((ipv6_begin = grub_strchr (server, '['))) ++ { ++ char* ipv6_end = grub_strchr (server, ']'); ++ if(!ipv6_end) ++ { ++ grub_error (GRUB_ERR_NET_BAD_ADDRESS, ++ N_("mismatched [ in address")); ++ return NULL; ++ } ++ /* port number after bracketed ipv6 addr */ ++ if(ipv6_end[1] == ':') ++ { ++ port = grub_strtoul (ipv6_end + 2, NULL, 10); ++ if(port > 65535) ++ { ++ grub_error (GRUB_ERR_NET_BAD_ADDRESS, ++ N_("bad port number")); ++ return NULL; ++ } ++ } ++ host = grub_strndup (ipv6_begin, (ipv6_end - ipv6_begin) + 1); ++ } ++ else ++ { ++ if (grub_strchr (port_start + 1, ':')) ++ { ++ int iplen = grub_strlen (server); ++ /* bracket bare ipv6 addrs */ ++ host = grub_malloc (iplen + 3); ++ if(!host) ++ { ++ return NULL; ++ } ++ host[0] = '['; ++ grub_memcpy (host + 1, server, iplen); ++ host[iplen + 1] = ']'; ++ host[iplen + 2] = '\0'; ++ } ++ else ++ { ++ /* hostname:port or ipv4:port */ ++ port = grub_strtol (port_start + 1, NULL, 10); ++ if(port > 65535) ++ { ++ grub_error (GRUB_ERR_NET_BAD_ADDRESS, ++ N_("bad port number")); ++ return NULL; ++ } ++ host = grub_strndup (server, port_start - server); ++ } ++ } ++ } ++ else ++ { ++ host = grub_strdup (server); ++ } ++ if (!host) ++ { ++ return NULL; ++ } ++ + for (try = 0; try < 2; try++) + { + FOR_NET_APP_LEVEL (proto) +@@ -1313,14 +1390,13 @@ grub_net_open_real (const char *name) + { + grub_net_t ret = grub_zalloc (sizeof (*ret)); + if (!ret) +- return NULL; +- ret->protocol = proto; +- ret->server = grub_strdup (server); +- if (!ret->server) + { +- grub_free (ret); ++ grub_free (host); + return NULL; + } ++ ret->protocol = proto; ++ ret->port = port; ++ ret->server = host; + ret->fs = &grub_net_fs; + return ret; + } +Index: grub-2.06~rc1/grub-core/net/tftp.c +=================================================================== +--- grub-2.06~rc1.orig/grub-core/net/tftp.c ++++ grub-2.06~rc1/grub-core/net/tftp.c +@@ -295,6 +295,7 @@ tftp_open (struct grub_file *file, const + grub_err_t err; + grub_uint8_t *nbd; + grub_net_network_level_address_t addr; ++ int port = file->device->net->port; + + data = grub_zalloc (sizeof (*data)); + if (!data) +@@ -361,12 +362,15 @@ tftp_open (struct grub_file *file, const + err = grub_net_resolve_address (file->device->net->server, &addr); + if (err) + { ++ grub_dprintf ("tftp", "file_size is %llu, block_size is %llu\n", ++ (unsigned long long)data->file_size, ++ (unsigned long long)data->block_size); + grub_free (data); + return err; + } + + data->sock = grub_net_udp_open (addr, +- TFTP_SERVER_PORT, tftp_receive, ++ port ? port : TFTP_SERVER_PORT, tftp_receive, + file); + if (!data->sock) + { +Index: grub-2.06~rc1/include/grub/net.h +=================================================================== +--- grub-2.06~rc1.orig/include/grub/net.h ++++ grub-2.06~rc1/include/grub/net.h +@@ -270,6 +270,7 @@ typedef struct grub_net + { + char *server; + char *name; ++ int port; + grub_net_app_level_t protocol; + grub_net_packets_t packs; + grub_off_t offset; diff --git a/0002-osdep-linux-hostdisk-Use-stat-instead-of-udevadm-for.patch b/0002-osdep-linux-hostdisk-Use-stat-instead-of-udevadm-for.patch new file mode 100644 index 0000000..69789d4 --- /dev/null +++ b/0002-osdep-linux-hostdisk-Use-stat-instead-of-udevadm-for.patch @@ -0,0 +1,98 @@ +From 1ea4e5ef09c06552402bf676ce262a661372f08d Mon Sep 17 00:00:00 2001 +From: Jeff Mahoney +Date: Thu, 15 Jul 2021 17:35:28 +0200 +Subject: [PATCH 2/2] osdep/linux/hostdisk: Use stat() instead of udevadm for + partition lookup + +The sysfs_partition_path() calls udevadm to resolve the sysfs path for +a block device. That can be accomplished by stating the device node +and using the major/minor to follow the symlinks in /sys/dev/block/. + +This cuts the execution time of grub-mkconfig to somewhere near 55% on +system without LVM (which uses libdevmapper instead sysfs_partition_path()). + +Remove udevadm call as it does not help us more than calling stat() directly. + +Signed-off-by: Jeff Mahoney +Signed-off-by: Petr Vorel +Reviewed-by: Daniel Kiper +[ upstream status: 1ea4e5ef0 ("osdep/linux/hostdisk: Use stat() instead of udevadm for partition lookup") +--- + grub-core/osdep/linux/hostdisk.c | 52 ++++---------------------------- + 1 file changed, 6 insertions(+), 46 deletions(-) + +diff --git a/grub-core/osdep/linux/hostdisk.c b/grub-core/osdep/linux/hostdisk.c +index da62f924e..d3326d095 100644 +--- a/grub-core/osdep/linux/hostdisk.c ++++ b/grub-core/osdep/linux/hostdisk.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -98,54 +99,13 @@ grub_util_get_fd_size_os (grub_util_fd_t fd, const char *name, unsigned *log_sec + static char * + sysfs_partition_path (const char *dev, const char *entry) + { +- const char *argv[7]; +- int fd; +- pid_t pid; +- FILE *udevadm; +- char *buf = NULL; +- size_t len = 0; +- char *path = NULL; +- +- argv[0] = "udevadm"; +- argv[1] = "info"; +- argv[2] = "--query"; +- argv[3] = "path"; +- argv[4] = "--name"; +- argv[5] = dev; +- argv[6] = NULL; +- +- pid = grub_util_exec_pipe (argv, &fd); +- +- if (!pid) +- return NULL; +- +- /* Parent. Read udevadm's output. */ +- udevadm = fdopen (fd, "r"); +- if (!udevadm) +- { +- grub_util_warn (_("Unable to open stream from %s: %s"), +- "udevadm", strerror (errno)); +- close (fd); +- goto out; +- } +- +- if (getline (&buf, &len, udevadm) > 0) +- { +- char *newline; +- +- newline = strchr (buf, '\n'); +- if (newline) +- *newline = '\0'; +- path = xasprintf ("/sys%s/%s", buf, entry); +- } ++ struct stat st; + +-out: +- if (udevadm) +- fclose (udevadm); +- waitpid (pid, NULL, 0); +- free (buf); ++ if (stat (dev, &st) == 0 && S_ISBLK (st.st_mode)) ++ return xasprintf ("/sys/dev/block/%u:%u/%s", ++ major (st.st_rdev), minor (st.st_rdev), entry); + +- return path; ++ return NULL; + } + + static int +-- +2.32.0 + diff --git a/0002-prep_loadenv-Fix-regex-for-Open-Firmware-device-spec.patch b/0002-prep_loadenv-Fix-regex-for-Open-Firmware-device-spec.patch new file mode 100644 index 0000000..e2f0512 --- /dev/null +++ b/0002-prep_loadenv-Fix-regex-for-Open-Firmware-device-spec.patch @@ -0,0 +1,205 @@ +From 990902e28c390217d25ea474e5ef163d79eadc7f Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Fri, 31 Mar 2023 15:19:58 +0800 +Subject: [PATCH 2/2] prep_loadenv: Fix regex for Open Firmware device + specifier with encoded commas + +The Open Firmware device specifier allows for comma-separated properties +of a component, but this conflicts with the way that grub separates +device and partition in its device specifier. To address this, grub +encodes commas in Open Firmware device strings with a leading backslash +as an established convention. + +However, the regular expression used to extract the boot device +substring from the $cmdpath environment variable did not properly retain +commas with leading backslashes as part of the device. This could cause +the comma to be incorrectly interpreted as a partition delimiter and +result in a broken name for the boot disk. + +To fix this issue, we have updated the regular expression to properly +handle the encoded comma in the Open Firmware device specifier, ensuring +that the correct boot device is identified and used. + +v2: +Fix the issue of freeing an uninitialized pointer in early_prep_loadenv. + +Signed-off-by: Michael Chang +--- + grub-core/commands/prep_loadenv.c | 108 ++++++++++++++++++++++-------- + 1 file changed, 79 insertions(+), 29 deletions(-) + +--- a/grub-core/commands/prep_loadenv.c ++++ b/grub-core/commands/prep_loadenv.c +@@ -15,7 +15,7 @@ + GRUB_MOD_LICENSE ("GPLv3+"); + + static char * +-match_substr (regmatch_t *match, const char *str) ++match_substr (const regmatch_t *match, const char *str) + { + if (match->rm_so != -1) + { +@@ -185,24 +185,18 @@ + return err; + } + +-static grub_err_t +-boot_disk_prep_partname (char **name) ++static regmatch_t * ++regex_match_str (const char *pattern, const char *str, grub_size_t *nmatch) + { + regex_t regex; + int ret; + grub_size_t s; + char *comperr; +- const char *cmdpath; + regmatch_t *matches = NULL; + grub_err_t err = GRUB_ERR_NONE; + +- *name = NULL; +- +- cmdpath = grub_env_get ("cmdpath"); +- if (!cmdpath) +- return GRUB_ERR_NONE; +- +- ret = regcomp (®ex, "\\(([^,]+)(,?.*)?\\)(.*)", REG_EXTENDED); ++ *nmatch = 0; ++ ret = regcomp (®ex, pattern, REG_EXTENDED); + if (ret) + goto fail; + +@@ -210,22 +204,11 @@ + if (! matches) + goto fail; + +- ret = regexec (®ex, cmdpath, regex.re_nsub + 1, matches, 0); +- if (!ret) ++ ret = regexec (®ex, str, regex.re_nsub + 1, matches, 0); ++ if (ret == 0) + { +- char *devname = devname = match_substr (matches + 1, cmdpath); +- if (!devname) +- { +- err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "%s contains no disk name", cmdpath); +- goto out; +- } +- +- err = prep_partname (devname, name); +- out: +- grub_free (devname); +- regfree (®ex); +- grub_free (matches); +- return err; ++ *nmatch = regex.re_nsub + 1; ++ return matches; + } + + fail: +@@ -235,13 +218,60 @@ + if (!comperr) + { + regfree (®ex); +- return grub_errno; ++ return NULL; + } + regerror (ret, ®ex, comperr, s); + err = grub_error (GRUB_ERR_TEST_FAILURE, "%s", comperr); + regfree (®ex); + grub_free (comperr); +- return err; ++ return NULL; ++} ++ ++static grub_err_t ++boot_disk_prep_partname (const char *varname, char **name) ++{ ++ const char *cmdpath; ++ regmatch_t *matches; ++ grub_size_t nmatch; ++ char *devname = NULL; ++ ++ *name = NULL; ++ ++ if (varname) ++ cmdpath = grub_env_get (varname); ++ else ++ cmdpath = grub_env_get ("cmdpath"); ++ if (!cmdpath) ++ return GRUB_ERR_NONE; ++ ++ matches = regex_match_str("\\((.*)\\)(.*)", cmdpath, &nmatch); ++ if (matches && nmatch >= 2) ++ devname = match_substr (matches + 1, cmdpath); ++ if (devname == NULL) ++ goto quit; ++ grub_free (matches); ++ ++ matches = regex_match_str ("(.*[^\\])(,.*)", devname, &nmatch); ++ if (matches && nmatch >= 2) ++ { ++ char *n = match_substr (matches + 1, devname); ++ grub_free (devname); ++ devname = n; ++ } ++ else ++ grub_errno = GRUB_ERR_NONE; ++ if (devname) ++ { ++ grub_printf ("search prep from disk `%s'\n", devname); ++ prep_partname (devname, name); ++ } ++ ++ quit: ++ grub_free (devname); ++ grub_free (matches); ++ if (grub_errno) ++ grub_print_error (); ++ return GRUB_ERR_NONE; + } + + static grub_err_t +@@ -274,13 +304,31 @@ + return GRUB_ERR_NONE; + } + ++static grub_err_t ++grub_cmd_prep_partname (grub_command_t cmd __attribute__ ((unused)), ++ int argc, ++ char **argv) ++{ ++ char *prep = NULL; ++ const char *varname = NULL; ++ ++ if (argc > 0) ++ varname = argv[0]; ++ ++ boot_disk_prep_partname(varname, &prep); ++ if (prep) ++ grub_printf ("prep: %s\n", prep); ++ ++ return GRUB_ERR_NONE; ++} ++ + static void + early_prep_loadenv (void) + { + grub_err_t err; +- char *prep; ++ char *prep = NULL; + +- err = boot_disk_prep_partname (&prep); ++ err = boot_disk_prep_partname (NULL, &prep); + if (err == GRUB_ERR_NONE && prep) + err = prep_read_envblk (prep); + if (err == GRUB_ERR_BAD_FILE_TYPE || err == GRUB_ERR_FILE_NOT_FOUND) +@@ -296,6 +344,10 @@ + { + early_env_hook = early_prep_loadenv; + cmd_prep_load = ++ grub_register_command("prep_partname", grub_cmd_prep_partname, ++ "VARNAME", ++ N_("Get partition name of PReP.")); ++ cmd_prep_load = + grub_register_command("prep_load_env", grub_cmd_prep_loadenv, + "DEVICE", + N_("Load variables from environment block file.")); diff --git a/0002-tpm-Disable-tpm-verifier-if-tpm-is-not-present.patch b/0002-tpm-Disable-tpm-verifier-if-tpm-is-not-present.patch new file mode 100644 index 0000000..d6cc8e6 --- /dev/null +++ b/0002-tpm-Disable-tpm-verifier-if-tpm-is-not-present.patch @@ -0,0 +1,130 @@ +From e5bba1012e34597215684aa948bbc30093faa750 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Fri, 7 Oct 2022 13:37:10 +0800 +Subject: [PATCH 2/2] tpm: Disable tpm verifier if tpm is not present + +This helps to prevent out of memory error when reading large files via +disabling tpm device as verifier has to read all content into memory in +one chunk to measure the hash and extend to tpm. + +For ibmvtpm driver support this change here would be needed. It helps to +prevent much memory consuming tpm subsystem from being activated when no +vtpm device present. + +Signed-off-by: Michael Chang +Signed-off-by: Stefan Berger +--- + grub-core/commands/efi/tpm.c | 37 +++++++++++++++++++++++++++ + grub-core/commands/ieee1275/ibmvtpm.c | 16 +++++++----- + grub-core/commands/tpm.c | 4 +++ + include/grub/tpm.h | 1 + + 4 files changed, 52 insertions(+), 6 deletions(-) + +diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c +index c3f6e00d2..f68c1db1b 100644 +--- a/grub-core/commands/efi/tpm.c ++++ b/grub-core/commands/efi/tpm.c +@@ -288,3 +288,40 @@ grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, + else + return grub_tpm2_log_event (tpm_handle, buf, size, pcr, description); + } ++ ++int ++grub_tpm_present (void) ++{ ++ grub_efi_handle_t tpm_handle; ++ grub_efi_uint8_t protocol_version; ++ ++ if (!grub_tpm_handle_find (&tpm_handle, &protocol_version)) ++ return 0; ++ ++ if (protocol_version == 1) ++ { ++ grub_efi_tpm_protocol_t *tpm; ++ ++ tpm = grub_efi_open_protocol (tpm_handle, &tpm_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ if (!tpm) ++ { ++ grub_dprintf ("tpm", "Cannot open TPM protocol\n"); ++ return 0; ++ } ++ return grub_tpm1_present (tpm); ++ } ++ else ++ { ++ grub_efi_tpm2_protocol_t *tpm; ++ ++ tpm = grub_efi_open_protocol (tpm_handle, &tpm2_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ if (!tpm) ++ { ++ grub_dprintf ("tpm", "Cannot open TPM protocol\n"); ++ return 0; ++ } ++ return grub_tpm2_present (tpm); ++ } ++} +diff --git a/grub-core/commands/ieee1275/ibmvtpm.c b/grub-core/commands/ieee1275/ibmvtpm.c +index e68b8448b..dec4ffec6 100644 +--- a/grub-core/commands/ieee1275/ibmvtpm.c ++++ b/grub-core/commands/ieee1275/ibmvtpm.c +@@ -136,12 +136,6 @@ grub_err_t + grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, + const char *description) + { +- grub_err_t err = tpm_init(); +- +- /* Absence of a TPM isn't a failure. */ +- if (err != GRUB_ERR_NONE) +- return GRUB_ERR_NONE; +- + grub_dprintf ("tpm", "log_event, pcr = %d, size = 0x%" PRIxGRUB_SIZE ", %s\n", + pcr, size, description); + +@@ -150,3 +144,13 @@ grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, + + return GRUB_ERR_NONE; + } ++ ++int ++grub_tpm_present (void) ++{ ++ /* ++ * Call tpm_init() 'late' rather than from GRUB_MOD_INIT() so that device nodes ++ * can be found. ++ */ ++ return tpm_init() == GRUB_ERR_NONE; ++} +diff --git a/grub-core/commands/tpm.c b/grub-core/commands/tpm.c +index 2052c36ea..cb8ed6b94 100644 +--- a/grub-core/commands/tpm.c ++++ b/grub-core/commands/tpm.c +@@ -86,10 +86,14 @@ struct grub_file_verifier grub_tpm_verifier = { + + GRUB_MOD_INIT (tpm) + { ++ if (!grub_tpm_present()) ++ return; + grub_verifier_register (&grub_tpm_verifier); + } + + GRUB_MOD_FINI (tpm) + { ++ if (!grub_tpm_present()) ++ return; + grub_verifier_unregister (&grub_tpm_verifier); + } +diff --git a/include/grub/tpm.h b/include/grub/tpm.h +index 5c285cbc5..c19fcbd0a 100644 +--- a/include/grub/tpm.h ++++ b/include/grub/tpm.h +@@ -36,4 +36,5 @@ + + grub_err_t grub_tpm_measure (unsigned char *buf, grub_size_t size, + grub_uint8_t pcr, const char *description); ++int grub_tpm_present (void); + #endif +-- +2.39.1 + diff --git a/0003-Handle-multi-arch-64-on-32-boot-in-linuxefi-loader.patch b/0003-Handle-multi-arch-64-on-32-boot-in-linuxefi-loader.patch new file mode 100644 index 0000000..88e4f3c --- /dev/null +++ b/0003-Handle-multi-arch-64-on-32-boot-in-linuxefi-loader.patch @@ -0,0 +1,290 @@ +From 25069a23257ba9c6db644bbe6114dafb879063e5 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 8 Jul 2019 12:32:37 +0200 +Subject: [PATCH 03/11] Handle multi-arch (64-on-32) boot in linuxefi loader. + +Allow booting 64-bit kernels on 32-bit EFI on x86. + +Signed-off-by: Peter Jones +--- + grub-core/loader/efi/linux.c | 11 ++- + grub-core/loader/i386/efi/linux.c | 127 +++++++++++++++++++----------- + include/grub/i386/linux.h | 7 +- + 3 files changed, 97 insertions(+), 48 deletions(-) + +diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c +index 442627dc2..9265cf420 100644 +--- a/grub-core/loader/efi/linux.c ++++ b/grub-core/loader/efi/linux.c +@@ -30,11 +30,16 @@ + typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *); + + grub_err_t +-grub_efi_linux_boot (void *kernel_addr, grub_off_t offset, ++grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset, + void *kernel_params) + { + grub_efi_loaded_image_t *loaded_image = NULL; + handover_func hf; ++ int offset = 0; ++ ++#ifdef __x86_64__ ++ offset = 512; ++#endif + + /* + * Since the EFI loader is not calling the LoadImage() and StartImage() +@@ -48,8 +53,8 @@ grub_efi_linux_boot (void *kernel_addr, grub_off_t offset, + grub_dprintf ("linux", "Loaded Image base address could not be set\n"); + + grub_dprintf ("linux", "kernel_addr: %p handover_offset: %p params: %p\n", +- kernel_addr, (void *)(grub_efi_uintn_t)offset, kernel_params); +- hf = (handover_func)((char *)kernel_addr + offset); ++ kernel_addr, (void *)(grub_efi_uintn_t)handover_offset, kernel_params); ++ hf = (handover_func)((char *)kernel_addr + handover_offset + offset); + hf (grub_efi_image_handle, grub_efi_system_table, kernel_params); + + return GRUB_ERR_BUG; +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 1e09c88ab..0b3d20875 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -44,14 +44,10 @@ static char *linux_cmdline; + static grub_err_t + grub_linuxefi_boot (void) + { +- int offset = 0; +- +-#ifdef __x86_64__ +- offset = 512; +-#endif + asm volatile ("cli"); + +- return grub_efi_linux_boot ((char *)kernel_mem, handover_offset + offset, ++ return grub_efi_linux_boot ((char *)kernel_mem, ++ handover_offset, + params); + } + +@@ -147,14 +143,20 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + return grub_errno; + } + ++#define MIN(a, b) \ ++ ({ typeof (a) _a = (a); \ ++ typeof (b) _b = (b); \ ++ _a < _b ? _a : _b; }) ++ + static grub_err_t + grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) + { + grub_file_t file = 0; +- struct linux_i386_kernel_header lh; +- grub_ssize_t len, start, filelen; ++ struct linux_i386_kernel_header *lh = NULL; ++ grub_ssize_t start, filelen; + void *kernel = NULL; ++ int setup_header_end_offset; + grub_err_t err; + + grub_dl_ref (my_mod); +@@ -185,45 +187,79 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- params = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(16384)); +- ++ params = grub_efi_allocate_pages_max (0x3fffffff, ++ BYTES_TO_PAGES(sizeof(*params))); + if (! params) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); + goto fail; + } + +- grub_memset (params, 0, 16384); +- +- grub_memcpy (&lh, kernel, sizeof (lh)); +- +- if (lh.boot_flag != grub_cpu_to_le16 (0xaa55)) ++ grub_dprintf ("linux", "params = %p\n", params); ++ ++ grub_memset (params, 0, sizeof(*params)); ++ ++ setup_header_end_offset = *((grub_uint8_t *)kernel + 0x201); ++ grub_dprintf ("linux", "copying %lu bytes from %p to %p\n", ++ MIN((grub_size_t)0x202+setup_header_end_offset, ++ sizeof (*params)) - 0x1f1, ++ (grub_uint8_t *)kernel + 0x1f1, ++ (grub_uint8_t *)params + 0x1f1); ++ grub_memcpy ((grub_uint8_t *)params + 0x1f1, ++ (grub_uint8_t *)kernel + 0x1f1, ++ MIN((grub_size_t)0x202+setup_header_end_offset,sizeof (*params)) - 0x1f1); ++ lh = (struct linux_i386_kernel_header *)params; ++ grub_dprintf ("linux", "lh is at %p\n", lh); ++ grub_dprintf ("linux", "checking lh->boot_flag\n"); ++ if (lh->boot_flag != grub_cpu_to_le16 (0xaa55)) + { + grub_error (GRUB_ERR_BAD_OS, N_("invalid magic number")); + goto fail; + } + +- if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS) ++ grub_dprintf ("linux", "checking lh->setup_sects\n"); ++ if (lh->setup_sects > GRUB_LINUX_MAX_SETUP_SECTS) + { + grub_error (GRUB_ERR_BAD_OS, N_("too many setup sectors")); + goto fail; + } + +- if (lh.version < grub_cpu_to_le16 (0x020b)) ++ grub_dprintf ("linux", "checking lh->version\n"); ++ if (lh->version < grub_cpu_to_le16 (0x020b)) + { + grub_error (GRUB_ERR_BAD_OS, N_("kernel too old")); + goto fail; + } + +- if (!lh.handover_offset) ++ grub_dprintf ("linux", "checking lh->handover_offset\n"); ++ if (!lh->handover_offset) + { + grub_error (GRUB_ERR_BAD_OS, N_("kernel doesn't support EFI handover")); + goto fail; + } + +- linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff, +- BYTES_TO_PAGES(lh.cmdline_size + 1)); ++#if defined(__x86_64__) || defined(__aarch64__) ++ grub_dprintf ("linux", "checking lh->xloadflags\n"); ++ if (!(lh->xloadflags & LINUX_XLF_KERNEL_64)) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("kernel doesn't support 64-bit CPUs")); ++ goto fail; ++ } ++#endif ++ ++#if defined(__i386__) ++ if ((lh->xloadflags & LINUX_XLF_KERNEL_64) && ++ !(lh->xloadflags & LINUX_XLF_EFI_HANDOVER_32)) ++ { ++ grub_error (GRUB_ERR_BAD_OS, ++ N_("kernel doesn't support 32-bit handover")); ++ goto fail; ++ } ++#endif + ++ grub_dprintf ("linux", "setting up cmdline\n"); ++ linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff, ++ BYTES_TO_PAGES(lh->cmdline_size + 1)); + if (!linux_cmdline) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline")); +@@ -233,27 +269,26 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); + err = grub_create_loader_cmdline (argc, argv, + linux_cmdline + sizeof (LINUX_IMAGE) - 1, +- lh.cmdline_size - (sizeof (LINUX_IMAGE) - 1), ++ lh->cmdline_size - (sizeof (LINUX_IMAGE) - 1), + GRUB_VERIFY_KERNEL_CMDLINE); + if (err) + goto fail; + +- lh.cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline; ++ grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline); ++ grub_dprintf ("linux", "setting lh->cmd_line_ptr\n"); ++ lh->cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline; + +- handover_offset = lh.handover_offset; ++ grub_dprintf ("linux", "computing handover offset\n"); ++ handover_offset = lh->handover_offset; + +- start = (lh.setup_sects + 1) * 512; +- len = grub_file_size(file) - start; ++ start = (lh->setup_sects + 1) * 512; + +- kernel_mem = grub_efi_allocate_fixed (lh.pref_address, +- BYTES_TO_PAGES(lh.init_size)); ++ kernel_mem = grub_efi_allocate_pages_max(lh->pref_address, ++ BYTES_TO_PAGES(lh->init_size)); + + if (!kernel_mem) +- { +- grub_errno = GRUB_ERR_NONE; +- kernel_mem = grub_efi_allocate_pages_max(0x3fffffff, +- BYTES_TO_PAGES(lh.init_size)); +- } ++ kernel_mem = grub_efi_allocate_pages_max(0x3fffffff, ++ BYTES_TO_PAGES(lh->init_size)); + + if (!kernel_mem) + { +@@ -261,21 +296,23 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- grub_memcpy (kernel_mem, (char *)kernel + start, len); ++ grub_dprintf ("linux", "kernel_mem = %lx\n", (unsigned long) kernel_mem); ++ + grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); + loaded=1; ++ grub_dprintf ("linux", "setting lh->code32_start to %p\n", kernel_mem); ++ lh->code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem; + +- lh.code32_start = (grub_uint32_t)(grub_uint64_t) kernel_mem; +- /* Grub linuxefi erroneously initialize linux's boot_params with non-zero values. (bsc#1025563) ++ grub_memcpy (kernel_mem, (char *)kernel + start, filelen - start); + +- From https://www.kernel.org/doc/Documentation/x86/boot.txt: +- The memory for struct boot_params could be allocated anywhere (even above 4G) +- and initialized to all zero. +- Then, the setup header at offset 0x01f1 of kernel image on should be +- loaded into struct boot_params and examined. */ +- grub_memcpy (¶ms->setup_sects, &lh.setup_sects, sizeof (lh) - 0x01f1); ++ grub_dprintf ("linux", "setting lh->type_of_loader\n"); ++ lh->type_of_loader = 0x6; + +- params->type_of_loader = 0x21; ++ grub_dprintf ("linux", "setting lh->ext_loader_{type,ver}\n"); ++ params->ext_loader_type = 0; ++ params->ext_loader_ver = 2; ++ grub_dprintf("linux", "kernel_mem: %p handover_offset: %08x\n", ++ kernel_mem, handover_offset); + + fail: + +@@ -291,8 +328,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + loaded = 0; + } + +- if (linux_cmdline && !loaded) +- grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)linux_cmdline, BYTES_TO_PAGES(lh.cmdline_size + 1)); ++ if (linux_cmdline && lh && !loaded) ++ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t) ++ linux_cmdline, ++ BYTES_TO_PAGES(lh->cmdline_size + 1)); + + if (kernel_mem && !loaded) + grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)kernel_mem, BYTES_TO_PAGES(kernel_size)); +diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h +index eddf9251d..25ef52c04 100644 +--- a/include/grub/i386/linux.h ++++ b/include/grub/i386/linux.h +@@ -138,7 +138,12 @@ struct linux_i386_kernel_header + grub_uint32_t kernel_alignment; + grub_uint8_t relocatable; + grub_uint8_t min_alignment; +- grub_uint8_t pad[2]; ++#define LINUX_XLF_KERNEL_64 (1<<0) ++#define LINUX_XLF_CAN_BE_LOADED_ABOVE_4G (1<<1) ++#define LINUX_XLF_EFI_HANDOVER_32 (1<<2) ++#define LINUX_XLF_EFI_HANDOVER_64 (1<<3) ++#define LINUX_XLF_EFI_KEXEC (1<<4) ++ grub_uint16_t xloadflags; + grub_uint32_t cmdline_size; + grub_uint32_t hardware_subarch; + grub_uint64_t hardware_subarch_data; +-- +2.31.1 + diff --git a/0003-Make-grub_error-more-verbose.patch b/0003-Make-grub_error-more-verbose.patch new file mode 100644 index 0000000..944acb0 --- /dev/null +++ b/0003-Make-grub_error-more-verbose.patch @@ -0,0 +1,61 @@ +From 3526c4e467ee01a3cfd2f4d627433d078a1ab780 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 27 Aug 2018 13:14:06 -0400 +Subject: [PATCH 3/9] Make grub_error() more verbose + +Signed-off-by: Peter Jones +--- + grub-core/kern/efi/mm.c | 17 ++++++++++++++--- + grub-core/kern/err.c | 13 +++++++++++-- + include/grub/err.h | 5 ++++- + 3 files changed, 29 insertions(+), 6 deletions(-) + +Index: grub-2.06~rc1/grub-core/kern/err.c +=================================================================== +--- grub-2.06~rc1.orig/grub-core/kern/err.c ++++ grub-2.06~rc1/grub-core/kern/err.c +@@ -33,15 +33,24 @@ static struct grub_error_saved grub_erro + static int grub_error_stack_pos; + static int grub_error_stack_assert; + ++#ifdef grub_error ++#undef grub_error ++#endif ++ + grub_err_t +-grub_error (grub_err_t n, const char *fmt, ...) ++grub_error (grub_err_t n, const char *file, const int line, const char *fmt, ...) + { + va_list ap; ++ int m; + + grub_errno = n; + ++ m = grub_snprintf (grub_errmsg, sizeof (grub_errmsg), "%s:%d:", file, line); ++ if (m < 0) ++ m = 0; ++ + va_start (ap, fmt); +- grub_vsnprintf (grub_errmsg, sizeof (grub_errmsg), _(fmt), ap); ++ grub_vsnprintf (grub_errmsg + m, sizeof (grub_errmsg) - m, _(fmt), ap); + va_end (ap); + + return n; +Index: grub-2.06~rc1/include/grub/err.h +=================================================================== +--- grub-2.06~rc1.orig/include/grub/err.h ++++ grub-2.06~rc1/include/grub/err.h +@@ -85,8 +85,11 @@ struct grub_error_saved + extern grub_err_t EXPORT_VAR(grub_errno); + extern char EXPORT_VAR(grub_errmsg)[GRUB_MAX_ERRMSG]; + +-grub_err_t EXPORT_FUNC(grub_error) (grub_err_t n, const char *fmt, ...) +- __attribute__ ((format (GNU_PRINTF, 2, 3))); ++grub_err_t EXPORT_FUNC(grub_error) (grub_err_t n, const char *file, const int line, const char *fmt, ...) ++ __attribute__ ((format (GNU_PRINTF, 4, 5))); ++ ++#define grub_error(n, fmt, ...) grub_error (n, __FILE__, __LINE__, fmt, ##__VA_ARGS__) ++ + void EXPORT_FUNC(grub_fatal) (const char *fmt, ...) __attribute__ ((noreturn)); + void EXPORT_FUNC(grub_error_push) (void); + int EXPORT_FUNC(grub_error_pop) (void); diff --git a/0003-bootp-New-net_bootp6-command.patch b/0003-bootp-New-net_bootp6-command.patch new file mode 100644 index 0000000..877206e --- /dev/null +++ b/0003-bootp-New-net_bootp6-command.patch @@ -0,0 +1,1120 @@ +From f6c8c7985fd88fc89cd49227c9e74feaf58cfdd6 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Sun, 10 Jul 2016 23:46:06 +0800 +Subject: [PATCH 3/8] bootp: New net_bootp6 command + +Implement new net_bootp6 command for IPv6 network auto configuration via the +DHCPv6 protocol (RFC3315). + +Signed-off-by: Michael Chang +Signed-off-by: Ken Lin + +V1: + * Use grub_calloc for overflow check and return NULL when it would + occur. + +--- + grub-core/net/bootp.c | 908 +++++++++++++++++++++++++++++++++++++++++++++++++- + grub-core/net/ip.c | 39 +++ + include/grub/net.h | 72 ++++ + 3 files changed, 1018 insertions(+), 1 deletion(-) + +Index: grub-2.06/grub-core/net/bootp.c +=================================================================== +--- grub-2.06.orig/grub-core/net/bootp.c ++++ grub-2.06/grub-core/net/bootp.c +@@ -24,6 +24,98 @@ + #include + #include + #include ++#include ++#include ++ ++static int ++dissect_url (const char *url, char **proto, char **host, char **path) ++{ ++ const char *p, *ps; ++ grub_size_t l; ++ ++ *proto = *host = *path = NULL; ++ ps = p = url; ++ ++ while ((p = grub_strchr (p, ':'))) ++ { ++ if (grub_strlen (p) < sizeof ("://") - 1) ++ break; ++ if (grub_memcmp (p, "://", sizeof ("://") - 1) == 0) ++ { ++ l = p - ps; ++ *proto = grub_malloc (l + 1); ++ if (!*proto) ++ { ++ grub_print_error (); ++ return 0; ++ } ++ ++ grub_memcpy (*proto, ps, l); ++ (*proto)[l] = '\0'; ++ p += sizeof ("://") - 1; ++ break; ++ } ++ ++p; ++ } ++ ++ if (!*proto) ++ { ++ grub_dprintf ("bootp", "url: %s is not valid, protocol not found\n", url); ++ return 0; ++ } ++ ++ ps = p; ++ p = grub_strchr (p, '/'); ++ ++ if (!p) ++ { ++ grub_dprintf ("bootp", "url: %s is not valid, host/path not found\n", url); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ ++ l = p - ps; ++ ++ if (l > 2 && ps[0] == '[' && ps[l - 1] == ']') ++ { ++ *host = grub_malloc (l - 1); ++ if (!*host) ++ { ++ grub_print_error (); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ grub_memcpy (*host, ps + 1, l - 2); ++ (*host)[l - 2] = 0; ++ } ++ else ++ { ++ *host = grub_malloc (l + 1); ++ if (!*host) ++ { ++ grub_print_error (); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ grub_memcpy (*host, ps, l); ++ (*host)[l] = 0; ++ } ++ ++ *path = grub_strdup (p); ++ if (!*path) ++ { ++ grub_print_error (); ++ grub_free (*host); ++ grub_free (*proto); ++ *host = NULL; ++ *proto = NULL; ++ return 0; ++ } ++ return 1; ++} + + struct grub_dhcp_discover_options + { +@@ -607,6 +699,578 @@ out: + return err; + } + ++/* The default netbuff size for sending DHCPv6 packets which should be ++ large enough to hold the information */ ++#define GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE 512 ++ ++struct grub_dhcp6_options ++{ ++ grub_uint8_t *client_duid; ++ grub_uint16_t client_duid_len; ++ grub_uint8_t *server_duid; ++ grub_uint16_t server_duid_len; ++ grub_uint32_t iaid; ++ grub_uint32_t t1; ++ grub_uint32_t t2; ++ grub_net_network_level_address_t *ia_addr; ++ grub_uint32_t preferred_lifetime; ++ grub_uint32_t valid_lifetime; ++ grub_net_network_level_address_t *dns_server_addrs; ++ grub_uint16_t num_dns_server; ++ char *boot_file_proto; ++ char *boot_file_server_ip; ++ char *boot_file_path; ++}; ++ ++typedef struct grub_dhcp6_options *grub_dhcp6_options_t; ++ ++struct grub_dhcp6_session ++{ ++ struct grub_dhcp6_session *next; ++ struct grub_dhcp6_session **prev; ++ grub_uint32_t iaid; ++ grub_uint32_t transaction_id:24; ++ grub_uint64_t start_time; ++ struct grub_net_dhcp6_option_duid_ll duid; ++ struct grub_net_network_level_interface *iface; ++ ++ /* The associated dhcpv6 options */ ++ grub_dhcp6_options_t adv; ++ grub_dhcp6_options_t reply; ++}; ++ ++typedef struct grub_dhcp6_session *grub_dhcp6_session_t; ++ ++typedef void (*dhcp6_option_hook_fn) (const struct grub_net_dhcp6_option *opt, void *data); ++ ++static void ++foreach_dhcp6_option (const struct grub_net_dhcp6_option *opt, grub_size_t size, ++ dhcp6_option_hook_fn hook, void *hook_data); ++ ++static void ++parse_dhcp6_iaaddr (const struct grub_net_dhcp6_option *opt, void *data) ++{ ++ grub_dhcp6_options_t dhcp6 = (grub_dhcp6_options_t )data; ++ ++ grub_uint16_t code = grub_be_to_cpu16 (opt->code); ++ grub_uint16_t len = grub_be_to_cpu16 (opt->len); ++ ++ if (code == GRUB_NET_DHCP6_OPTION_IAADDR) ++ { ++ const struct grub_net_dhcp6_option_iaaddr *iaaddr; ++ iaaddr = (const struct grub_net_dhcp6_option_iaaddr *)opt->data; ++ ++ if (len < sizeof (*iaaddr)) ++ { ++ grub_dprintf ("bootp", "DHCPv6: code %u with insufficient length %u\n", code, len); ++ return; ++ } ++ if (!dhcp6->ia_addr) ++ { ++ dhcp6->ia_addr = grub_malloc (sizeof(*dhcp6->ia_addr)); ++ dhcp6->ia_addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ dhcp6->ia_addr->ipv6[0] = grub_get_unaligned64 (iaaddr->addr); ++ dhcp6->ia_addr->ipv6[1] = grub_get_unaligned64 (iaaddr->addr + 8); ++ dhcp6->preferred_lifetime = grub_be_to_cpu32 (iaaddr->preferred_lifetime); ++ dhcp6->valid_lifetime = grub_be_to_cpu32 (iaaddr->valid_lifetime); ++ } ++ } ++} ++ ++static void ++parse_dhcp6_option (const struct grub_net_dhcp6_option *opt, void *data) ++{ ++ grub_dhcp6_options_t dhcp6 = (grub_dhcp6_options_t)data; ++ grub_uint16_t code = grub_be_to_cpu16 (opt->code); ++ grub_uint16_t len = grub_be_to_cpu16 (opt->len); ++ ++ switch (code) ++ { ++ case GRUB_NET_DHCP6_OPTION_CLIENTID: ++ ++ if (dhcp6->client_duid || !len) ++ { ++ grub_dprintf ("bootp", "Skipped DHCPv6 CLIENTID with length %u\n", len); ++ break; ++ } ++ dhcp6->client_duid = grub_malloc (len); ++ grub_memcpy (dhcp6->client_duid, opt->data, len); ++ dhcp6->client_duid_len = len; ++ break; ++ ++ case GRUB_NET_DHCP6_OPTION_SERVERID: ++ ++ if (dhcp6->server_duid || !len) ++ { ++ grub_dprintf ("bootp", "Skipped DHCPv6 SERVERID with length %u\n", len); ++ break; ++ } ++ dhcp6->server_duid = grub_malloc (len); ++ grub_memcpy (dhcp6->server_duid, opt->data, len); ++ dhcp6->server_duid_len = len; ++ break; ++ ++ case GRUB_NET_DHCP6_OPTION_IA_NA: ++ { ++ const struct grub_net_dhcp6_option_iana *ia_na; ++ grub_uint16_t data_len; ++ ++ if (dhcp6->iaid || len < sizeof (*ia_na)) ++ { ++ grub_dprintf ("bootp", "Skipped DHCPv6 IA_NA with length %u\n", len); ++ break; ++ } ++ ia_na = (const struct grub_net_dhcp6_option_iana *)opt->data; ++ dhcp6->iaid = grub_be_to_cpu32 (ia_na->iaid); ++ dhcp6->t1 = grub_be_to_cpu32 (ia_na->t1); ++ dhcp6->t2 = grub_be_to_cpu32 (ia_na->t2); ++ ++ data_len = len - sizeof (*ia_na); ++ if (data_len) ++ foreach_dhcp6_option ((const struct grub_net_dhcp6_option *)ia_na->data, data_len, parse_dhcp6_iaaddr, dhcp6); ++ } ++ break; ++ ++ case GRUB_NET_DHCP6_OPTION_DNS_SERVERS: ++ { ++ const grub_uint8_t *po; ++ grub_uint16_t ln; ++ grub_net_network_level_address_t *la; ++ ++ if (!len || len & 0xf) ++ { ++ grub_dprintf ("bootp", "Skip invalid length DHCPv6 DNS_SERVERS \n"); ++ break; ++ } ++ dhcp6->num_dns_server = ln = len >> 4; ++ dhcp6->dns_server_addrs = la = grub_calloc (ln, sizeof (*la)); ++ ++ for (po = opt->data; ln > 0; po += 0x10, la++, ln--) ++ { ++ la->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ la->ipv6[0] = grub_get_unaligned64 (po); ++ la->ipv6[1] = grub_get_unaligned64 (po + 8); ++ la->option = DNS_OPTION_PREFER_IPV6; ++ } ++ } ++ break; ++ ++ case GRUB_NET_DHCP6_OPTION_BOOTFILE_URL: ++ dissect_url ((const char *)opt->data, ++ &dhcp6->boot_file_proto, ++ &dhcp6->boot_file_server_ip, ++ &dhcp6->boot_file_path); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++static void ++foreach_dhcp6_option (const struct grub_net_dhcp6_option *opt, grub_size_t size, dhcp6_option_hook_fn hook, void *hook_data) ++{ ++ while (size) ++ { ++ grub_uint16_t code, len; ++ ++ if (size < sizeof (*opt)) ++ { ++ grub_dprintf ("bootp", "DHCPv6: Options stopped with remaining size %" PRIxGRUB_SIZE "\n", size); ++ break; ++ } ++ size -= sizeof (*opt); ++ len = grub_be_to_cpu16 (opt->len); ++ code = grub_be_to_cpu16 (opt->code); ++ if (size < len) ++ { ++ grub_dprintf ("bootp", "DHCPv6: Options stopped at out of bound length %u for option %u\n", len, code); ++ break; ++ } ++ if (!len) ++ { ++ grub_dprintf ("bootp", "DHCPv6: Options stopped at zero length option %u\n", code); ++ break; ++ } ++ else ++ { ++ if (hook) ++ hook (opt, hook_data); ++ size -= len; ++ opt = (const struct grub_net_dhcp6_option *)((grub_uint8_t *)opt + len + sizeof (*opt)); ++ } ++ } ++} ++ ++static grub_dhcp6_options_t ++grub_dhcp6_options_get (const struct grub_net_dhcp6_packet *v6h, ++ grub_size_t size) ++{ ++ grub_dhcp6_options_t options; ++ ++ if (size < sizeof (*v6h)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("DHCPv6 packet size too small")); ++ return NULL; ++ } ++ ++ options = grub_zalloc (sizeof(*options)); ++ if (!options) ++ return NULL; ++ ++ foreach_dhcp6_option ((const struct grub_net_dhcp6_option *)v6h->dhcp_options, ++ size - sizeof (*v6h), parse_dhcp6_option, options); ++ ++ return options; ++} ++ ++static void ++grub_dhcp6_options_free (grub_dhcp6_options_t options) ++{ ++ if (options->client_duid) ++ grub_free (options->client_duid); ++ if (options->server_duid) ++ grub_free (options->server_duid); ++ if (options->ia_addr) ++ grub_free (options->ia_addr); ++ if (options->dns_server_addrs) ++ grub_free (options->dns_server_addrs); ++ if (options->boot_file_proto) ++ grub_free (options->boot_file_proto); ++ if (options->boot_file_server_ip) ++ grub_free (options->boot_file_server_ip); ++ if (options->boot_file_path) ++ grub_free (options->boot_file_path); ++ ++ grub_free (options); ++} ++ ++static grub_dhcp6_session_t grub_dhcp6_sessions; ++#define FOR_DHCP6_SESSIONS(var) FOR_LIST_ELEMENTS (var, grub_dhcp6_sessions) ++ ++static void ++grub_net_configure_by_dhcp6_info (const char *name, ++ struct grub_net_card *card, ++ grub_dhcp6_options_t dhcp6, ++ int is_def, ++ int flags, ++ struct grub_net_network_level_interface **ret_inf) ++{ ++ grub_net_network_level_netaddress_t netaddr; ++ struct grub_net_network_level_interface *inf; ++ ++ if (dhcp6->ia_addr) ++ { ++ inf = grub_net_add_addr (name, card, dhcp6->ia_addr, &card->default_address, flags); ++ ++ netaddr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ netaddr.ipv6.base[0] = dhcp6->ia_addr->ipv6[0]; ++ netaddr.ipv6.base[1] = 0; ++ netaddr.ipv6.masksize = 64; ++ grub_net_add_route (name, netaddr, inf); ++ ++ if (ret_inf) ++ *ret_inf = inf; ++ } ++ ++ if (dhcp6->dns_server_addrs) ++ { ++ grub_uint16_t i; ++ ++ for (i = 0; i < dhcp6->num_dns_server; ++i) ++ grub_net_add_dns_server (dhcp6->dns_server_addrs + i); ++ } ++ ++ if (dhcp6->boot_file_path) ++ grub_env_set_net_property (name, "boot_file", dhcp6->boot_file_path, ++ grub_strlen (dhcp6->boot_file_path)); ++ ++ if (is_def && dhcp6->boot_file_server_ip) ++ { ++ grub_net_default_server = grub_strdup (dhcp6->boot_file_server_ip); ++ grub_env_set ("net_default_interface", name); ++ grub_env_export ("net_default_interface"); ++ } ++} ++ ++static void ++grub_dhcp6_session_add (struct grub_net_network_level_interface *iface, ++ grub_uint32_t iaid) ++{ ++ grub_dhcp6_session_t se; ++ struct grub_datetime date; ++ grub_err_t err; ++ grub_int64_t t = 0; ++ ++ se = grub_malloc (sizeof (*se)); ++ ++ err = grub_get_datetime (&date); ++ if (err || !grub_datetime2unixtime (&date, &t)) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ t = 0; ++ } ++ ++ se->iface = iface; ++ se->iaid = iaid; ++ se->transaction_id = t; ++ se->start_time = grub_get_time_ms (); ++ se->duid.type = grub_cpu_to_be16_compile_time (3) ; ++ se->duid.hw_type = grub_cpu_to_be16_compile_time (1); ++ grub_memcpy (&se->duid.hwaddr, &iface->hwaddress.mac, sizeof (se->duid.hwaddr)); ++ se->adv = NULL; ++ se->reply = NULL; ++ grub_list_push (GRUB_AS_LIST_P (&grub_dhcp6_sessions), GRUB_AS_LIST (se)); ++} ++ ++static void ++grub_dhcp6_session_remove (grub_dhcp6_session_t se) ++{ ++ grub_list_remove (GRUB_AS_LIST (se)); ++ if (se->adv) ++ grub_dhcp6_options_free (se->adv); ++ if (se->reply) ++ grub_dhcp6_options_free (se->reply); ++ grub_free (se); ++} ++ ++static void ++grub_dhcp6_session_remove_all (void) ++{ ++ grub_dhcp6_session_t se; ++ ++ FOR_DHCP6_SESSIONS (se) ++ { ++ grub_dhcp6_session_remove (se); ++ se = grub_dhcp6_sessions; ++ } ++} ++ ++static grub_err_t ++grub_dhcp6_session_configure_network (grub_dhcp6_session_t se) ++{ ++ char *name; ++ ++ name = grub_xasprintf ("%s:dhcp6", se->iface->card->name); ++ if (!name) ++ return grub_errno; ++ ++ grub_net_configure_by_dhcp6_info (name, se->iface->card, se->reply, 1, 0, 0); ++ grub_free (name); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_dhcp6_session_send_request (grub_dhcp6_session_t se) ++{ ++ struct grub_net_buff *nb; ++ struct grub_net_dhcp6_option *opt; ++ struct grub_net_dhcp6_packet *v6h; ++ struct grub_net_dhcp6_option_iana *ia_na; ++ struct grub_net_dhcp6_option_iaaddr *iaaddr; ++ struct udphdr *udph; ++ grub_net_network_level_address_t multicast; ++ grub_net_link_level_address_t ll_multicast; ++ grub_uint64_t elapsed; ++ struct grub_net_network_level_interface *inf = se->iface; ++ grub_dhcp6_options_t dhcp6 = se->adv; ++ grub_err_t err = GRUB_ERR_NONE; ++ ++ multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ multicast.ipv6[0] = grub_cpu_to_be64_compile_time (0xff02ULL << 48); ++ multicast.ipv6[1] = grub_cpu_to_be64_compile_time (0x10002ULL); ++ ++ err = grub_net_link_layer_resolve (inf, &multicast, &ll_multicast); ++ if (err) ++ return err; ++ ++ nb = grub_netbuff_alloc (GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE); ++ ++ if (!nb) ++ return grub_errno; ++ ++ err = grub_netbuff_reserve (nb, GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ err = grub_netbuff_push (nb, dhcp6->client_duid_len + sizeof (*opt)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_CLIENTID); ++ opt->len = grub_cpu_to_be16 (dhcp6->client_duid_len); ++ grub_memcpy (opt->data, dhcp6->client_duid , dhcp6->client_duid_len); ++ ++ err = grub_netbuff_push (nb, dhcp6->server_duid_len + sizeof (*opt)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_SERVERID); ++ opt->len = grub_cpu_to_be16 (dhcp6->server_duid_len); ++ grub_memcpy (opt->data, dhcp6->server_duid , dhcp6->server_duid_len); ++ ++ err = grub_netbuff_push (nb, sizeof (*ia_na) + sizeof (*opt)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ if (dhcp6->ia_addr) ++ { ++ err = grub_netbuff_push (nb, sizeof(*iaaddr) + sizeof (*opt)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ } ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA); ++ opt->len = grub_cpu_to_be16 (sizeof (*ia_na)); ++ if (dhcp6->ia_addr) ++ opt->len += grub_cpu_to_be16 (sizeof(*iaaddr) + sizeof (*opt)); ++ ++ ia_na = (struct grub_net_dhcp6_option_iana *)opt->data; ++ ia_na->iaid = grub_cpu_to_be32 (dhcp6->iaid); ++ ++ ia_na->t1 = grub_cpu_to_be32 (dhcp6->t1); ++ ia_na->t2 = grub_cpu_to_be32 (dhcp6->t2); ++ ++ if (dhcp6->ia_addr) ++ { ++ opt = (struct grub_net_dhcp6_option *)ia_na->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IAADDR); ++ opt->len = grub_cpu_to_be16 (sizeof (*iaaddr)); ++ iaaddr = (struct grub_net_dhcp6_option_iaaddr *)opt->data; ++ grub_set_unaligned64 (iaaddr->addr, dhcp6->ia_addr->ipv6[0]); ++ grub_set_unaligned64 (iaaddr->addr + 8, dhcp6->ia_addr->ipv6[1]); ++ ++ iaaddr->preferred_lifetime = grub_cpu_to_be32 (dhcp6->preferred_lifetime); ++ iaaddr->valid_lifetime = grub_cpu_to_be32 (dhcp6->valid_lifetime); ++ } ++ ++ err = grub_netbuff_push (nb, sizeof (*opt) + 2 * sizeof (grub_uint16_t)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ opt = (struct grub_net_dhcp6_option*) nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ORO); ++ opt->len = grub_cpu_to_be16_compile_time (2 * sizeof (grub_uint16_t)); ++ grub_set_unaligned16 (opt->data, grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_BOOTFILE_URL)); ++ grub_set_unaligned16 (opt->data + 2, grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_DNS_SERVERS)); ++ ++ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (grub_uint16_t)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ opt = (struct grub_net_dhcp6_option*) nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ELAPSED_TIME); ++ opt->len = grub_cpu_to_be16_compile_time (sizeof (grub_uint16_t)); ++ ++ /* the time is expressed in hundredths of a second */ ++ elapsed = grub_divmod64 (grub_get_time_ms () - se->start_time, 10, 0); ++ ++ if (elapsed > 0xffff) ++ elapsed = 0xffff; ++ ++ grub_set_unaligned16 (opt->data, grub_cpu_to_be16 ((grub_uint16_t)elapsed)); ++ ++ err = grub_netbuff_push (nb, sizeof (*v6h)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ v6h = (struct grub_net_dhcp6_packet *) nb->data; ++ v6h->message_type = GRUB_NET_DHCP6_REQUEST; ++ v6h->transaction_id = se->transaction_id; ++ ++ err = grub_netbuff_push (nb, sizeof (*udph)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ udph = (struct udphdr *) nb->data; ++ udph->src = grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT); ++ udph->dst = grub_cpu_to_be16_compile_time (DHCP6_SERVER_PORT); ++ udph->chksum = 0; ++ udph->len = grub_cpu_to_be16 (nb->tail - nb->data); ++ ++ udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP, ++ &inf->address, ++ &multicast); ++ err = grub_net_send_ip_packet (inf, &multicast, &ll_multicast, nb, ++ GRUB_NET_IP_UDP); ++ ++ grub_netbuff_free (nb); ++ ++ return err; ++} ++ ++struct grub_net_network_level_interface * ++grub_net_configure_by_dhcpv6_reply (const char *name, ++ struct grub_net_card *card, ++ grub_net_interface_flags_t flags, ++ const struct grub_net_dhcp6_packet *v6h, ++ grub_size_t size, ++ int is_def, ++ char **device, char **path) ++{ ++ struct grub_net_network_level_interface *inf; ++ grub_dhcp6_options_t dhcp6; ++ ++ dhcp6 = grub_dhcp6_options_get (v6h, size); ++ if (!dhcp6) ++ { ++ grub_print_error (); ++ return NULL; ++ } ++ ++ grub_net_configure_by_dhcp6_info (name, card, dhcp6, is_def, flags, &inf); ++ ++ if (device && dhcp6->boot_file_proto && dhcp6->boot_file_server_ip) ++ { ++ *device = grub_xasprintf ("%s,%s", dhcp6->boot_file_proto, dhcp6->boot_file_server_ip); ++ grub_print_error (); ++ } ++ if (path && dhcp6->boot_file_path) ++ { ++ *path = grub_strdup (dhcp6->boot_file_path); ++ grub_print_error (); ++ if (*path) ++ { ++ char *slash; ++ slash = grub_strrchr (*path, '/'); ++ if (slash) ++ *slash = 0; ++ else ++ **path = 0; ++ } ++ } ++ ++ grub_dhcp6_options_free (dhcp6); ++ return inf; ++} ++ + /* + * This is called directly from net/ip.c:handle_dgram(), because those + * BOOTP/DHCP packets are a bit special due to their improper +@@ -675,6 +1339,77 @@ grub_net_process_dhcp (struct grub_net_b + } + } + ++grub_err_t ++grub_net_process_dhcp6 (struct grub_net_buff *nb, ++ struct grub_net_card *card __attribute__ ((unused))) ++{ ++ const struct grub_net_dhcp6_packet *v6h; ++ grub_dhcp6_session_t se; ++ grub_size_t size; ++ grub_dhcp6_options_t options; ++ ++ v6h = (const struct grub_net_dhcp6_packet *) nb->data; ++ size = nb->tail - nb->data; ++ ++ options = grub_dhcp6_options_get (v6h, size); ++ if (!options) ++ return grub_errno; ++ ++ if (!options->client_duid || !options->server_duid || !options->ia_addr) ++ { ++ grub_dhcp6_options_free (options); ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Bad DHCPv6 Packet"); ++ } ++ ++ FOR_DHCP6_SESSIONS (se) ++ { ++ if (se->transaction_id == v6h->transaction_id && ++ grub_memcmp (options->client_duid, &se->duid, sizeof (se->duid)) == 0 && ++ se->iaid == options->iaid) ++ break; ++ } ++ ++ if (!se) ++ { ++ grub_dprintf ("bootp", "DHCPv6 session not found\n"); ++ grub_dhcp6_options_free (options); ++ return GRUB_ERR_NONE; ++ } ++ ++ if (v6h->message_type == GRUB_NET_DHCP6_ADVERTISE) ++ { ++ if (se->adv) ++ { ++ grub_dprintf ("bootp", "Skipped DHCPv6 Advertised .. \n"); ++ grub_dhcp6_options_free (options); ++ return GRUB_ERR_NONE; ++ } ++ ++ se->adv = options; ++ return grub_dhcp6_session_send_request (se); ++ } ++ else if (v6h->message_type == GRUB_NET_DHCP6_REPLY) ++ { ++ if (!se->adv) ++ { ++ grub_dprintf ("bootp", "Skipped DHCPv6 Reply .. \n"); ++ grub_dhcp6_options_free (options); ++ return GRUB_ERR_NONE; ++ } ++ ++ se->reply = options; ++ grub_dhcp6_session_configure_network (se); ++ grub_dhcp6_session_remove (se); ++ return GRUB_ERR_NONE; ++ } ++ else ++ { ++ grub_dhcp6_options_free (options); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ + static grub_err_t + grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)), + int argc, char **args) +@@ -900,7 +1635,174 @@ grub_cmd_bootp (struct grub_command *cmd + return err; + } + +-static grub_command_t cmd_getdhcp, cmd_bootp, cmd_dhcp; ++static grub_err_t ++grub_cmd_bootp6 (struct grub_command *cmd __attribute__ ((unused)), ++ int argc, char **args) ++{ ++ struct grub_net_card *card; ++ grub_uint32_t iaid = 0; ++ int interval; ++ grub_err_t err; ++ grub_dhcp6_session_t se; ++ ++ err = GRUB_ERR_NONE; ++ ++ FOR_NET_CARDS (card) ++ { ++ struct grub_net_network_level_interface *iface; ++ ++ if (argc > 0 && grub_strcmp (card->name, args[0]) != 0) ++ continue; ++ ++ iface = grub_net_ipv6_get_link_local (card, &card->default_address); ++ if (!iface) ++ { ++ grub_dhcp6_session_remove_all (); ++ return grub_errno; ++ } ++ ++ grub_dhcp6_session_add (iface, iaid++); ++ } ++ ++ for (interval = 200; interval < 10000; interval *= 2) ++ { ++ int done = 1; ++ ++ FOR_DHCP6_SESSIONS (se) ++ { ++ struct grub_net_buff *nb; ++ struct grub_net_dhcp6_option *opt; ++ struct grub_net_dhcp6_packet *v6h; ++ struct grub_net_dhcp6_option_duid_ll *duid; ++ struct grub_net_dhcp6_option_iana *ia_na; ++ grub_net_network_level_address_t multicast; ++ grub_net_link_level_address_t ll_multicast; ++ struct udphdr *udph; ++ ++ multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ multicast.ipv6[0] = grub_cpu_to_be64_compile_time (0xff02ULL << 48); ++ multicast.ipv6[1] = grub_cpu_to_be64_compile_time (0x10002ULL); ++ ++ err = grub_net_link_layer_resolve (se->iface, ++ &multicast, &ll_multicast); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ return err; ++ } ++ ++ nb = grub_netbuff_alloc (GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE); ++ ++ if (!nb) ++ { ++ grub_dhcp6_session_remove_all (); ++ return grub_errno; ++ } ++ ++ err = grub_netbuff_reserve (nb, GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (grub_uint16_t)); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ELAPSED_TIME); ++ opt->len = grub_cpu_to_be16_compile_time (sizeof (grub_uint16_t)); ++ grub_set_unaligned16 (opt->data, 0); ++ ++ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (*duid)); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_CLIENTID); ++ opt->len = grub_cpu_to_be16 (sizeof (*duid)); ++ ++ duid = (struct grub_net_dhcp6_option_duid_ll *) opt->data; ++ grub_memcpy (duid, &se->duid, sizeof (*duid)); ++ ++ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (*ia_na)); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA); ++ opt->len = grub_cpu_to_be16 (sizeof (*ia_na)); ++ ia_na = (struct grub_net_dhcp6_option_iana *)opt->data; ++ ia_na->iaid = grub_cpu_to_be32 (se->iaid); ++ ia_na->t1 = 0; ++ ia_na->t2 = 0; ++ ++ err = grub_netbuff_push (nb, sizeof (*v6h)); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ v6h = (struct grub_net_dhcp6_packet *)nb->data; ++ v6h->message_type = GRUB_NET_DHCP6_SOLICIT; ++ v6h->transaction_id = se->transaction_id; ++ ++ grub_netbuff_push (nb, sizeof (*udph)); ++ ++ udph = (struct udphdr *) nb->data; ++ udph->src = grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT); ++ udph->dst = grub_cpu_to_be16_compile_time (DHCP6_SERVER_PORT); ++ udph->chksum = 0; ++ udph->len = grub_cpu_to_be16 (nb->tail - nb->data); ++ ++ udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP, ++ &se->iface->address, &multicast); ++ ++ err = grub_net_send_ip_packet (se->iface, &multicast, ++ &ll_multicast, nb, GRUB_NET_IP_UDP); ++ done = 0; ++ grub_netbuff_free (nb); ++ ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ return err; ++ } ++ } ++ if (!done) ++ grub_net_poll_cards (interval, 0); ++ } ++ ++ FOR_DHCP6_SESSIONS (se) ++ { ++ grub_error_push (); ++ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, ++ N_("couldn't autoconfigure %s"), ++ se->iface->card->name); ++ } ++ ++ grub_dhcp6_session_remove_all (); ++ ++ return err; ++} ++ ++static grub_command_t cmd_getdhcp, cmd_bootp, cmd_dhcp, cmd_bootp6; + + void + grub_bootp_init (void) +@@ -914,6 +1816,9 @@ grub_bootp_init (void) + cmd_getdhcp = grub_register_command ("net_get_dhcp_option", grub_cmd_dhcpopt, + N_("VAR INTERFACE NUMBER DESCRIPTION"), + N_("retrieve DHCP option and save it into VAR. If VAR is - then print the value.")); ++ cmd_bootp6 = grub_register_command ("net_bootp6", grub_cmd_bootp6, ++ N_("[CARD]"), ++ N_("perform a DHCPv6 autoconfiguration")); + } + + void +@@ -922,4 +1827,5 @@ grub_bootp_fini (void) + grub_unregister_command (cmd_getdhcp); + grub_unregister_command (cmd_bootp); + grub_unregister_command (cmd_dhcp); ++ grub_unregister_command (cmd_bootp6); + } +Index: grub-2.06/grub-core/net/ip.c +=================================================================== +--- grub-2.06.orig/grub-core/net/ip.c ++++ grub-2.06/grub-core/net/ip.c +@@ -239,6 +239,45 @@ handle_dgram (struct grub_net_buff *nb, + { + struct udphdr *udph; + udph = (struct udphdr *) nb->data; ++ ++ if (proto == GRUB_NET_IP_UDP && udph->dst == grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT)) ++ { ++ if (udph->chksum) ++ { ++ grub_uint16_t chk, expected; ++ chk = udph->chksum; ++ udph->chksum = 0; ++ expected = grub_net_ip_transport_checksum (nb, ++ GRUB_NET_IP_UDP, ++ source, ++ dest); ++ if (expected != chk) ++ { ++ grub_dprintf ("net", "Invalid UDP checksum. " ++ "Expected %x, got %x\n", ++ grub_be_to_cpu16 (expected), ++ grub_be_to_cpu16 (chk)); ++ grub_netbuff_free (nb); ++ return GRUB_ERR_NONE; ++ } ++ udph->chksum = chk; ++ } ++ ++ err = grub_netbuff_pull (nb, sizeof (*udph)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ err = grub_net_process_dhcp6 (nb, card); ++ if (err) ++ grub_print_error (); ++ ++ grub_netbuff_free (nb); ++ return GRUB_ERR_NONE; ++ } ++ + if (proto == GRUB_NET_IP_UDP && grub_be_to_cpu16 (udph->dst) == 68) + { + const struct grub_net_bootp_packet *bootp; +Index: grub-2.06/include/grub/net.h +=================================================================== +--- grub-2.06.orig/include/grub/net.h ++++ grub-2.06/include/grub/net.h +@@ -448,6 +448,66 @@ struct grub_net_bootp_packet + grub_uint8_t vendor[0]; + } GRUB_PACKED; + ++struct grub_net_dhcp6_packet ++{ ++ grub_uint32_t message_type:8; ++ grub_uint32_t transaction_id:24; ++ grub_uint8_t dhcp_options[0]; ++} GRUB_PACKED; ++ ++struct grub_net_dhcp6_option { ++ grub_uint16_t code; ++ grub_uint16_t len; ++ grub_uint8_t data[0]; ++} GRUB_PACKED; ++ ++struct grub_net_dhcp6_option_iana { ++ grub_uint32_t iaid; ++ grub_uint32_t t1; ++ grub_uint32_t t2; ++ grub_uint8_t data[0]; ++} GRUB_PACKED; ++ ++struct grub_net_dhcp6_option_iaaddr { ++ grub_uint8_t addr[16]; ++ grub_uint32_t preferred_lifetime; ++ grub_uint32_t valid_lifetime; ++ grub_uint8_t data[0]; ++} GRUB_PACKED; ++ ++struct grub_net_dhcp6_option_duid_ll ++{ ++ grub_uint16_t type; ++ grub_uint16_t hw_type; ++ grub_uint8_t hwaddr[6]; ++} GRUB_PACKED; ++ ++enum ++ { ++ GRUB_NET_DHCP6_SOLICIT = 1, ++ GRUB_NET_DHCP6_ADVERTISE = 2, ++ GRUB_NET_DHCP6_REQUEST = 3, ++ GRUB_NET_DHCP6_REPLY = 7 ++ }; ++ ++enum ++ { ++ DHCP6_CLIENT_PORT = 546, ++ DHCP6_SERVER_PORT = 547 ++ }; ++ ++enum ++ { ++ GRUB_NET_DHCP6_OPTION_CLIENTID = 1, ++ GRUB_NET_DHCP6_OPTION_SERVERID = 2, ++ GRUB_NET_DHCP6_OPTION_IA_NA = 3, ++ GRUB_NET_DHCP6_OPTION_IAADDR = 5, ++ GRUB_NET_DHCP6_OPTION_ORO = 6, ++ GRUB_NET_DHCP6_OPTION_ELAPSED_TIME = 8, ++ GRUB_NET_DHCP6_OPTION_DNS_SERVERS = 23, ++ GRUB_NET_DHCP6_OPTION_BOOTFILE_URL = 59 ++ }; ++ + #define GRUB_NET_BOOTP_RFC1048_MAGIC_0 0x63 + #define GRUB_NET_BOOTP_RFC1048_MAGIC_1 0x82 + #define GRUB_NET_BOOTP_RFC1048_MAGIC_2 0x53 +@@ -483,6 +543,14 @@ grub_net_configure_by_dhcp_ack (const ch + grub_size_t size, + int is_def, char **device, char **path); + ++struct grub_net_network_level_interface * ++grub_net_configure_by_dhcpv6_reply (const char *name, ++ struct grub_net_card *card, ++ grub_net_interface_flags_t flags, ++ const struct grub_net_dhcp6_packet *v6, ++ grub_size_t size, ++ int is_def, char **device, char **path); ++ + grub_err_t + grub_net_add_ipv4_local (struct grub_net_network_level_interface *inf, + int mask); +@@ -491,6 +559,10 @@ void + grub_net_process_dhcp (struct grub_net_buff *nb, + struct grub_net_network_level_interface *iface); + ++grub_err_t ++grub_net_process_dhcp6 (struct grub_net_buff *nb, ++ struct grub_net_card *card); ++ + int + grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a, + const grub_net_link_level_address_t *b); diff --git a/0003-commands-boot-Add-API-to-pass-context-to-loader.patch b/0003-commands-boot-Add-API-to-pass-context-to-loader.patch new file mode 100644 index 0000000..3125a74 --- /dev/null +++ b/0003-commands-boot-Add-API-to-pass-context-to-loader.patch @@ -0,0 +1,161 @@ +From 8bb57923d39f00b6f850cf6138ff5973cfd0d25f Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Tue, 5 Apr 2022 10:58:28 +0100 +Subject: [PATCH 03/32] commands/boot: Add API to pass context to loader + +Loaders rely on global variables for saving context which is consumed +in the boot hook and freed in the unload hook. In the case where a loader +command is executed twice, calling grub_loader_set() a second time executes +the unload hook, but in some cases this runs when the loader's global +context has already been updated, resulting in the updated context being +freed and potential use-after-free bugs when the boot hook is subsequently +called. + +This adds a new API, grub_loader_set_ex(), which allows a loader to specify +context that is passed to its boot and unload hooks. This is an alternative +to requiring that loaders call grub_loader_unset() before mutating their +global context. + +Signed-off-by: Chris Coulson +Reviewed-by: Daniel Kiper +--- + grub-core/commands/boot.c | 66 ++++++++++++++++++++++++++++++++++----- + include/grub/loader.h | 5 +++ + 2 files changed, 63 insertions(+), 8 deletions(-) + +diff --git a/grub-core/commands/boot.c b/grub-core/commands/boot.c +index bbca81e947..61514788e2 100644 +--- a/grub-core/commands/boot.c ++++ b/grub-core/commands/boot.c +@@ -27,10 +27,20 @@ + + GRUB_MOD_LICENSE ("GPLv3+"); + +-static grub_err_t (*grub_loader_boot_func) (void); +-static grub_err_t (*grub_loader_unload_func) (void); ++static grub_err_t (*grub_loader_boot_func) (void *context); ++static grub_err_t (*grub_loader_unload_func) (void *context); ++static void *grub_loader_context; + static int grub_loader_flags; + ++struct grub_simple_loader_hooks ++{ ++ grub_err_t (*boot) (void); ++ grub_err_t (*unload) (void); ++}; ++ ++/* Don't heap allocate this to avoid making grub_loader_set() fallible. */ ++static struct grub_simple_loader_hooks simple_loader_hooks; ++ + struct grub_preboot + { + grub_err_t (*preboot_func) (int); +@@ -44,6 +54,29 @@ static int grub_loader_loaded; + static struct grub_preboot *preboots_head = 0, + *preboots_tail = 0; + ++static grub_err_t ++grub_simple_boot_hook (void *context) ++{ ++ struct grub_simple_loader_hooks *hooks; ++ ++ hooks = (struct grub_simple_loader_hooks *) context; ++ return hooks->boot (); ++} ++ ++static grub_err_t ++grub_simple_unload_hook (void *context) ++{ ++ struct grub_simple_loader_hooks *hooks; ++ grub_err_t ret; ++ ++ hooks = (struct grub_simple_loader_hooks *) context; ++ ++ ret = hooks->unload (); ++ grub_memset (hooks, 0, sizeof (*hooks)); ++ ++ return ret; ++} ++ + int + grub_loader_is_loaded (void) + { +@@ -110,28 +143,45 @@ grub_loader_unregister_preboot_hook (struct grub_preboot *hnd) + } + + void +-grub_loader_set (grub_err_t (*boot) (void), +- grub_err_t (*unload) (void), +- int flags) ++grub_loader_set_ex (grub_err_t (*boot) (void *context), ++ grub_err_t (*unload) (void *context), ++ void *context, ++ int flags) + { + if (grub_loader_loaded && grub_loader_unload_func) +- grub_loader_unload_func (); ++ grub_loader_unload_func (grub_loader_context); + + grub_loader_boot_func = boot; + grub_loader_unload_func = unload; ++ grub_loader_context = context; + grub_loader_flags = flags; + + grub_loader_loaded = 1; + } + ++void ++grub_loader_set (grub_err_t (*boot) (void), ++ grub_err_t (*unload) (void), ++ int flags) ++{ ++ grub_loader_set_ex (grub_simple_boot_hook, ++ grub_simple_unload_hook, ++ &simple_loader_hooks, ++ flags); ++ ++ simple_loader_hooks.boot = boot; ++ simple_loader_hooks.unload = unload; ++} ++ + void + grub_loader_unset(void) + { + if (grub_loader_loaded && grub_loader_unload_func) +- grub_loader_unload_func (); ++ grub_loader_unload_func (grub_loader_context); + + grub_loader_boot_func = 0; + grub_loader_unload_func = 0; ++ grub_loader_context = 0; + + grub_loader_loaded = 0; + } +@@ -158,7 +208,7 @@ grub_loader_boot (void) + return err; + } + } +- err = (grub_loader_boot_func) (); ++ err = (grub_loader_boot_func) (grub_loader_context); + + for (cur = preboots_tail; cur; cur = cur->prev) + if (! err) +diff --git a/include/grub/loader.h b/include/grub/loader.h +index b208642821..97f2310545 100644 +--- a/include/grub/loader.h ++++ b/include/grub/loader.h +@@ -40,6 +40,11 @@ void EXPORT_FUNC (grub_loader_set) (grub_err_t (*boot) (void), + grub_err_t (*unload) (void), + int flags); + ++void EXPORT_FUNC (grub_loader_set_ex) (grub_err_t (*boot) (void *context), ++ grub_err_t (*unload) (void *context), ++ void *context, ++ int flags); ++ + /* Unset current loader, if any. */ + void EXPORT_FUNC (grub_loader_unset) (void); + +-- +2.34.1 + diff --git a/0003-cryptodisk-Return-failure-in-cryptomount-when-no-cry.patch b/0003-cryptodisk-Return-failure-in-cryptomount-when-no-cry.patch new file mode 100644 index 0000000..8c0bc1a --- /dev/null +++ b/0003-cryptodisk-Return-failure-in-cryptomount-when-no-cry.patch @@ -0,0 +1,32 @@ +From 86fe3bbbf75e62387cc9842654fd6c852e9457a6 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:52 -0600 +Subject: [PATCH 03/14] cryptodisk: Return failure in cryptomount when no + cryptodisk modules are loaded + +This displays an error notifying the user that they'll want to load +a backend module to make cryptomount useful. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 9df3d310fe..27491871a5 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -1125,6 +1125,9 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + if (argc < 1 && !state[1].set && !state[2].set) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); + ++ if (grub_cryptodisk_list == NULL) ++ return grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk modules loaded"); ++ + if (state[0].set) + { + int found_uuid; +-- +2.34.1 + diff --git a/0003-disk-cryptodisk-When-cheatmounting-use-the-sector-in.patch b/0003-disk-cryptodisk-When-cheatmounting-use-the-sector-in.patch new file mode 100644 index 0000000..45baa6f --- /dev/null +++ b/0003-disk-cryptodisk-When-cheatmounting-use-the-sector-in.patch @@ -0,0 +1,71 @@ +From 5b694a13545224c2d21afc3e94831be1bcc85770 Mon Sep 17 00:00:00 2001 +From: Fabian Vogt +Date: Tue, 14 Jun 2022 15:55:21 +0200 +Subject: [PATCH 03/10] disk/cryptodisk: When cheatmounting, use the sector + info of the cheat device + +When using grub-probe with cryptodisk, the mapped block device from the host +is used directly instead of decrypting the source device in GRUB code. +In that case, the sector size and count of the host device needs to be used. +This is especially important when using luks2, which does not assign +total_sectors and log_sector_size when scanning, but only later when the +segments in the JSON area are evaluated. With an unset log_sector_size, +grub_open_device complains. + +This fixes grub-probe failing with +"error: sector sizes of 1 bytes aren't supported yet." + +Signed-off-by: Fabian Vogt +--- + grub-core/disk/cryptodisk.c | 20 ++++++++++++++++++-- + 1 file changed, 18 insertions(+), 2 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 6d22bf871c..ae8790f10f 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -698,16 +698,31 @@ grub_cryptodisk_open (const char *name, grub_disk_t disk) + if (!dev) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No such device"); + +- disk->log_sector_size = dev->log_sector_size; +- + #ifdef GRUB_UTIL + if (dev->cheat) + { ++ grub_uint64_t cheat_dev_size; ++ unsigned int cheat_log_sector_size; ++ + if (!GRUB_UTIL_FD_IS_VALID (dev->cheat_fd)) + dev->cheat_fd = grub_util_fd_open (dev->cheat, GRUB_UTIL_FD_O_RDONLY); + if (!GRUB_UTIL_FD_IS_VALID (dev->cheat_fd)) + return grub_error (GRUB_ERR_IO, N_("cannot open `%s': %s"), + dev->cheat, grub_util_fd_strerror ()); ++ ++ /* Use the sector size and count of the cheat device */ ++ cheat_dev_size = grub_util_get_fd_size (dev->cheat_fd, dev->cheat, &cheat_log_sector_size); ++ if (cheat_dev_size == -1) ++ { ++ const char *errmsg = grub_util_fd_strerror (); ++ grub_util_fd_close (dev->cheat_fd); ++ dev->cheat_fd = GRUB_UTIL_FD_INVALID; ++ return grub_error (GRUB_ERR_IO, N_("failed to query size of device `%s': %s"), ++ dev->cheat, errmsg); ++ } ++ ++ dev->log_sector_size = cheat_log_sector_size; ++ dev->total_sectors = cheat_dev_size >> cheat_log_sector_size; + } + #endif + +@@ -721,6 +736,7 @@ grub_cryptodisk_open (const char *name, grub_disk_t disk) + } + + disk->data = dev; ++ disk->log_sector_size = dev->log_sector_size; + disk->total_sectors = dev->total_sectors; + disk->max_agglomerate = GRUB_DISK_MAX_MAX_AGGLOMERATE; + disk->id = dev->id; +-- +2.34.1 + diff --git a/0003-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch b/0003-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch new file mode 100644 index 0000000..c62d25c --- /dev/null +++ b/0003-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch @@ -0,0 +1,260 @@ +From 94a752f603290443d9e526540d3b09a5e931a522 Mon Sep 17 00:00:00 2001 +From: Lu Ken +Date: Wed, 13 Jul 2022 10:06:12 +0800 +Subject: [PATCH 3/3] efi/tpm: Add EFI_CC_MEASUREMENT_PROTOCOL support + +The EFI_CC_MEASUREMENT_PROTOCOL abstracts the measurement for virtual firmware +in confidential computing environment. It is similar to the EFI_TCG2_PROTOCOL. +It was proposed by Intel and ARM and approved by UEFI organization. + +It is defined in Intel GHCI specification: https://cdrdv2.intel.com/v1/dl/getContent/726790 . +The EDKII header file is available at https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/CcMeasurement.h . + +Signed-off-by: Lu Ken +Reviewed-by: Daniel Kiper +--- + grub-core/commands/efi/tpm.c | 48 +++++++++++ + include/grub/efi/cc.h | 151 +++++++++++++++++++++++++++++++++++ + 2 files changed, 199 insertions(+) + create mode 100644 include/grub/efi/cc.h + +diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c +index 8fe3101f3..c3f6e00d2 100644 +--- a/grub-core/commands/efi/tpm.c ++++ b/grub-core/commands/efi/tpm.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -31,6 +32,7 @@ typedef TCG_PCR_EVENT grub_tpm_event_t; + + static grub_efi_guid_t tpm_guid = EFI_TPM_GUID; + static grub_efi_guid_t tpm2_guid = EFI_TPM2_GUID; ++static grub_efi_guid_t cc_measurement_guid = GRUB_EFI_CC_MEASUREMENT_PROTOCOL_GUID; + + static grub_efi_handle_t *grub_tpm_handle; + static grub_uint8_t grub_tpm_version; +@@ -222,6 +224,50 @@ grub_tpm2_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf, + return grub_efi_log_event_status (status); + } + ++static void ++grub_cc_log_event (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, ++ const char *description) ++{ ++ grub_efi_cc_event_t *event; ++ grub_efi_status_t status; ++ grub_efi_cc_protocol_t *cc; ++ grub_efi_cc_mr_index_t mr; ++ ++ cc = grub_efi_locate_protocol (&cc_measurement_guid, NULL); ++ if (cc == NULL) ++ return; ++ ++ status = efi_call_3 (cc->map_pcr_to_mr_index, cc, pcr, &mr); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_efi_log_event_status (status); ++ return; ++ } ++ ++ event = grub_zalloc (sizeof (grub_efi_cc_event_t) + ++ grub_strlen (description) + 1); ++ if (event == NULL) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate CC event buffer")); ++ return; ++ } ++ ++ event->Header.HeaderSize = sizeof (grub_efi_cc_event_header_t); ++ event->Header.HeaderVersion = GRUB_EFI_CC_EVENT_HEADER_VERSION; ++ event->Header.MrIndex = mr; ++ event->Header.EventType = EV_IPL; ++ event->Size = sizeof (*event) + grub_strlen (description) + 1; ++ grub_strcpy ((char *) event->Event, description); ++ ++ status = efi_call_5 (cc->hash_log_extend_event, cc, 0, ++ (grub_efi_physical_address_t)(grub_addr_t) buf, ++ (grub_efi_uint64_t) size, event); ++ grub_free (event); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ grub_efi_log_event_status (status); ++} ++ + grub_err_t + grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, + const char *description) +@@ -229,6 +275,8 @@ grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, + grub_efi_handle_t tpm_handle; + grub_efi_uint8_t protocol_version; + ++ grub_cc_log_event(buf, size, pcr, description); ++ + if (!grub_tpm_handle_find (&tpm_handle, &protocol_version)) + return 0; + +diff --git a/include/grub/efi/cc.h b/include/grub/efi/cc.h +new file mode 100644 +index 000000000..896030689 +--- /dev/null ++++ b/include/grub/efi/cc.h +@@ -0,0 +1,151 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 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 . ++ */ ++ ++#ifndef GRUB_EFI_CC_H ++#define GRUB_EFI_CC_H 1 ++ ++#include ++#include ++#include ++ ++#define GRUB_EFI_CC_MEASUREMENT_PROTOCOL_GUID \ ++ { 0x96751a3d, 0x72f4, 0x41a6, \ ++ { 0xa7, 0x94, 0xed, 0x5d, 0x0e, 0x67, 0xae, 0x6b } \ ++ }; ++ ++struct grub_efi_cc_version ++{ ++ grub_efi_uint8_t Major; ++ grub_efi_uint8_t Minor; ++}; ++typedef struct grub_efi_cc_version grub_efi_cc_version_t; ++ ++/* EFI_CC Type/SubType definition. */ ++#define GRUB_EFI_CC_TYPE_NONE 0 ++#define GRUB_EFI_CC_TYPE_SEV 1 ++#define GRUB_EFI_CC_TYPE_TDX 2 ++ ++struct grub_efi_cc_type ++{ ++ grub_efi_uint8_t Type; ++ grub_efi_uint8_t SubType; ++}; ++typedef struct grub_efi_cc_type grub_efi_cc_type_t; ++ ++typedef grub_efi_uint32_t grub_efi_cc_event_log_bitmap_t; ++typedef grub_efi_uint32_t grub_efi_cc_event_log_format_t; ++typedef grub_efi_uint32_t grub_efi_cc_event_algorithm_bitmap_t; ++typedef grub_efi_uint32_t grub_efi_cc_mr_index_t; ++ ++/* Intel TDX measure register index. */ ++#define GRUB_TDX_MR_INDEX_MRTD 0 ++#define GRUB_TDX_MR_INDEX_RTMR0 1 ++#define GRUB_TDX_MR_INDEX_RTMR1 2 ++#define GRUB_TDX_MR_INDEX_RTMR2 3 ++#define GRUB_TDX_MR_INDEX_RTMR3 4 ++ ++#define GRUB_EFI_CC_EVENT_LOG_FORMAT_TCG_2 0x00000002 ++#define GRUB_EFI_CC_BOOT_HASH_ALG_SHA384 0x00000004 ++#define GRUB_EFI_CC_EVENT_HEADER_VERSION 1 ++ ++struct grub_efi_cc_event_header ++{ ++ /* Size of the event header itself (sizeof(EFI_TD_EVENT_HEADER)). */ ++ grub_efi_uint32_t HeaderSize; ++ ++ /* ++ * Header version. For this version of this specification, ++ * the value shall be 1. ++ */ ++ grub_efi_uint16_t HeaderVersion; ++ ++ /* Index of the MR that shall be extended. */ ++ grub_efi_cc_mr_index_t MrIndex; ++ ++ /* Type of the event that shall be extended (and optionally logged). */ ++ grub_efi_uint32_t EventType; ++} GRUB_PACKED; ++typedef struct grub_efi_cc_event_header grub_efi_cc_event_header_t; ++ ++struct grub_efi_cc_event ++{ ++ /* Total size of the event including the Size component, the header and the Event data. */ ++ grub_efi_uint32_t Size; ++ grub_efi_cc_event_header_t Header; ++ grub_efi_uint8_t Event[0]; ++} GRUB_PACKED; ++typedef struct grub_efi_cc_event grub_efi_cc_event_t; ++ ++struct grub_efi_cc_boot_service_capability ++{ ++ /* Allocated size of the structure. */ ++ grub_efi_uint8_t Size; ++ ++ /* ++ * Version of the grub_efi_cc_boot_service_capability_t structure itself. ++ * For this version of the protocol, the Major version shall be set to 1 ++ * and the Minor version shall be set to 1. ++ */ ++ grub_efi_cc_version_t StructureVersion; ++ ++ /* ++ * Version of the EFI TD protocol. ++ * For this version of the protocol, the Major version shall be set to 1 ++ * and the Minor version shall be set to 1. ++ */ ++ grub_efi_cc_version_t ProtocolVersion; ++ ++ /* Supported hash algorithms. */ ++ grub_efi_cc_event_algorithm_bitmap_t HashAlgorithmBitmap; ++ ++ /* Bitmap of supported event log formats. */ ++ grub_efi_cc_event_log_bitmap_t SupportedEventLogs; ++ ++ /* Indicates the CC type. */ ++ grub_efi_cc_type_t CcType; ++}; ++typedef struct grub_efi_cc_boot_service_capability grub_efi_cc_boot_service_capability_t; ++ ++struct grub_efi_cc_protocol ++{ ++ grub_efi_status_t ++ (*get_capability) (struct grub_efi_cc_protocol *this, ++ grub_efi_cc_boot_service_capability_t *ProtocolCapability); ++ ++ grub_efi_status_t ++ (*get_event_log) (struct grub_efi_cc_protocol *this, ++ grub_efi_cc_event_log_format_t EventLogFormat, ++ grub_efi_physical_address_t *EventLogLocation, ++ grub_efi_physical_address_t *EventLogLastEntry, ++ grub_efi_boolean_t *EventLogTruncated); ++ ++ grub_efi_status_t ++ (*hash_log_extend_event) (struct grub_efi_cc_protocol *this, ++ grub_efi_uint64_t Flags, ++ grub_efi_physical_address_t DataToHash, ++ grub_efi_uint64_t DataToHashLen, ++ grub_efi_cc_event_t *EfiCcEvent); ++ ++ grub_efi_status_t ++ (*map_pcr_to_mr_index) (struct grub_efi_cc_protocol *this, ++ grub_efi_uint32_t PcrIndex, ++ grub_efi_cc_mr_index_t *MrIndex); ++}; ++typedef struct grub_efi_cc_protocol grub_efi_cc_protocol_t; ++ ++#endif +-- +2.35.3 + diff --git a/0003-font-Fix-several-integer-overflows-in-grub_font_cons.patch b/0003-font-Fix-several-integer-overflows-in-grub_font_cons.patch new file mode 100644 index 0000000..e50418e --- /dev/null +++ b/0003-font-Fix-several-integer-overflows-in-grub_font_cons.patch @@ -0,0 +1,81 @@ +From a63cbda5bbfa4696c97dc8231e7b81aedaef2fc7 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Fri, 5 Aug 2022 01:58:27 +0800 +Subject: [PATCH 03/12] font: Fix several integer overflows in + grub_font_construct_glyph() + +This patch fixes several integer overflows in grub_font_construct_glyph(). +Glyphs of invalid size, zero or leading to an overflow, are rejected. +The inconsistency between "glyph" and "max_glyph_size" when grub_malloc() +returns NULL is fixed too. + +Fixes: CVE-2022-2601 + +Reported-by: Zhang Boyang +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +--- + grub-core/font/font.c | 29 +++++++++++++++++------------ + 1 file changed, 17 insertions(+), 12 deletions(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index 6a3fbebbd..1fa181d4c 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -1517,6 +1517,7 @@ grub_font_construct_glyph (grub_font_t hinted_font, + struct grub_video_signed_rect bounds; + static struct grub_font_glyph *glyph = 0; + static grub_size_t max_glyph_size = 0; ++ grub_size_t cur_glyph_size; + + ensure_comb_space (glyph_id); + +@@ -1533,29 +1534,33 @@ grub_font_construct_glyph (grub_font_t hinted_font, + if (!glyph_id->ncomb && !glyph_id->attributes) + return main_glyph; + +- if (max_glyph_size < sizeof (*glyph) + (bounds.width * bounds.height + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT) ++ if (grub_video_bitmap_calc_1bpp_bufsz (bounds.width, bounds.height, &cur_glyph_size) || ++ grub_add (sizeof (*glyph), cur_glyph_size, &cur_glyph_size)) ++ return main_glyph; ++ ++ if (max_glyph_size < cur_glyph_size) + { + grub_free (glyph); +- max_glyph_size = (sizeof (*glyph) + (bounds.width * bounds.height + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT) * 2; +- if (max_glyph_size < 8) +- max_glyph_size = 8; +- glyph = grub_malloc (max_glyph_size); ++ if (grub_mul (cur_glyph_size, 2, &max_glyph_size)) ++ max_glyph_size = 0; ++ glyph = max_glyph_size > 0 ? grub_malloc (max_glyph_size) : NULL; + } + if (!glyph) + { ++ max_glyph_size = 0; + grub_errno = GRUB_ERR_NONE; + return main_glyph; + } + +- grub_memset (glyph, 0, sizeof (*glyph) +- + (bounds.width * bounds.height +- + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT); ++ grub_memset (glyph, 0, cur_glyph_size); + + glyph->font = main_glyph->font; +- glyph->width = bounds.width; +- glyph->height = bounds.height; +- glyph->offset_x = bounds.x; +- glyph->offset_y = bounds.y; ++ if (bounds.width == 0 || bounds.height == 0 || ++ grub_cast (bounds.width, &glyph->width) || ++ grub_cast (bounds.height, &glyph->height) || ++ grub_cast (bounds.x, &glyph->offset_x) || ++ grub_cast (bounds.y, &glyph->offset_y)) ++ return main_glyph; + + if (glyph_id->attributes & GRUB_UNICODE_GLYPH_ATTRIBUTE_MIRROR) + grub_font_blit_glyph_mirror (glyph, main_glyph, +-- +2.35.3 + diff --git a/0003-fs-ntfs-Fix-an-OOB-read-when-parsing-directory-entri.patch b/0003-fs-ntfs-Fix-an-OOB-read-when-parsing-directory-entri.patch new file mode 100644 index 0000000..77227b9 --- /dev/null +++ b/0003-fs-ntfs-Fix-an-OOB-read-when-parsing-directory-entri.patch @@ -0,0 +1,73 @@ +From 7e5f031a6a6a3decc2360a7b0c71abbe598e7354 Mon Sep 17 00:00:00 2001 +From: Maxim Suhanov +Date: Mon, 28 Aug 2023 16:33:17 +0300 +Subject: [PATCH 3/6] fs/ntfs: Fix an OOB read when parsing directory entries + from resident and non-resident index attributes + +This fix introduces checks to ensure that index entries are never read +beyond the corresponding directory index. + +The lack of this check is a minor issue, likely not exploitable in any way. + +Reported-by: Maxim Suhanov +Signed-off-by: Maxim Suhanov +Reviewed-by: Daniel Kiper +--- + grub-core/fs/ntfs.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index a68e173d8..2d78b96e1 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -599,7 +599,7 @@ get_utf8 (grub_uint8_t *in, grub_size_t len) + } + + static int +-list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos, ++list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos, grub_uint8_t *end_pos, + grub_fshelp_iterate_dir_hook_t hook, void *hook_data) + { + grub_uint8_t *np; +@@ -610,6 +610,9 @@ list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos, + grub_uint8_t namespace; + char *ustr; + ++ if ((pos >= end_pos) || (end_pos - pos < 0x52)) ++ break; ++ + if (pos[0xC] & 2) /* end signature */ + break; + +@@ -617,6 +620,9 @@ list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos, + ns = *(np++); + namespace = *(np++); + ++ if (2 * ns > end_pos - pos - 0x52) ++ break; ++ + /* + * Ignore files in DOS namespace, as they will reappear as Win32 + * names. +@@ -806,7 +812,9 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + } + + cur_pos += 0x10; /* Skip index root */ +- ret = list_file (mft, cur_pos + u16at (cur_pos, 0), hook, hook_data); ++ ret = list_file (mft, cur_pos + u16at (cur_pos, 0), ++ at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR), ++ hook, hook_data); + if (ret) + goto done; + +@@ -893,6 +901,7 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + (const grub_uint8_t *) "INDX"))) + goto done; + ret = list_file (mft, &indx[0x18 + u16at (indx, 0x18)], ++ indx + (mft->data->idx_size << GRUB_NTFS_BLK_SHR), + hook, hook_data); + if (ret) + goto done; +-- +2.42.0 + diff --git a/0003-grub-install-support-prep-environment-block.patch b/0003-grub-install-support-prep-environment-block.patch new file mode 100644 index 0000000..b470345 --- /dev/null +++ b/0003-grub-install-support-prep-environment-block.patch @@ -0,0 +1,97 @@ +From c31fc5aa0ded9ce1e774d0a3526cfee19be1b77f Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Mon, 7 Feb 2022 20:49:01 +0800 +Subject: [PATCH 3/5] grub-install: support prep environment block + +The grub-install can be instructed to create environment block at end of +PReP paritition with probed device identities and properties in +variables to facilitate root device discovery. So far these variables +are defined for this purpose: + +ENV_FS_UUID - The filesystem uuid for the grub root device +ENV_CRYPTO_UUID - The crytodisk uuid for the grub root device +ENV_GRUB_DIR - The path to grub prefix directory +ENV_HINT - The recommended hint string for searching root device + +The size of environment block is defined in GRUB_ENVBLK_PREP_SIZE which +is 4096 bytes and can be extended in the future. + +Signed-off-by: Michael Chang +--- + include/grub/lib/envblk.h | 3 +++ + util/grub-install.c | 38 ++++++++++++++++++++++++++++++++++++++ + 2 files changed, 41 insertions(+) + +diff --git a/include/grub/lib/envblk.h b/include/grub/lib/envblk.h +index 83f3fcf841..d01927bcf7 100644 +--- a/include/grub/lib/envblk.h ++++ b/include/grub/lib/envblk.h +@@ -24,6 +24,9 @@ + + #ifndef ASM_FILE + ++#include ++#define GRUB_ENVBLK_PREP_SIZE (GRUB_DISK_SECTOR_SIZE << 3) ++ + struct grub_envblk + { + char *buf; +diff --git a/util/grub-install.c b/util/grub-install.c +index 8fb5ea616b..7bc5f84378 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -43,6 +43,7 @@ + #include + #include + #include ++#include + + #include + +@@ -2112,6 +2113,43 @@ main (int argc, char *argv[]) + { + grub_util_error ("%s", _("failed to copy Grub to the PReP partition")); + } ++ ++ if ((signed_grub_mode >= SIGNED_GRUB_FORCE) || ((signed_grub_mode == SIGNED_GRUB_AUTO) && (ppc_sb_state > 0))) ++ { ++ char *uuid = NULL; ++ const char *cryptouuid = NULL; ++ grub_envblk_t envblk = NULL; ++ char *buf; ++ ++ /* TODO: Add LVM/RAID on encrypted partitions */ ++ if (grub_dev->disk && grub_dev->disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID) ++ cryptouuid = grub_util_cryptodisk_get_uuid (grub_dev->disk); ++ if (grub_fs->fs_uuid && grub_fs->fs_uuid (grub_dev, &uuid)) ++ { ++ grub_print_error (); ++ grub_errno = 0; ++ uuid = NULL; ++ } ++ buf = grub_envblk_buf (GRUB_ENVBLK_PREP_SIZE); ++ envblk = grub_envblk_open (buf, GRUB_ENVBLK_PREP_SIZE); ++ if (uuid) ++ grub_envblk_set (envblk, "ENV_FS_UUID", uuid); ++ if (cryptouuid) ++ grub_envblk_set (envblk, "ENV_CRYPTO_UUID", cryptouuid); ++ if (relative_grubdir) ++ grub_envblk_set (envblk, "ENV_GRUB_DIR", relative_grubdir); ++ if (have_abstractions) ++ grub_envblk_set (envblk, "ENV_HINT", grub_dev->disk->name); ++ if (use_relative_path_on_btrfs) ++ grub_envblk_set (envblk, "btrfs_relative_path", "1"); ++ if (envblk) ++ { ++ fprintf (stderr, _("Write environment block to PReP.\n")); ++ if (grub_disk_write_tail (ins_dev->disk, envblk->size, envblk->buf)) ++ grub_util_error ("%s", _("failed to write environment block to the PReP partition")); ++ } ++ grub_envblk_close (envblk); ++ } + grub_device_close (ins_dev); + if (update_nvram) + grub_install_register_ieee1275 (1, grub_util_get_os_disk (install_device), +-- +2.34.1 + diff --git a/0003-ieee1275-change-the-logic-of-ieee1275_get_devargs.patch b/0003-ieee1275-change-the-logic-of-ieee1275_get_devargs.patch new file mode 100644 index 0000000..ec5db6b --- /dev/null +++ b/0003-ieee1275-change-the-logic-of-ieee1275_get_devargs.patch @@ -0,0 +1,62 @@ +From 142069a7758372787d5dda714f3c71fae1a0b3bd Mon Sep 17 00:00:00 2001 +From: Diego Domingos +Date: Fri, 25 Feb 2022 12:49:51 -0500 +Subject: [PATCH 3/4] ieee1275: change the logic of ieee1275_get_devargs() + +Usually grub will parse the PFW arguments by searching for the first occurence of the character ':'. +However, we can have this char more than once on NQN. +This patch changes the logic to find the last occurence of this char so we can get the proper values +for NVMeoFC +--- + grub-core/kern/ieee1275/openfw.c | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/grub-core/kern/ieee1275/openfw.c b/grub-core/kern/ieee1275/openfw.c +index f819bd106..655a71310 100644 +--- a/grub-core/kern/ieee1275/openfw.c ++++ b/grub-core/kern/ieee1275/openfw.c +@@ -354,6 +354,13 @@ static char * + grub_ieee1275_get_devargs (const char *path) + { + char *colon = grub_strchr (path, ':'); ++ char *colon_check = colon; ++ ++ /* Find the last occurence of colon */ ++ while(colon_check){ ++ colon = colon_check; ++ colon_check = grub_strchr (colon+1, ':'); ++ } + + if (! colon) + return 0; +@@ -368,6 +375,18 @@ grub_ieee1275_get_devname (const char *path) + char *colon = grub_strchr (path, ':'); + int pathlen = grub_strlen (path); + struct grub_ieee1275_devalias curalias; ++ ++ /* Check some special cases */ ++ if(grub_strstr(path, "nvme-of")){ ++ char *namespace_split = grub_strstr(path,"/namespace@"); ++ if(namespace_split){ ++ colon = grub_strchr (namespace_split, ':'); ++ } else { ++ colon = NULL; ++ } ++ ++ } ++ + if (colon) + pathlen = (int)(colon - path); + +@@ -693,7 +712,7 @@ grub_ieee1275_get_boot_dev (void) + return NULL; + } + +- bootpath = (char *) grub_malloc ((grub_size_t) bootpath_size + 64); ++ bootpath = (char *) grub_malloc ((grub_size_t) bootpath_size + 64 + 256); + if (! bootpath) + { + grub_print_error (); +-- +2.35.3 + diff --git a/0003-ieee1275-request-memory-with-ibm-client-architecture.patch b/0003-ieee1275-request-memory-with-ibm-client-architecture.patch new file mode 100644 index 0000000..b97e7fe --- /dev/null +++ b/0003-ieee1275-request-memory-with-ibm-client-architecture.patch @@ -0,0 +1,263 @@ +From bbfcae1cd408c4922ddcefc0528bfe19da845c90 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 16 Apr 2021 11:48:46 +1000 +Subject: [PATCH 03/23] ieee1275: request memory with + ibm,client-architecture-support + +On PowerVM, the first time we boot a Linux partition, we may only get +256MB of real memory area, even if the partition has more memory. + +This isn't really enough. Fortunately, the Power Architecture Platform +Reference (PAPR) defines a method we can call to ask for more memory. +This is part of the broad and powerful ibm,client-architecture-support +(CAS) method. + +CAS can do an enormous amount of things on a PAPR platform: as well as +asking for memory, you can set the supported processor level, the interrupt +controller, hash vs radix mmu, and so on. We want to touch as little of +this as possible because we don't want to step on the toes of the future OS. + +If: + + - we are running under what we think is PowerVM (compatible property of / + begins with "IBM"), and + + - the full amount of RMA is less than 512MB (as determined by the reg + property of /memory) + +then call CAS as follows: (refer to the Linux on Power Architecture +Reference, LoPAR, which is public, at B.5.2.3): + + - Use the "any" PVR value and supply 2 option vectors. + + - Set option vector 1 (PowerPC Server Processor Architecture Level) + to "ignore". + + - Set option vector 2 with default or Linux-like options, including a + min-rma-size of 512MB. + +This will cause a CAS reboot and the partition will restart with 512MB +of RMA. Grub will notice the 512MB and not call CAS again. + +(A partition can be configured with only 256MB of memory, which would +mean this request couldn't be satisfied, but PFW refuses to load with +only 256MB of memory, so it's a bit moot. SLOF will run fine with 256MB, +but we will never call CAS under qemu/SLOF because /compatible won't +begin with "IBM".) + +One of the first things Linux does while still running under OpenFirmware +is to call CAS with a much fuller set of options (including asking for +512MB of memory). This includes a much more restrictive set of PVR values +and processor support levels, and this will induce another reboot. On this +reboot grub will again notice the higher RMA, and not call CAS. We will get +to Linux, Linux will call CAS but because the values are now set for Linux +this will not induce another CAS reboot and we will finally boot. + +On all subsequent boots, everything will be configured with 512MB of RMA +and all the settings Linux likes, so there will be no further CAS reboots. + +(phyp is super sticky with the RMA size - it persists even on cold boots. +So if you've ever booted Linux in a partition, you'll probably never have +grub call CAS. It'll only ever fire the first time a partition loads grub, +or if you deliberately lower the amount of memory your partition has below +512MB.) + +Signed-off-by: Daniel Axtens +--- + grub-core/kern/ieee1275/cmain.c | 3 + + grub-core/kern/ieee1275/init.c | 140 +++++++++++++++++++++++++++++++ + include/grub/ieee1275/ieee1275.h | 8 +- + 3 files changed, 150 insertions(+), 1 deletion(-) + +diff --git a/grub-core/kern/ieee1275/cmain.c b/grub-core/kern/ieee1275/cmain.c +index e9a184657..ee63c7b71 100644 +--- a/grub-core/kern/ieee1275/cmain.c ++++ b/grub-core/kern/ieee1275/cmain.c +@@ -127,6 +127,9 @@ grub_ieee1275_find_options (void) + break; + } + } ++ ++ if (grub_strncmp (tmp, "IBM,", 4) == 0) ++ grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY); + } + + if (is_smartfirmware) +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index d661a8da5..446201165 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -241,11 +241,151 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, + return 0; + } + ++/* How much memory does OF believe it has? (regardless of whether ++ it's accessible or not) */ ++static grub_err_t ++grub_ieee1275_total_mem (grub_uint64_t *total) ++{ ++ grub_ieee1275_phandle_t root; ++ grub_ieee1275_phandle_t memory; ++ grub_uint32_t reg[4]; ++ grub_ssize_t reg_size; ++ grub_uint32_t address_cells = 1; ++ grub_uint32_t size_cells = 1; ++ grub_uint64_t size; ++ ++ /* If we fail to get to the end, report 0. */ ++ *total = 0; ++ ++ /* Determine the format of each entry in `reg'. */ ++ grub_ieee1275_finddevice ("/", &root); ++ grub_ieee1275_get_integer_property (root, "#address-cells", &address_cells, ++ sizeof address_cells, 0); ++ grub_ieee1275_get_integer_property (root, "#size-cells", &size_cells, ++ sizeof size_cells, 0); ++ ++ if (size_cells > address_cells) ++ address_cells = size_cells; ++ ++ /* Load `/memory/reg'. */ ++ if (grub_ieee1275_finddevice ("/memory", &memory)) ++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, ++ "couldn't find /memory node"); ++ if (grub_ieee1275_get_integer_property (memory, "reg", reg, ++ sizeof reg, ®_size)) ++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, ++ "couldn't examine /memory/reg property"); ++ if (reg_size < 0 || (grub_size_t) reg_size > sizeof (reg)) ++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, ++ "/memory response buffer exceeded"); ++ ++ if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_BROKEN_ADDRESS_CELLS)) ++ { ++ address_cells = 1; ++ size_cells = 1; ++ } ++ ++ /* Decode only the size */ ++ size = reg[address_cells]; ++ if (size_cells == 2) ++ size = (size << 32) | reg[address_cells + 1]; ++ ++ *total = size; ++ ++ return grub_errno; ++} ++ ++/* Based on linux - arch/powerpc/kernel/prom_init.c */ ++struct option_vector2 { ++ grub_uint8_t byte1; ++ grub_uint16_t reserved; ++ grub_uint32_t real_base; ++ grub_uint32_t real_size; ++ grub_uint32_t virt_base; ++ grub_uint32_t virt_size; ++ grub_uint32_t load_base; ++ grub_uint32_t min_rma; ++ grub_uint32_t min_load; ++ grub_uint8_t min_rma_percent; ++ grub_uint8_t max_pft_size; ++} __attribute__((packed)); ++ ++struct pvr_entry { ++ grub_uint32_t mask; ++ grub_uint32_t entry; ++}; ++ ++struct cas_vector { ++ struct { ++ struct pvr_entry terminal; ++ } pvr_list; ++ grub_uint8_t num_vecs; ++ grub_uint8_t vec1_size; ++ grub_uint8_t vec1; ++ grub_uint8_t vec2_size; ++ struct option_vector2 vec2; ++} __attribute__((packed)); ++ ++/* Call ibm,client-architecture-support to try to get more RMA. ++ We ask for 512MB which should be enough to verify a distro kernel. ++ We ignore most errors: if we don't succeed we'll proceed with whatever ++ memory we have. */ ++static void ++grub_ieee1275_ibm_cas (void) ++{ ++ int rc; ++ grub_ieee1275_ihandle_t root; ++ struct cas_args { ++ struct grub_ieee1275_common_hdr common; ++ grub_ieee1275_cell_t method; ++ grub_ieee1275_ihandle_t ihandle; ++ grub_ieee1275_cell_t cas_addr; ++ grub_ieee1275_cell_t result; ++ } args; ++ struct cas_vector vector = { ++ .pvr_list = { { 0x00000000, 0xffffffff } }, /* any processor */ ++ .num_vecs = 2 - 1, ++ .vec1_size = 0, ++ .vec1 = 0x80, /* ignore */ ++ .vec2_size = 1 + sizeof(struct option_vector2) - 2, ++ .vec2 = { ++ 0, 0, -1, -1, -1, -1, -1, 512, -1, 0, 48 ++ }, ++ }; ++ ++ INIT_IEEE1275_COMMON (&args.common, "call-method", 3, 2); ++ args.method = (grub_ieee1275_cell_t)"ibm,client-architecture-support"; ++ rc = grub_ieee1275_open("/", &root); ++ if (rc) { ++ grub_error (GRUB_ERR_IO, "could not open root when trying to call CAS"); ++ return; ++ } ++ args.ihandle = root; ++ args.cas_addr = (grub_ieee1275_cell_t)&vector; ++ ++ grub_printf("Calling ibm,client-architecture-support..."); ++ IEEE1275_CALL_ENTRY_FN (&args); ++ grub_printf("done\n"); ++ ++ grub_ieee1275_close(root); ++} ++ + static void + grub_claim_heap (void) + { + grub_uint32_t total = 0; + ++ if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY)) ++ { ++ grub_uint64_t rma_size; ++ grub_err_t err; ++ ++ err = grub_ieee1275_total_mem (&rma_size); ++ /* if we have an error, don't call CAS, just hope for the best */ ++ if (!err && rma_size < (512 * 1024 * 1024)) ++ grub_ieee1275_ibm_cas(); ++ } ++ + grub_machine_mmap_iterate (heap_size, &total); + + total = total / 4; +diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h +index debb7086a..591f4f12c 100644 +--- a/include/grub/ieee1275/ieee1275.h ++++ b/include/grub/ieee1275/ieee1275.h +@@ -155,7 +155,13 @@ enum grub_ieee1275_flag + + GRUB_IEEE1275_FLAG_RAW_DEVNAMES, + +- GRUB_IEEE1275_FLAG_DISABLE_VIDEO_SUPPORT ++ GRUB_IEEE1275_FLAG_DISABLE_VIDEO_SUPPORT, ++ ++ /* On PFW, the first time we boot a Linux partition, we may only get 256MB ++ of real memory area, even if the partition has more memory. Set this flag ++ if we think we're running under PFW. Then, if this flag is set, and the ++ RMA is only 256MB in size, try asking for more with CAS. */ ++ GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY, + }; + + extern int EXPORT_FUNC(grub_ieee1275_test_flag) (enum grub_ieee1275_flag flag); +-- +2.31.1 + diff --git a/0004-Add-suport-for-signing-grub-with-an-appended-signatu.patch b/0004-Add-suport-for-signing-grub-with-an-appended-signatu.patch new file mode 100644 index 0000000..64ba773 --- /dev/null +++ b/0004-Add-suport-for-signing-grub-with-an-appended-signatu.patch @@ -0,0 +1,314 @@ +From cf6b16f113b1b5e6efce79b569be1de3e504de8f Mon Sep 17 00:00:00 2001 +From: Rashmica Gupta +Date: Thu, 11 Jun 2020 11:26:23 +1000 +Subject: [PATCH 04/23] Add suport for signing grub with an appended signature + +Add infrastructure to allow firmware to verify the integrity of grub +by use of a Linux-kernel-module-style appended signature. We initially +target powerpc-ieee1275, but the code should be extensible to other +platforms. + +Usually these signatures are appended to a file without modifying the +ELF file itself. (This is what the 'sign-file' tool does, for example.) +The verifier loads the signed file from the file system and looks at the +end of the file for the appended signature. However, on powerpc-ieee1275 +platforms, the bootloader is often stored directly in the PReP partition +as raw bytes without a file-system. This makes determining the location +of an appended signature more difficult. + +To address this, we add a new ELF note. + +The name field of shall be the string "Appended-Signature", zero-padded +to 4 byte alignment. The type field shall be 0x41536967 (the ASCII values +for the string "ASig"). It must be the final section in the ELF binary. + +The description shall contain the appended signature structure as defined +by the Linux kernel. The description will also be padded to be a multiple +of 4 bytes. The padding shall be added before the appended signature +structure (not at the end) so that the final bytes of a signed ELF file +are the appended signature magic. + +A subsequent patch documents how to create a grub core.img validly signed +under this scheme. + +Signed-off-by: Daniel Axtens +Signed-off-by: Rashmica Gupta + +--- + +You can experiment with this code with a patched version of SLOF +that verifies these signatures. You can find one at: + https://github.com/daxtens/SLOF + +I will be proposing this for inclusion in a future Power Architecture +Platform Reference (PAPR). +--- + include/grub/util/install.h | 8 ++++++-- + include/grub/util/mkimage.h | 4 ++-- + util/grub-install-common.c | 15 +++++++++++--- + util/grub-mkimage.c | 11 +++++++++++ + util/grub-mkimagexx.c | 39 ++++++++++++++++++++++++++++++++++++- + util/mkimage.c | 13 +++++++------ + 6 files changed, 76 insertions(+), 14 deletions(-) + +diff --git a/include/grub/util/install.h b/include/grub/util/install.h +index 9e83e1339..0b2e8a06d 100644 +--- a/include/grub/util/install.h ++++ b/include/grub/util/install.h +@@ -67,6 +67,9 @@ + N_("SBAT metadata"), 0 }, \ + { "disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, \ + N_("disable shim_lock verifier"), 0 }, \ ++ { "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,\ ++ "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), \ ++ 1}, \ + { "verbose", 'v', 0, 0, \ + N_("print verbose messages."), 1 } + +@@ -129,7 +132,8 @@ enum grub_install_options { + GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS, + GRUB_INSTALL_OPTIONS_DTB, + GRUB_INSTALL_OPTIONS_SBAT, +- GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK ++ GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, ++ GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE + }; + + extern char *grub_install_source_directory; +@@ -189,7 +193,7 @@ grub_install_generate_image (const char *dir, const char *prefix, + size_t npubkeys, + char *config_path, + const struct grub_install_image_target_desc *image_target, +- int note, ++ int note, size_t appsig_size, + grub_compression_t comp, const char *dtb_file, + const char *sbat_path, const int disable_shim_lock); + +diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h +index 3819a6744..6f1da89b9 100644 +--- a/include/grub/util/mkimage.h ++++ b/include/grub/util/mkimage.h +@@ -51,12 +51,12 @@ grub_mkimage_load_image64 (const char *kernel_path, + const struct grub_install_image_target_desc *image_target); + void + grub_mkimage_generate_elf32 (const struct grub_install_image_target_desc *image_target, +- int note, char **core_img, size_t *core_size, ++ int note, size_t appsig_size, char **core_img, size_t *core_size, + Elf32_Addr target_addr, + struct grub_mkimage_layout *layout); + void + grub_mkimage_generate_elf64 (const struct grub_install_image_target_desc *image_target, +- int note, char **core_img, size_t *core_size, ++ int note, size_t appsig_size, char **core_img, size_t *core_size, + Elf64_Addr target_addr, + struct grub_mkimage_layout *layout); + +diff --git a/util/grub-install-common.c b/util/grub-install-common.c +index c6c561292..954df20eb 100644 +--- a/util/grub-install-common.c ++++ b/util/grub-install-common.c +@@ -461,10 +461,12 @@ static size_t npubkeys; + static char *sbat; + static int disable_shim_lock; + static grub_compression_t compression; ++static size_t appsig_size; + + int + grub_install_parse (int key, char *arg) + { ++ const char *end; + switch (key) + { + case 'C': +@@ -562,6 +564,12 @@ grub_install_parse (int key, char *arg) + grub_util_error (_("Unrecognized compression `%s'"), arg); + case GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE: + return 1; ++ case GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE: ++ grub_errno = 0; ++ appsig_size = grub_strtol(arg, &end, 10); ++ if (grub_errno) ++ return 0; ++ return 1; + default: + return 0; + } +@@ -661,10 +669,11 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, + " --output '%s' " + " --dtb '%s' " + "--sbat '%s' " +- "--format '%s' --compression '%s' %s %s %s\n", ++ "--format '%s' --compression '%s' " ++ "--appended-signature-size %zu %s %s %s\n", + dir, prefix, + outname, dtb ? : "", sbat ? : "", mkimage_target, +- compnames[compression], note ? "--note" : "", ++ compnames[compression], appsig_size, note ? "--note" : "", + disable_shim_lock ? "--disable-shim-lock" : "", s); + free (s); + +@@ -675,7 +684,7 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, + grub_install_generate_image (dir, prefix, fp, outname, + modules.entries, memdisk_path, + pubkeys, npubkeys, config_path, tgt, +- note, compression, dtb, sbat, ++ note, appsig_size, compression, dtb, sbat, + disable_shim_lock); + while (dc--) + grub_install_pop_module (); +diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c +index c0d559937..d01eaeb84 100644 +--- a/util/grub-mkimage.c ++++ b/util/grub-mkimage.c +@@ -84,6 +84,7 @@ static struct argp_option options[] = { + {"sbat", 's', N_("FILE"), 0, N_("SBAT metadata"), 0}, + {"disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, N_("disable shim_lock verifier"), 0}, + {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, ++ {"appended-signature-size", 'S', N_("SIZE"), 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), 0}, + { 0, 0, 0, 0, 0, 0 } + }; + +@@ -128,6 +129,7 @@ struct arguments + char *sbat; + int note; + int disable_shim_lock; ++ size_t appsig_size; + const struct grub_install_image_target_desc *image_target; + grub_compression_t comp; + }; +@@ -138,6 +140,7 @@ argp_parser (int key, char *arg, struct argp_state *state) + /* Get the input argument from argp_parse, which we + know is a pointer to our arguments structure. */ + struct arguments *arguments = state->input; ++ const char* end; + + switch (key) + { +@@ -170,6 +173,13 @@ argp_parser (int key, char *arg, struct argp_state *state) + arguments->note = 1; + break; + ++ case 'S': ++ grub_errno = 0; ++ arguments->appsig_size = grub_strtol(arg, &end, 10); ++ if (grub_errno) ++ return 0; ++ break; ++ + case 'm': + if (arguments->memdisk) + free (arguments->memdisk); +@@ -324,6 +334,7 @@ main (int argc, char *argv[]) + arguments.memdisk, arguments.pubkeys, + arguments.npubkeys, arguments.config, + arguments.image_target, arguments.note, ++ arguments.appsig_size, + arguments.comp, arguments.dtb, + arguments.sbat, arguments.disable_shim_lock); + +diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c +index d78fa3e53..393119486 100644 +--- a/util/grub-mkimagexx.c ++++ b/util/grub-mkimagexx.c +@@ -84,6 +84,15 @@ struct grub_ieee1275_note + struct grub_ieee1275_note_desc descriptor; + }; + ++#define GRUB_APPENDED_SIGNATURE_NOTE_NAME "Appended-Signature" ++#define GRUB_APPENDED_SIGNATURE_NOTE_TYPE 0x41536967 /* "ASig" */ ++ ++struct grub_appended_signature_note ++{ ++ Elf32_Nhdr header; ++ char name[ALIGN_UP(sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME), 4)]; ++}; ++ + #define GRUB_XEN_NOTE_NAME "Xen" + + struct fixup_block_list +@@ -207,7 +216,7 @@ grub_arm_reloc_jump24 (grub_uint32_t *target, Elf32_Addr sym_addr) + + void + SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc *image_target, +- int note, char **core_img, size_t *core_size, ++ int note, size_t appsig_size, char **core_img, size_t *core_size, + Elf_Addr target_addr, + struct grub_mkimage_layout *layout) + { +@@ -221,6 +230,12 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc + int shnum = 4; + int string_size = sizeof (".text") + sizeof ("mods") + 1; + ++ if (appsig_size) ++ { ++ phnum++; ++ footer_size += ALIGN_UP(sizeof (struct grub_appended_signature_note) + appsig_size, 4); ++ } ++ + if (image_target->id != IMAGE_LOONGSON_ELF) + phnum += 2; + +@@ -484,6 +499,28 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc + phdr->p_offset = grub_host_to_target32 (header_size + program_size); + } + ++ if (appsig_size) { ++ int note_size = ALIGN_UP(sizeof (struct grub_appended_signature_note) + appsig_size, 4); ++ struct grub_appended_signature_note *note_ptr = (struct grub_appended_signature_note *) ++ (elf_img + program_size + header_size + (note ? sizeof (struct grub_ieee1275_note) : 0)); ++ ++ note_ptr->header.n_namesz = grub_host_to_target32 (sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME)); ++ /* needs to sit at the end, so we round this up and sign some zero padding */ ++ note_ptr->header.n_descsz = grub_host_to_target32 (ALIGN_UP(appsig_size, 4)); ++ note_ptr->header.n_type = grub_host_to_target32 (GRUB_APPENDED_SIGNATURE_NOTE_TYPE); ++ strcpy (note_ptr->name, GRUB_APPENDED_SIGNATURE_NOTE_NAME); ++ ++ phdr++; ++ phdr->p_type = grub_host_to_target32 (PT_NOTE); ++ phdr->p_flags = grub_host_to_target32 (PF_R); ++ phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof); ++ phdr->p_vaddr = 0; ++ phdr->p_paddr = 0; ++ phdr->p_filesz = grub_host_to_target32 (note_size); ++ phdr->p_memsz = 0; ++ phdr->p_offset = grub_host_to_target32 (header_size + program_size + (note ? sizeof (struct grub_ieee1275_note) : 0)); ++ } ++ + { + char *str_start = (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr) + + shnum * sizeof (*shdr)); +diff --git a/util/mkimage.c b/util/mkimage.c +index a26cf76f7..d2cb33883 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -869,8 +869,9 @@ grub_install_generate_image (const char *dir, const char *prefix, + char *memdisk_path, char **pubkey_paths, + size_t npubkeys, char *config_path, + const struct grub_install_image_target_desc *image_target, +- int note, grub_compression_t comp, const char *dtb_path, +- const char *sbat_path, int disable_shim_lock) ++ int note, size_t appsig_size, grub_compression_t comp, ++ const char *dtb_path, const char *sbat_path, ++ int disable_shim_lock) + { + char *kernel_img, *core_img; + size_t total_module_size, core_size; +@@ -1773,11 +1774,11 @@ grub_install_generate_image (const char *dir, const char *prefix, + else + target_addr = image_target->link_addr; + if (image_target->voidp_sizeof == 4) +- grub_mkimage_generate_elf32 (image_target, note, &core_img, &core_size, +- target_addr, &layout); ++ grub_mkimage_generate_elf32 (image_target, note, appsig_size, &core_img, ++ &core_size, target_addr, &layout); + else +- grub_mkimage_generate_elf64 (image_target, note, &core_img, &core_size, +- target_addr, &layout); ++ grub_mkimage_generate_elf64 (image_target, note, appsig_size, &core_img, ++ &core_size, target_addr, &layout); + } + break; + } +-- +2.31.1 + diff --git a/0004-Introduce-prep_load_env-command.patch b/0004-Introduce-prep_load_env-command.patch new file mode 100644 index 0000000..e117f0d --- /dev/null +++ b/0004-Introduce-prep_load_env-command.patch @@ -0,0 +1,272 @@ +From 3cf4fdf8d17423dea4e5913ab14fb6305f3c2571 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Fri, 18 Feb 2022 21:43:38 +0800 +Subject: [PATCH 4/5] Introduce prep_load_env command + +This command will accept grub disk device and perform load_env for +environment block located at end of PReP partition which belongs to that +input disk device. All variables read from that environment block are +exported to grub as environment variables. + +Please note there's no support for whitelist variables and also +--skip-sig option compared to ordinary load_env command. + +v2: +To avoid disrupting the boot process with errors, it's important to log +any errors that may occur and always return GRUB_ERR_NONE. + +v3: +Making the new module powerpc_ieee1275 specific. + +Signed-off-by: Michael Chang +--- + grub-core/Makefile.core.def | 5 + + grub-core/commands/prep_loadenv.c | 227 ++++++++++++++++++++++++++++++ + 2 files changed, 232 insertions(+) + create mode 100644 grub-core/commands/prep_loadenv.c + +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2624,3 +2624,9 @@ + common = lib/libtasn1_wrap/tests/Test_strings.c; + common = lib/libtasn1_wrap/wrap_tests.c; + }; ++ ++module = { ++ name = prep_loadenv; ++ common = commands/prep_loadenv.c; ++ enable = powerpc_ieee1275; ++}; +--- /dev/null ++++ b/grub-core/commands/prep_loadenv.c +@@ -0,0 +1,230 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static char * ++match_substr (regmatch_t *match, const char *str) ++{ ++ if (match->rm_so != -1) ++ { ++ char *substr; ++ regoff_t sz = match->rm_eo - match->rm_so; ++ ++ if (!sz) ++ return NULL; ++ substr = grub_malloc (1 + sz); ++ if (!substr) ++ { ++ grub_print_error (); ++ return NULL; ++ } ++ grub_memcpy (substr, str + match->rm_so, sz); ++ substr[sz] = '\0'; ++ return substr; ++ } ++ ++ return NULL; ++} ++ ++static int ++is_prep_partition (grub_device_t dev) ++{ ++ if (!dev->disk) ++ return 0; ++ if (!dev->disk->partition) ++ return 0; ++ if (grub_strcmp (dev->disk->partition->partmap->name, "msdos") == 0) ++ return (dev->disk->partition->msdostype == 0x41); ++ ++ if (grub_strcmp (dev->disk->partition->partmap->name, "gpt") == 0) ++ { ++ struct grub_gpt_partentry gptdata; ++ grub_partition_t p = dev->disk->partition; ++ int ret = 0; ++ dev->disk->partition = dev->disk->partition->parent; ++ ++ if (grub_disk_read (dev->disk, p->offset, p->index, ++ sizeof (gptdata), &gptdata) == 0) ++ { ++ const grub_gpt_part_guid_t template = { ++ grub_cpu_to_le32_compile_time (0x9e1a2d38), ++ grub_cpu_to_le16_compile_time (0xc612), ++ grub_cpu_to_le16_compile_time (0x4316), ++ { 0xaa, 0x26, 0x8b, 0x49, 0x52, 0x1e, 0x5a, 0x8b } ++ }; ++ ++ ret = grub_memcmp (&template, &gptdata.type, ++ sizeof (template)) == 0; ++ } ++ dev->disk->partition = p; ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ++part_hook (grub_disk_t disk, const grub_partition_t partition, void *data) ++{ ++ char **ret = data; ++ char *partition_name, *devname; ++ grub_device_t dev; ++ ++ partition_name = grub_partition_get_name (partition); ++ if (! partition_name) ++ return 2; ++ ++ devname = grub_xasprintf ("%s,%s", disk->name, partition_name); ++ grub_free (partition_name); ++ if (!devname) ++ return 2; ++ ++ dev = grub_device_open (devname); ++ if (!dev) ++ { ++ grub_free (devname); ++ return 2; ++ } ++ if (is_prep_partition (dev)) ++ { ++ *ret = devname; ++ return 1; ++ } ++ grub_free (devname); ++ grub_device_close (dev); ++ return 0; ++} ++ ++static int ++set_var (const char *name, const char *value, ++ void *hook_data __attribute__ ((unused))) ++{ ++ grub_env_set (name, value); ++ grub_env_export (name); ++ return 0; ++} ++ ++static grub_err_t ++prep_read_envblk (const char *devname) ++{ ++ char *buf = NULL; ++ grub_device_t dev = NULL; ++ grub_envblk_t envblk = NULL; ++ ++ dev = grub_device_open (devname); ++ if (!dev) ++ return grub_errno; ++ ++ if (!dev->disk || !dev->disk->partition) ++ { ++ grub_error (GRUB_ERR_BAD_DEVICE, "disk device required"); ++ goto fail; ++ } ++ ++ buf = grub_malloc (GRUB_ENVBLK_PREP_SIZE); ++ if (!buf) ++ goto fail; ++ ++ if (grub_disk_read (dev->disk, dev->disk->partition->len - (GRUB_ENVBLK_PREP_SIZE >> GRUB_DISK_SECTOR_BITS), 0, GRUB_ENVBLK_PREP_SIZE, buf)) ++ goto fail; ++ ++ envblk = grub_envblk_open (buf, GRUB_ENVBLK_PREP_SIZE); ++ if (!envblk) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid environment block"); ++ goto fail; ++ } ++ grub_envblk_iterate (envblk, NULL, set_var); ++ ++ fail: ++ if (envblk) ++ grub_envblk_close (envblk); ++ else ++ grub_free (buf); ++ if (dev) ++ grub_device_close (dev); ++ return grub_errno; ++} ++ ++static grub_err_t ++prep_partname (const char *devname, char **prep) ++{ ++ grub_device_t dev = NULL; ++ grub_err_t err; ++ int ret; ++ ++ dev = grub_device_open (devname); ++ if (!dev) ++ return grub_errno; ++ ++ ret = grub_partition_iterate (dev->disk, part_hook, prep); ++ if (ret == 1 && *prep) ++ { ++ err = GRUB_ERR_NONE; ++ goto out; ++ } ++ else if (ret == 0 && grub_errno == GRUB_ERR_NONE) ++ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "no prep partition"); ++ else ++ err = grub_errno; ++ ++ out: ++ grub_device_close (dev); ++ return err; ++} ++ ++static grub_err_t ++grub_cmd_prep_loadenv (grub_command_t cmd __attribute__ ((unused)), ++ int argc, ++ char **argv) ++{ ++ char *devname, *prep = NULL; ++ grub_err_t err; ++ ++ if (argc < 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); ++ ++ devname = grub_file_get_device_name(argv[0]); ++ if (!devname) ++ return grub_errno; ++ ++ err = prep_partname (devname, &prep); ++ if (prep == NULL || err != GRUB_ERR_NONE) ++ goto out; ++ ++ err = prep_read_envblk (prep); ++ ++ out: ++ grub_free (devname); ++ grub_free (prep); ++ ++ if (err) ++ grub_print_error (); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_command_t cmd_prep_load; ++ ++GRUB_MOD_INIT(prep_loadenv) ++{ ++ cmd_prep_load = ++ grub_register_command("prep_load_env", grub_cmd_prep_loadenv, ++ "DEVICE", ++ N_("Load variables from environment block file.")); ++} ++ ++GRUB_MOD_FINI(prep_loadenv) ++{ ++ grub_unregister_command (cmd_prep_load); ++} diff --git a/0004-Try-to-pick-better-locations-for-kernel-and-initrd.patch b/0004-Try-to-pick-better-locations-for-kernel-and-initrd.patch new file mode 100644 index 0000000..d3ed7fb --- /dev/null +++ b/0004-Try-to-pick-better-locations-for-kernel-and-initrd.patch @@ -0,0 +1,200 @@ +From 384763d7990f769839ca74d6756fbd85580873d4 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 11 Jul 2019 17:17:02 +0200 +Subject: [PATCH 04/11] Try to pick better locations for kernel and initrd + +- Don't limit allocations on 64-bit platforms to < 0x[37f]fffffff if + we're using the "large" code model ; use __UINTPTR_MAX__. +- Get the comparison right to check the address we've allocated. +- Fix the allocation for the command line as well. + +*But*, when we did this some systems started failing badly; coudln't +parse partition tables, etc. What's going on here is the disk controller +is silently failing DMAs to addresses above 4GB, so we're trying to parse +uninitialized (or HW zeroed) ram when looking for the partition table, +etc. + +So to limit this, we make grub_malloc() pick addresses below 4GB on +x86_64, but the direct EFI page allocation functions can get addresses +above that. + +Additionally, we now try to locate kernel+initrd+cmdline+etc below +0x7fffffff, and if they're too big to fit any memory window there, then +we try a higher address. + +Signed-off-by: Peter Jones +--- + grub-core/kern/efi/mm.c | 8 ++++---- + grub-core/loader/i386/efi/linux.c | 25 +++++++++++++++++-------- + include/grub/arm/efi/memory.h | 1 + + include/grub/arm64/efi/memory.h | 1 + + include/grub/i386/efi/memory.h | 1 + + include/grub/ia64/efi/memory.h | 1 + + include/grub/x86_64/efi/memory.h | 4 +++- + 7 files changed, 28 insertions(+), 13 deletions(-) + +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index 4ff75a8ce..67a691d89 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -122,7 +122,7 @@ grub_efi_allocate_pages_max (grub_efi_physical_address_t max, + grub_efi_boot_services_t *b; + grub_efi_physical_address_t address = max; + +- if (max > 0xffffffff) ++ if (max > GRUB_EFI_MAX_USABLE_ADDRESS) + return 0; + + b = grub_efi_system_table->boot_services; +@@ -480,7 +480,7 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, + { + if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY + #if 1 +- && desc->physical_start <= GRUB_EFI_MAX_USABLE_ADDRESS ++ && desc->physical_start <= GRUB_EFI_MAX_ALLOCATION_ADDRESS + #endif + && desc->physical_start + PAGES_TO_BYTES (desc->num_pages) > 0x100000 + && desc->num_pages != 0) +@@ -498,9 +498,9 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, + #if 1 + if (BYTES_TO_PAGES (filtered_desc->physical_start) + + filtered_desc->num_pages +- > BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_USABLE_ADDRESS)) ++ > BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_ALLOCATION_ADDRESS)) + filtered_desc->num_pages +- = (BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_USABLE_ADDRESS) ++ = (BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_ALLOCATION_ADDRESS) + - BYTES_TO_PAGES (filtered_desc->physical_start)); + #endif + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 0b3d20875..f3abbd025 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -102,8 +103,9 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + size += ALIGN_UP (grub_file_size (files[i]), 4); + } + +- initrd_mem = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(size)); +- ++ initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, BYTES_TO_PAGES(size)); ++ if (!initrd_mem) ++ initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, BYTES_TO_PAGES(size)); + if (!initrd_mem) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd")); +@@ -187,8 +189,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- params = grub_efi_allocate_pages_max (0x3fffffff, ++ params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, + BYTES_TO_PAGES(sizeof(*params))); ++ if (!params) ++ params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, ++ BYTES_TO_PAGES(sizeof(*params))); + if (! params) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); +@@ -258,8 +263,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + #endif + + grub_dprintf ("linux", "setting up cmdline\n"); +- linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff, +- BYTES_TO_PAGES(lh->cmdline_size + 1)); ++ linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS, ++ BYTES_TO_PAGES(lh->cmdline_size + 1)); ++ if (!linux_cmdline) ++ linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS, ++ BYTES_TO_PAGES(lh->cmdline_size + 1)); + if (!linux_cmdline) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline")); +@@ -285,11 +293,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + kernel_mem = grub_efi_allocate_pages_max(lh->pref_address, + BYTES_TO_PAGES(lh->init_size)); +- + if (!kernel_mem) +- kernel_mem = grub_efi_allocate_pages_max(0x3fffffff, ++ kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS, ++ BYTES_TO_PAGES(lh->init_size)); ++ if (!kernel_mem) ++ kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS, + BYTES_TO_PAGES(lh->init_size)); +- + if (!kernel_mem) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel")); +diff --git a/include/grub/arm/efi/memory.h b/include/grub/arm/efi/memory.h +index 2c64918e3..a4c2ec835 100644 +--- a/include/grub/arm/efi/memory.h ++++ b/include/grub/arm/efi/memory.h +@@ -2,5 +2,6 @@ + #include + + #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/include/grub/arm64/efi/memory.h b/include/grub/arm64/efi/memory.h +index c6cb32417..acb61dca4 100644 +--- a/include/grub/arm64/efi/memory.h ++++ b/include/grub/arm64/efi/memory.h +@@ -2,5 +2,6 @@ + #include + + #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffffffffULL ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/include/grub/i386/efi/memory.h b/include/grub/i386/efi/memory.h +index 2c64918e3..a4c2ec835 100644 +--- a/include/grub/i386/efi/memory.h ++++ b/include/grub/i386/efi/memory.h +@@ -2,5 +2,6 @@ + #include + + #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/include/grub/ia64/efi/memory.h b/include/grub/ia64/efi/memory.h +index 2c64918e3..a4c2ec835 100644 +--- a/include/grub/ia64/efi/memory.h ++++ b/include/grub/ia64/efi/memory.h +@@ -2,5 +2,6 @@ + #include + + #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/include/grub/x86_64/efi/memory.h b/include/grub/x86_64/efi/memory.h +index 46e9145a3..e81cfb322 100644 +--- a/include/grub/x86_64/efi/memory.h ++++ b/include/grub/x86_64/efi/memory.h +@@ -2,9 +2,11 @@ + #include + + #if defined (__code_model_large__) +-#define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff ++#define GRUB_EFI_MAX_USABLE_ADDRESS __UINTPTR_MAX__ ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS 0x7fffffff + #else + #define GRUB_EFI_MAX_USABLE_ADDRESS 0x7fffffff ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + #endif + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +-- +2.31.1 + diff --git a/0004-arm-arm64-loader-Better-memory-allocation-and-error-.patch b/0004-arm-arm64-loader-Better-memory-allocation-and-error-.patch new file mode 100644 index 0000000..df1727c --- /dev/null +++ b/0004-arm-arm64-loader-Better-memory-allocation-and-error-.patch @@ -0,0 +1,308 @@ +From 5d417346956bc3108183020a8a9f20ddda034b48 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 11 Jul 2019 14:38:57 +0200 +Subject: [PATCH 4/9] arm/arm64 loader: Better memory allocation and error + messages. + +On mustang, our memory map looks like: + +Type Physical start - end #Pages Size Attributes +reserved 0000004000000000-00000040001fffff 00000200 2MiB UC WC WT WB +conv-mem 0000004000200000-0000004393ffffff 00393e00 14654MiB UC WC WT WB +ldr-code 0000004394000000-00000043f7ffffff 00064000 1600MiB UC WC WT WB +BS-data 00000043f8000000-00000043f801ffff 00000020 128KiB UC WC WT WB +conv-mem 00000043f8020000-00000043fa15bfff 0000213c 34032KiB UC WC WT WB +ldr-code 00000043fa15c000-00000043fa2a1fff 00000146 1304KiB UC WC WT WB +ldr-data 00000043fa2a2000-00000043fa3e8fff 00000147 1308KiB UC WC WT WB +conv-mem 00000043fa3e9000-00000043fa3e9fff 00000001 4KiB UC WC WT WB +ldr-data 00000043fa3ea000-00000043fa3eafff 00000001 4KiB UC WC WT WB +ldr-code 00000043fa3eb000-00000043fa4affff 000000c5 788KiB UC WC WT WB +BS-code 00000043fa4b0000-00000043fa59ffff 000000f0 960KiB UC WC WT WB +RT-code 00000043fa5a0000-00000043fa5affff 00000010 64KiB RT UC WC WT WB +RT-data 00000043fa5b0000-00000043fa5bffff 00000010 64KiB RT UC WC WT WB +RT-code 00000043fa5c0000-00000043fa5cffff 00000010 64KiB RT UC WC WT WB +ldr-data 00000043fa5d0000-00000043fa5d0fff 00000001 4KiB UC WC WT WB +BS-code 00000043fa5d1000-00000043fa5ddfff 0000000d 52KiB UC WC WT WB +reserved 00000043fa5de000-00000043fa60ffff 00000032 200KiB UC WC WT WB +ACPI-rec 00000043fa610000-00000043fa6affff 000000a0 640KiB UC WC WT WB +ACPI-nvs 00000043fa6b0000-00000043fa6bffff 00000010 64KiB UC WC WT WB +ACPI-rec 00000043fa6c0000-00000043fa70ffff 00000050 320KiB UC WC WT WB +RT-code 00000043fa710000-00000043fa72ffff 00000020 128KiB RT UC WC WT WB +RT-data 00000043fa730000-00000043fa78ffff 00000060 384KiB RT UC WC WT WB +RT-code 00000043fa790000-00000043fa79ffff 00000010 64KiB RT UC WC WT WB +RT-data 00000043fa7a0000-00000043fa99ffff 00000200 2MiB RT UC WC WT WB +RT-code 00000043fa9a0000-00000043fa9affff 00000010 64KiB RT UC WC WT WB +RT-data 00000043fa9b0000-00000043fa9cffff 00000020 128KiB RT UC WC WT WB +BS-code 00000043fa9d0000-00000043fa9d9fff 0000000a 40KiB UC WC WT WB +reserved 00000043fa9da000-00000043fa9dbfff 00000002 8KiB UC WC WT WB +conv-mem 00000043fa9dc000-00000043fc29dfff 000018c2 25352KiB UC WC WT WB +BS-data 00000043fc29e000-00000043fc78afff 000004ed 5044KiB UC WC WT WB +conv-mem 00000043fc78b000-00000043fca01fff 00000277 2524KiB UC WC WT WB +BS-data 00000043fca02000-00000043fcea3fff 000004a2 4744KiB UC WC WT WB +conv-mem 00000043fcea4000-00000043fcea4fff 00000001 4KiB UC WC WT WB +BS-data 00000043fcea5000-00000043fd192fff 000002ee 3000KiB UC WC WT WB +conv-mem 00000043fd193000-00000043fd2b0fff 0000011e 1144KiB UC WC WT WB +BS-data 00000043fd2b1000-00000043ff80ffff 0000255f 38268KiB UC WC WT WB +BS-code 00000043ff810000-00000043ff99ffff 00000190 1600KiB UC WC WT WB +RT-code 00000043ff9a0000-00000043ff9affff 00000010 64KiB RT UC WC WT WB +conv-mem 00000043ff9b0000-00000043ff9bffff 00000010 64KiB UC WC WT WB +RT-data 00000043ff9c0000-00000043ff9effff 00000030 192KiB RT UC WC WT WB +conv-mem 00000043ff9f0000-00000043ffa05fff 00000016 88KiB UC WC WT WB +BS-data 00000043ffa06000-00000043ffffffff 000005fa 6120KiB UC WC WT WB +MMIO 0000000010510000-0000000010510fff 00000001 4KiB RT +MMIO 0000000010548000-0000000010549fff 00000002 8KiB RT +MMIO 0000000017000000-0000000017001fff 00000002 8KiB RT +MMIO 000000001c025000-000000001c025fff 00000001 4KiB RT + +This patch adds a requirement when we're trying to find the base of ram, that +the memory we choose is actually /allocatable/ conventional memory, not merely +write-combining. On this machine that means we wind up with an allocation +around 0x4392XXXXXX, which is a reasonable address. + +This also changes grub_efi_allocate_pages_real() so that if 0 is allocated, it +tries to allocate again starting with the same max address it did the first +time, rather than interposing GRUB_EFI_MAX_USABLE_ADDRESS there, so that any +per-platform constraints on its given address are maintained. + +Signed-off-by: Peter Jones + +squash! arm/arm64 loader: Better memory allocation and error messages. + +Use PRIxGRUB_* conversion specifier in printf's format string to +correspond properly to the data type of arguments. + +Signed-off-by: Michael Chang +--- + grub-core/kern/efi/mm.c | 33 ++++++++++--- + grub-core/loader/arm64/efi/linux.c | 78 ++++++++++++++++++++++-------- + 2 files changed, 84 insertions(+), 27 deletions(-) + +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index 15595a46e..324e1dca0 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -154,6 +154,7 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, + { + grub_efi_status_t status; + grub_efi_boot_services_t *b; ++ grub_efi_physical_address_t ret = address; + + /* Limit the memory access to less than 4GB for 32-bit platforms. */ + if (address > GRUB_EFI_MAX_USABLE_ADDRESS) +@@ -165,19 +166,22 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, + } + + b = grub_efi_system_table->boot_services; +- status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &address); ++ status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &ret); + if (status != GRUB_EFI_SUCCESS) + { ++ grub_dprintf ("efi", ++ "allocate_pages(%d, %d, 0x%0" PRIxGRUB_SIZE ", 0x%016" PRIxGRUB_UINT64_T ") = 0x%016" PRIxGRUB_SIZE "\n", ++ alloctype, memtype, pages, address, status); + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + return NULL; + } + +- if (address == 0) ++ if (ret == 0) + { + /* Uggh, the address 0 was allocated... This is too annoying, + so reallocate another one. */ +- address = GRUB_EFI_MAX_USABLE_ADDRESS; +- status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &address); ++ ret = address; ++ status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &ret); + grub_efi_free_pages (0, pages); + if (status != GRUB_EFI_SUCCESS) + { +@@ -186,9 +190,9 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, + } + } + +- grub_efi_store_alloc (address, pages); ++ grub_efi_store_alloc (ret, pages); + +- return (void *) ((grub_addr_t) address); ++ return (void *) ((grub_addr_t) ret); + } + + void * +@@ -699,8 +703,21 @@ grub_efi_get_ram_base(grub_addr_t *base_addr) + for (desc = memory_map, *base_addr = GRUB_EFI_MAX_USABLE_ADDRESS; + (grub_addr_t) desc < ((grub_addr_t) memory_map + memory_map_size); + desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) +- if (desc->attribute & GRUB_EFI_MEMORY_WB) +- *base_addr = grub_min (*base_addr, desc->physical_start); ++ { ++ if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY && ++ (desc->attribute & GRUB_EFI_MEMORY_WB)) ++ { ++ *base_addr = grub_min (*base_addr, desc->physical_start); ++ grub_dprintf ("efi", "setting base_addr=0x%016" PRIxGRUB_ADDR "\n", *base_addr); ++ } ++ else ++ { ++ grub_dprintf ("efi", "ignoring address 0x%016" PRIxGRUB_UINT64_T "\n", desc->physical_start); ++ } ++ } ++ ++ if (*base_addr == GRUB_EFI_MAX_USABLE_ADDRESS) ++ grub_dprintf ("efi", "base_addr 0x%016" PRIxGRUB_ADDR " is probably wrong.\n", *base_addr); + + grub_free(memory_map); + +diff --git a/grub-core/loader/arm64/efi/linux.c b/grub-core/loader/arm64/efi/linux.c +index 98c4f038b..4d084950a 100644 +--- a/grub-core/loader/arm64/efi/linux.c ++++ b/grub-core/loader/arm64/efi/linux.c +@@ -116,13 +116,15 @@ finalize_params_linux (void) + { + grub_efi_loaded_image_t *loaded_image = NULL; + int node, retval, len; +- ++ grub_err_t err = GRUB_ERR_NONE; + void *fdt; + + fdt = grub_fdt_load (GRUB_EFI_LINUX_FDT_EXTRA_SPACE); +- + if (!fdt) +- goto failure; ++ { ++ err = grub_error(GRUB_ERR_BAD_OS, "failed to load FDT"); ++ goto failure; ++ } + + node = grub_fdt_find_subnode (fdt, 0, "chosen"); + if (node < 0) +@@ -133,17 +135,26 @@ finalize_params_linux (void) + */ + retval = grub_fdt_set_prop32(fdt, 0, "#address-cells", 2); + if (retval) +- goto failure; ++ { ++ err = grub_error(retval, "Could not find #address-cells"); ++ goto failure; ++ } + + retval = grub_fdt_set_prop32(fdt, 0, "#size-cells", 2); + if (retval) +- goto failure; ++ { ++ err = grub_error(retval, "Could not find #size-cells"); ++ goto failure; ++ } + + node = grub_fdt_add_subnode (fdt, 0, "chosen"); + } + + if (node < 1) +- goto failure; ++ { ++ err = grub_error(grub_errno, "failed to load chosen fdt node."); ++ goto failure; ++ } + + /* Set initrd info */ + if (initrd_start && initrd_end > initrd_start) +@@ -154,15 +165,26 @@ finalize_params_linux (void) + retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-start", + initrd_start); + if (retval) +- goto failure; ++ { ++ err = grub_error(retval, "Failed to set linux,initrd-start property"); ++ goto failure; ++ } ++ + retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-end", + initrd_end); + if (retval) +- goto failure; ++ { ++ err = grub_error(retval, "Failed to set linux,initrd-end property"); ++ goto failure; ++ } + } + +- if (grub_fdt_install() != GRUB_ERR_NONE) +- goto failure; ++ retval = grub_fdt_install(); ++ if (retval != GRUB_ERR_NONE) ++ { ++ err = grub_error(retval, "Failed to install fdt"); ++ goto failure; ++ } + + grub_dprintf ("linux", "Installed/updated FDT configuration table @ %p\n", + fdt); +@@ -170,14 +192,20 @@ finalize_params_linux (void) + /* Convert command line to UCS-2 */ + loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); + if (!loaded_image) +- goto failure; ++ { ++ err = grub_error(grub_errno, "Failed to install fdt"); ++ goto failure; ++ } + + loaded_image->load_options_size = len = + (grub_strlen (linux_args) + 1) * sizeof (grub_efi_char16_t); + loaded_image->load_options = + grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size)); + if (!loaded_image->load_options) +- return grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters"); ++ { ++ err = grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters"); ++ goto failure; ++ } + + loaded_image->load_options_size = + 2 * grub_utf8_to_utf16 (loaded_image->load_options, len, +@@ -187,7 +215,7 @@ finalize_params_linux (void) + + failure: + grub_fdt_unload(); +- return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT"); ++ return err; + } + + static void +@@ -272,16 +300,28 @@ grub_linux_unload (void) + static void * + allocate_initrd_mem (int initrd_pages) + { +- grub_addr_t max_addr; ++ grub_addr_t max_addr = 0; ++ grub_err_t err; ++ void *ret; ++ ++ err = grub_efi_get_ram_base (&max_addr); ++ if (err != GRUB_ERR_NONE) ++ { ++ grub_error (err, "grub_efi_get_ram_base() failed"); ++ return NULL; ++ } + +- if (grub_efi_get_ram_base (&max_addr) != GRUB_ERR_NONE) +- return NULL; ++ grub_dprintf ("linux", "max_addr: 0x%016lx, INITRD_MAX_ADDRESS_OFFSET: 0x%016llx\n", ++ max_addr, INITRD_MAX_ADDRESS_OFFSET); + + max_addr += INITRD_MAX_ADDRESS_OFFSET - 1; ++ grub_dprintf ("linux", "calling grub_efi_allocate_pages_real (0x%016lx, 0x%08x, EFI_ALLOCATE_MAX_ADDRESS, EFI_LOADER_DATA)", max_addr, initrd_pages); + +- return grub_efi_allocate_pages_real (max_addr, initrd_pages, +- GRUB_EFI_ALLOCATE_MAX_ADDRESS, +- GRUB_EFI_LOADER_DATA); ++ ret = grub_efi_allocate_pages_real (max_addr, initrd_pages, ++ GRUB_EFI_ALLOCATE_MAX_ADDRESS, ++ GRUB_EFI_LOADER_DATA); ++ grub_dprintf ("linux", "got 0x%016llx\n", (unsigned long long)ret); ++ return ret; + } + + static grub_err_t +-- +2.26.2 + diff --git a/0004-cryptodisk-Improve-error-messaging-in-cryptomount-in.patch b/0004-cryptodisk-Improve-error-messaging-in-cryptomount-in.patch new file mode 100644 index 0000000..4d11875 --- /dev/null +++ b/0004-cryptodisk-Improve-error-messaging-in-cryptomount-in.patch @@ -0,0 +1,58 @@ +From f41488d0e361a34f4d3f8fb6c92729a2901a5c76 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:53 -0600 +Subject: [PATCH 04/14] cryptodisk: Improve error messaging in cryptomount + invocations + +Update such that "cryptomount -u UUID" will not print two error messages +when an invalid passphrase is given and the most relevant error message +will be displayed. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 21 +++++++++++++++++---- + 1 file changed, 17 insertions(+), 4 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 27491871a5..3a896c6634 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -1109,7 +1109,10 @@ grub_cryptodisk_scan_device (const char *name, + if (grub_errno == GRUB_ERR_BAD_MODULE) + grub_error_pop (); + +- if (grub_errno != GRUB_ERR_NONE) ++ if (search_uuid != NULL) ++ /* Push error onto stack to save for cryptomount. */ ++ grub_error_push (); ++ else + grub_print_error (); + + cleanup: +@@ -1146,9 +1149,19 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, NULL); + search_uuid = NULL; + +- if (!found_uuid) +- return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found"); +- return GRUB_ERR_NONE; ++ if (found_uuid) ++ return GRUB_ERR_NONE; ++ else if (grub_errno == GRUB_ERR_NONE) ++ { ++ /* ++ * Try to pop the next error on the stack. If there is not one, then ++ * no device matched the given UUID. ++ */ ++ grub_error_pop (); ++ if (grub_errno == GRUB_ERR_NONE) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found"); ++ } ++ return grub_errno; + } + else if (state[1].set || (argc == 0 && state[2].set)) + { +-- +2.34.1 + diff --git a/0004-efinet-UEFI-IPv6-PXE-support.patch b/0004-efinet-UEFI-IPv6-PXE-support.patch new file mode 100644 index 0000000..dcd6199 --- /dev/null +++ b/0004-efinet-UEFI-IPv6-PXE-support.patch @@ -0,0 +1,127 @@ +From ca482c7c1efe5faf792bf0912a116ea8e0642e24 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Wed, 15 Apr 2015 14:48:30 +0800 +Subject: [PATCH 4/8] efinet: UEFI IPv6 PXE support + +When grub2 image is booted from UEFI IPv6 PXE, the DHCPv6 Reply packet is +cached in firmware buffer which can be obtained by PXE Base Code protocol. The +network interface can be setup through the parameters in that obtained packet. + +Signed-off-by: Michael Chang +Signed-off-by: Ken Lin +--- + grub-core/net/drivers/efi/efinet.c | 24 +++++++++++++---- + include/grub/efi/api.h | 55 +++++++++++++++++++++++++++++++++++++- + 2 files changed, 73 insertions(+), 6 deletions(-) + +diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c +index 5388f95..fc90415 100644 +--- a/grub-core/net/drivers/efi/efinet.c ++++ b/grub-core/net/drivers/efi/efinet.c +@@ -378,11 +378,25 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + if (! pxe) + continue; + pxe_mode = pxe->mode; +- grub_net_configure_by_dhcp_ack (card->name, card, 0, +- (struct grub_net_bootp_packet *) +- &pxe_mode->dhcp_ack, +- sizeof (pxe_mode->dhcp_ack), +- 1, device, path); ++ ++ if (pxe_mode->using_ipv6) ++ { ++ grub_net_configure_by_dhcpv6_reply (card->name, card, 0, ++ (struct grub_net_dhcp6_packet *) ++ &pxe_mode->dhcp_ack, ++ sizeof (pxe_mode->dhcp_ack), ++ 1, device, path); ++ if (grub_errno) ++ grub_print_error (); ++ } ++ else ++ { ++ grub_net_configure_by_dhcp_ack (card->name, card, 0, ++ (struct grub_net_bootp_packet *) ++ &pxe_mode->dhcp_ack, ++ sizeof (pxe_mode->dhcp_ack), ++ 1, device, path); ++ } + return; + } + } +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index c7c9f0e..92f9b5a 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -1452,14 +1452,67 @@ typedef struct grub_efi_simple_text_output_interface grub_efi_simple_text_output + + typedef grub_uint8_t grub_efi_pxe_packet_t[1472]; + ++typedef struct { ++ grub_uint8_t addr[4]; ++} grub_efi_pxe_ipv4_address_t; ++ ++typedef struct { ++ grub_uint8_t addr[16]; ++} grub_efi_pxe_ipv6_address_t; ++ ++typedef struct { ++ grub_uint8_t addr[32]; ++} grub_efi_pxe_mac_address_t; ++ ++typedef union { ++ grub_uint32_t addr[4]; ++ grub_efi_pxe_ipv4_address_t v4; ++ grub_efi_pxe_ipv6_address_t v6; ++} grub_efi_pxe_ip_address_t; ++ ++#define GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT 8 ++typedef struct { ++ grub_uint8_t filters; ++ grub_uint8_t ip_cnt; ++ grub_uint16_t reserved; ++ grub_efi_pxe_ip_address_t ip_list[GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT]; ++} grub_efi_pxe_ip_filter_t; ++ ++typedef struct { ++ grub_efi_pxe_ip_address_t ip_addr; ++ grub_efi_pxe_mac_address_t mac_addr; ++} grub_efi_pxe_arp_entry_t; ++ ++typedef struct { ++ grub_efi_pxe_ip_address_t ip_addr; ++ grub_efi_pxe_ip_address_t subnet_mask; ++ grub_efi_pxe_ip_address_t gw_addr; ++} grub_efi_pxe_route_entry_t; ++ ++ ++#define GRUB_EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES 8 ++#define GRUB_EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES 8 ++ + typedef struct grub_efi_pxe_mode + { +- grub_uint8_t unused[52]; ++ grub_uint8_t started; ++ grub_uint8_t ipv6_available; ++ grub_uint8_t ipv6_supported; ++ grub_uint8_t using_ipv6; ++ grub_uint8_t unused[16]; ++ grub_efi_pxe_ip_address_t station_ip; ++ grub_efi_pxe_ip_address_t subnet_mask; + grub_efi_pxe_packet_t dhcp_discover; + grub_efi_pxe_packet_t dhcp_ack; + grub_efi_pxe_packet_t proxy_offer; + grub_efi_pxe_packet_t pxe_discover; + grub_efi_pxe_packet_t pxe_reply; ++ grub_efi_pxe_packet_t pxe_bis_reply; ++ grub_efi_pxe_ip_filter_t ip_filter; ++ grub_uint32_t arp_cache_entries; ++ grub_efi_pxe_arp_entry_t arp_cache[GRUB_EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES]; ++ grub_uint32_t route_table_entries; ++ grub_efi_pxe_route_entry_t route_table[GRUB_EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES]; + } grub_efi_pxe_mode_t; + + typedef struct grub_efi_pxe +-- +2.6.6 + diff --git a/0004-font-Remove-grub_font_dup_glyph.patch b/0004-font-Remove-grub_font_dup_glyph.patch new file mode 100644 index 0000000..3707617 --- /dev/null +++ b/0004-font-Remove-grub_font_dup_glyph.patch @@ -0,0 +1,42 @@ +From 9c99a0d55bf69f25ad41668867f719bbb1828457 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Fri, 5 Aug 2022 02:13:29 +0800 +Subject: [PATCH 04/12] font: Remove grub_font_dup_glyph() + +Remove grub_font_dup_glyph() since nobody is using it since 2013, and +I'm too lazy to fix the integer overflow problem in it. + +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +--- + grub-core/font/font.c | 14 -------------- + 1 file changed, 14 deletions(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index 1fa181d4c..a115a63b0 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -1055,20 +1055,6 @@ grub_font_get_glyph_with_fallback (grub_font_t font, grub_uint32_t code) + return best_glyph; + } + +-#if 0 +-static struct grub_font_glyph * +-grub_font_dup_glyph (struct grub_font_glyph *glyph) +-{ +- static struct grub_font_glyph *ret; +- ret = grub_malloc (sizeof (*ret) + (glyph->width * glyph->height + 7) / 8); +- if (!ret) +- return NULL; +- grub_memcpy (ret, glyph, sizeof (*ret) +- + (glyph->width * glyph->height + 7) / 8); +- return ret; +-} +-#endif +- + /* FIXME: suboptimal. */ + static void + grub_font_blit_glyph (struct grub_font_glyph *target, +-- +2.35.3 + diff --git a/0004-fs-ntfs-Fix-an-OOB-read-when-parsing-bitmaps-for-ind.patch b/0004-fs-ntfs-Fix-an-OOB-read-when-parsing-bitmaps-for-ind.patch new file mode 100644 index 0000000..8fed38f --- /dev/null +++ b/0004-fs-ntfs-Fix-an-OOB-read-when-parsing-bitmaps-for-ind.patch @@ -0,0 +1,51 @@ +From 7a5a116739fa6d8a625da7d6b9272c9a2462f967 Mon Sep 17 00:00:00 2001 +From: Maxim Suhanov +Date: Mon, 28 Aug 2023 16:33:44 +0300 +Subject: [PATCH 4/6] fs/ntfs: Fix an OOB read when parsing bitmaps for index + attributes + +This fix introduces checks to ensure that bitmaps for directory indices +are never read beyond their actual sizes. + +The lack of this check is a minor issue, likely not exploitable in any way. + +Reported-by: Maxim Suhanov +Signed-off-by: Maxim Suhanov +Reviewed-by: Daniel Kiper +--- + grub-core/fs/ntfs.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index 2d78b96e1..bb70c89fb 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -843,6 +843,25 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + + if (is_resident) + { ++ if (bitmap_len > (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "resident bitmap too large"); ++ goto done; ++ } ++ ++ if (cur_pos >= at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "resident bitmap out of range"); ++ goto done; ++ } ++ ++ if (u16at (cur_pos, 0x14) + u32at (cur_pos, 0x10) > ++ (grub_addr_t) at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR) - (grub_addr_t) cur_pos) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "resident bitmap out of range"); ++ goto done; ++ } ++ + grub_memcpy (bmp, cur_pos + u16at (cur_pos, 0x14), + bitmap_len); + } +-- +2.42.0 + diff --git a/0004-loader-efi-chainloader-Use-grub_loader_set_ex.patch b/0004-loader-efi-chainloader-Use-grub_loader_set_ex.patch new file mode 100644 index 0000000..7e1bc98 --- /dev/null +++ b/0004-loader-efi-chainloader-Use-grub_loader_set_ex.patch @@ -0,0 +1,83 @@ +From e0cc6a601865a72cfe316f2cbbaaefcdd2ad8c69 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Tue, 5 Apr 2022 11:48:58 +0100 +Subject: [PATCH 04/32] loader/efi/chainloader: Use grub_loader_set_ex() + +This ports the EFI chainloader to use grub_loader_set_ex() in order to fix +a use-after-free bug that occurs when grub_cmd_chainloader() is executed +more than once before a boot attempt is performed. + +Fixes: CVE-2022-28736 + +Signed-off-by: Chris Coulson +Reviewed-by: Daniel Kiper +--- + grub-core/loader/efi/chainloader.c | 15 +++++++-------- + 1 file changed, 7 insertions(+), 8 deletions(-) + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index 1ec09a166c..b3e1e89302 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -54,7 +54,6 @@ GRUB_MOD_LICENSE ("GPLv3+"); + static grub_dl_t my_mod; + + static grub_ssize_t fsize; +-static grub_efi_handle_t image_handle; + static grub_ssize_t cmdline_len; + static grub_efi_handle_t dev_handle; + +@@ -64,8 +63,9 @@ static grub_efi_status_t (*entry_point) (grub_efi_handle_t image_handle, grub_e + #endif + + static grub_err_t +-grub_chainloader_unload (void) ++grub_chainloader_unload (void *context) + { ++ grub_efi_handle_t image_handle = (grub_efi_handle_t) context; + grub_efi_loaded_image_t *loaded_image; + grub_efi_boot_services_t *b; + +@@ -83,8 +83,9 @@ grub_chainloader_unload (void) + } + + static grub_err_t +-grub_chainloader_boot (void) ++grub_chainloader_boot (void *context) + { ++ grub_efi_handle_t image_handle = (grub_efi_handle_t) context; + grub_efi_boot_services_t *b; + grub_efi_status_t status; + grub_efi_uintn_t exit_data_size; +@@ -644,6 +645,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_efi_physical_address_t address = 0; + grub_efi_uintn_t pages = 0; + grub_efi_char16_t *cmdline = NULL; ++ grub_efi_handle_t image_handle = NULL; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); +@@ -856,7 +858,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + efi_call_2 (b->free_pages, address, pages); + grub_free (file_path); + +- grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0); ++ grub_loader_set_ex (grub_chainloader_boot, grub_chainloader_unload, image_handle, 0); + return 0; + + fail: +@@ -874,10 +876,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + efi_call_2 (b->free_pages, address, pages); + + if (image_handle != NULL) +- { +- efi_call_1 (b->unload_image, image_handle); +- image_handle = NULL; +- } ++ efi_call_1 (b->unload_image, image_handle); + + grub_dl_unref (my_mod); + +-- +2.34.1 + diff --git a/0004-ofpath-controller-name-update.patch b/0004-ofpath-controller-name-update.patch new file mode 100644 index 0000000..bc27341 --- /dev/null +++ b/0004-ofpath-controller-name-update.patch @@ -0,0 +1,28 @@ +From 08a4d58d4ed6b6262b1f2ed44b7a14254ec76407 Mon Sep 17 00:00:00 2001 +From: mamatha +Date: Sat, 24 Sep 2022 11:22:39 +0530 +Subject: [PATCH 4/4] ofpath controller name update + +patch to update ofpath controller name + +Signed-off-by: mamatha +--- + grub-core/osdep/linux/ofpath.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c +index 10f2c1117..3614f5957 100644 +--- a/grub-core/osdep/linux/ofpath.c ++++ b/grub-core/osdep/linux/ofpath.c +@@ -483,6 +483,8 @@ of_path_get_nvmeof_adapter_info(char* sysfs_path, + buf3=strchr(buf2,'-')+1; + buf3=strchr(buf3,'-')+1; + nvmeof_info->target_wwpn = buf3; ++ buf3=strchr(buf3,'x')+1; ++ nvmeof_info->target_wwpn = buf3; + buf3 = strchr(nvmeof_info->target_wwpn,','); + *buf3 = '\0'; + +-- +2.35.3 + diff --git a/0005-cryptodisk-Improve-cryptomount-u-error-message.patch b/0005-cryptodisk-Improve-cryptomount-u-error-message.patch new file mode 100644 index 0000000..8716f9c --- /dev/null +++ b/0005-cryptodisk-Improve-cryptomount-u-error-message.patch @@ -0,0 +1,31 @@ +From 9ef619a7c1d38988f6d91496ea5c59062dcf6013 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:54 -0600 +Subject: [PATCH 05/14] cryptodisk: Improve cryptomount -u error message + +When a cryptmount is specified with a UUID, but no cryptodisk backends find +a disk with that UUID, return a more detailed message giving telling the +user that they might not have a needed cryptobackend module loaded. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 3a896c6634..5a9780b14c 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -1159,7 +1159,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + */ + grub_error_pop (); + if (grub_errno == GRUB_ERR_NONE) +- return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found"); ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found, perhaps a needed disk or cryptodisk module is not loaded"); + } + return grub_errno; + } +-- +2.34.1 + diff --git a/0005-docs-grub-Document-signing-grub-under-UEFI.patch b/0005-docs-grub-Document-signing-grub-under-UEFI.patch new file mode 100644 index 0000000..d10dc91 --- /dev/null +++ b/0005-docs-grub-Document-signing-grub-under-UEFI.patch @@ -0,0 +1,64 @@ +From f7b9580133cf346d77f345d175fa5cb8a591be16 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Sat, 15 Aug 2020 02:00:57 +1000 +Subject: [PATCH 05/23] docs/grub: Document signing grub under UEFI + +Before adding information about how grub is signed with an appended +signature scheme, it's worth adding some information about how it +can currently be signed for UEFI. + +Signed-off-by: Daniel Axtens +--- + docs/grub.texi | 22 +++++++++++++++++++++- + 1 file changed, 21 insertions(+), 1 deletion(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index e48018c5f..b1d808d93 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -5814,6 +5814,7 @@ environment variables and commands are listed in the same order. + * Secure Boot Advanced Targeting:: Embedded information for generation number based revocation + * Measured Boot:: Measuring boot components + * Lockdown:: Lockdown when booting on a secure setup ++* Signing GRUB itself:: Ensuring the integrity of the GRUB core image + @end menu + + @node Authentication and authorisation +@@ -5892,7 +5893,7 @@ commands. + + GRUB's @file{core.img} can optionally provide enforcement that all files + subsequently read from disk are covered by a valid digital signature. +-This document does @strong{not} cover how to ensure that your ++This section does @strong{not} cover how to ensure that your + platform's firmware (e.g., Coreboot) validates @file{core.img}. + + If environment variable @code{check_signatures} +@@ -6054,6 +6055,25 @@ be restricted and some operations/commands cannot be executed. + The @samp{lockdown} variable is set to @samp{y} when the GRUB is locked down. + Otherwise it does not exit. + ++@node Signing GRUB itself ++@section Signing GRUB itself ++ ++To ensure a complete secure-boot chain, there must be a way for the code that ++loads GRUB to verify the integrity of the core image. ++ ++This is ultimately platform-specific and individual platforms can define their ++own mechanisms. However, there are general-purpose mechanisms that can be used ++with GRUB. ++ ++@section Signing GRUB for UEFI secure boot ++ ++On UEFI platforms, @file{core.img} is a PE binary. Therefore, it can be signed ++with a tool such as @command{pesign} or @command{sbsign}. Refer to the ++suggestions in @pxref{UEFI secure boot and shim} to ensure that the final ++image works under UEFI secure boot and can maintain the secure-boot chain. It ++will also be necessary to enrol the public key used into a relevant firmware ++key database. ++ + @node Platform limitations + @chapter Platform limitations + +-- +2.31.1 + diff --git a/0005-export-environment-at-start-up.patch b/0005-export-environment-at-start-up.patch new file mode 100644 index 0000000..1d4055d --- /dev/null +++ b/0005-export-environment-at-start-up.patch @@ -0,0 +1,165 @@ +From 496b6b20cbce3fc27228d1d8290089fb7107b8de Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Fri, 18 Feb 2022 21:51:16 +0800 +Subject: [PATCH 5/5] export environment at start up + +If the prep_loadenv module is built into the core image, it will read +the environment block automatically during start up and export all +variables. The will ease integration with those without early scripts to +running the command. + +Signed-off-by: Michael Chang +--- + grub-core/Makefile.core.def | 2 + + grub-core/commands/prep_loadenv.c | 77 +++++++++++++++++++++++++++++++ + grub-core/kern/env.c | 2 + + grub-core/kern/main.c | 3 ++ + include/grub/env.h | 1 + + 5 files changed, 85 insertions(+) + +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2628,5 +2628,7 @@ + module = { + name = prep_loadenv; + common = commands/prep_loadenv.c; ++ cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)'; ++ cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB)'; + enable = powerpc_ieee1275; + }; +--- a/grub-core/commands/prep_loadenv.c ++++ b/grub-core/commands/prep_loadenv.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -185,6 +186,65 @@ + } + + static grub_err_t ++boot_disk_prep_partname (char **name) ++{ ++ regex_t regex; ++ int ret; ++ grub_size_t s; ++ char *comperr; ++ const char *cmdpath; ++ regmatch_t *matches = NULL; ++ grub_err_t err = GRUB_ERR_NONE; ++ ++ *name = NULL; ++ ++ cmdpath = grub_env_get ("cmdpath"); ++ if (!cmdpath) ++ return GRUB_ERR_NONE; ++ ++ ret = regcomp (®ex, "\\(([^,]+)(,?.*)?\\)(.*)", REG_EXTENDED); ++ if (ret) ++ goto fail; ++ ++ matches = grub_calloc (regex.re_nsub + 1, sizeof (*matches)); ++ if (! matches) ++ goto fail; ++ ++ ret = regexec (®ex, cmdpath, regex.re_nsub + 1, matches, 0); ++ if (!ret) ++ { ++ char *devname = devname = match_substr (matches + 1, cmdpath); ++ if (!devname) ++ { ++ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "%s contains no disk name", cmdpath); ++ goto out; ++ } ++ ++ err = prep_partname (devname, name); ++ out: ++ grub_free (devname); ++ regfree (®ex); ++ grub_free (matches); ++ return err; ++ } ++ ++ fail: ++ grub_free (matches); ++ s = regerror (ret, ®ex, 0, 0); ++ comperr = grub_malloc (s); ++ if (!comperr) ++ { ++ regfree (®ex); ++ return grub_errno; ++ } ++ regerror (ret, ®ex, comperr, s); ++ err = grub_error (GRUB_ERR_TEST_FAILURE, "%s", comperr); ++ regfree (®ex); ++ grub_free (comperr); ++ return err; ++} ++ ++static grub_err_t + grub_cmd_prep_loadenv (grub_command_t cmd __attribute__ ((unused)), + int argc, + char **argv) +@@ -214,10 +274,27 @@ + return GRUB_ERR_NONE; + } + ++static void ++early_prep_loadenv (void) ++{ ++ grub_err_t err; ++ char *prep; ++ ++ err = boot_disk_prep_partname (&prep); ++ if (err == GRUB_ERR_NONE && prep) ++ err = prep_read_envblk (prep); ++ if (err == GRUB_ERR_BAD_FILE_TYPE || err == GRUB_ERR_FILE_NOT_FOUND) ++ grub_error_pop (); ++ if (err != GRUB_ERR_NONE) ++ grub_print_error (); ++ grub_free (prep); ++} ++ + static grub_command_t cmd_prep_load; + + GRUB_MOD_INIT(prep_loadenv) + { ++ early_env_hook = early_prep_loadenv; + cmd_prep_load = + grub_register_command("prep_load_env", grub_cmd_prep_loadenv, + "DEVICE", +--- a/grub-core/kern/env.c ++++ b/grub-core/kern/env.c +@@ -28,6 +28,8 @@ + /* The current context. */ + struct grub_env_context *grub_current_context = &initial_context; + ++void (*early_env_hook) (void) = NULL; ++ + /* Return the hash representation of the string S. */ + static unsigned int + grub_env_hashval (const char *s) +--- a/grub-core/kern/main.c ++++ b/grub-core/kern/main.c +@@ -310,6 +310,9 @@ + + grub_boot_time ("Before execution of embedded config."); + ++ if (early_env_hook != NULL) ++ early_env_hook (); ++ + if (load_config) + grub_parser_execute (load_config); + +--- a/include/grub/env.h ++++ b/include/grub/env.h +@@ -68,5 +68,6 @@ + grub_err_t + grub_env_extractor_close (int source); + ++extern void (*EXPORT_VAR (early_env_hook)) (void); + + #endif /* ! GRUB_ENV_HEADER */ diff --git a/0005-font-Fix-integer-overflow-in-ensure_comb_space.patch b/0005-font-Fix-integer-overflow-in-ensure_comb_space.patch new file mode 100644 index 0000000..f2d28d6 --- /dev/null +++ b/0005-font-Fix-integer-overflow-in-ensure_comb_space.patch @@ -0,0 +1,48 @@ +From 2ec7e27b2cac3746f2e658042fd56fe75fee28f2 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Fri, 5 Aug 2022 02:27:05 +0800 +Subject: [PATCH 05/12] font: Fix integer overflow in ensure_comb_space() + +In fact it can't overflow at all because glyph_id->ncomb is only 8-bit +wide. But let's keep safe if somebody changes the width of glyph_id->ncomb +in the future. This patch also fixes the inconsistency between +render_max_comb_glyphs and render_combining_glyphs when grub_malloc() +returns NULL. + +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +--- + grub-core/font/font.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index a115a63b0..d0e634040 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -1468,14 +1468,18 @@ ensure_comb_space (const struct grub_unicode_glyph *glyph_id) + if (glyph_id->ncomb <= render_max_comb_glyphs) + return; + +- render_max_comb_glyphs = 2 * glyph_id->ncomb; +- if (render_max_comb_glyphs < 8) ++ if (grub_mul (glyph_id->ncomb, 2, &render_max_comb_glyphs)) ++ render_max_comb_glyphs = 0; ++ if (render_max_comb_glyphs > 0 && render_max_comb_glyphs < 8) + render_max_comb_glyphs = 8; + grub_free (render_combining_glyphs); +- render_combining_glyphs = grub_malloc (render_max_comb_glyphs +- * sizeof (render_combining_glyphs[0])); ++ render_combining_glyphs = (render_max_comb_glyphs > 0) ? ++ grub_calloc (render_max_comb_glyphs, sizeof (render_combining_glyphs[0])) : NULL; + if (!render_combining_glyphs) +- grub_errno = 0; ++ { ++ render_max_comb_glyphs = 0; ++ grub_errno = GRUB_ERR_NONE; ++ } + } + + int +-- +2.35.3 + diff --git a/0005-fs-ntfs-Fix-an-OOB-read-when-parsing-a-volume-label.patch b/0005-fs-ntfs-Fix-an-OOB-read-when-parsing-a-volume-label.patch new file mode 100644 index 0000000..546ca9b --- /dev/null +++ b/0005-fs-ntfs-Fix-an-OOB-read-when-parsing-a-volume-label.patch @@ -0,0 +1,61 @@ +From 1fe82c41e070385e273d7bb1cfb482627a3c28e8 Mon Sep 17 00:00:00 2001 +From: Maxim Suhanov +Date: Mon, 28 Aug 2023 16:38:19 +0300 +Subject: [PATCH 5/6] fs/ntfs: Fix an OOB read when parsing a volume label + +This fix introduces checks to ensure that an NTFS volume label is always +read from the corresponding file record segment. + +The current NTFS code allows the volume label string to be read from an +arbitrary, attacker-chosen memory location. However, the bytes read are +always treated as UTF-16LE. So, the final string displayed is mostly +unreadable and it can't be easily converted back to raw bytes. + +The lack of this check is a minor issue, likely not causing a significant +data leak. + +Reported-by: Maxim Suhanov +Signed-off-by: Maxim Suhanov +Reviewed-by: Daniel Kiper +--- + grub-core/fs/ntfs.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index bb70c89fb..ff5e3740f 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -1213,13 +1213,29 @@ grub_ntfs_label (grub_device_t device, char **label) + + init_attr (&mft->attr, mft); + pa = find_attr (&mft->attr, GRUB_NTFS_AT_VOLUME_NAME); ++ ++ if (pa >= mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR)) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "can\'t parse volume label"); ++ goto fail; ++ } ++ ++ if (mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR) - pa < 0x16) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "can\'t parse volume label"); ++ goto fail; ++ } ++ + if ((pa) && (pa[8] == 0) && (u32at (pa, 0x10))) + { + int len; + + len = u32at (pa, 0x10) / 2; + pa += u16at (pa, 0x14); +- *label = get_utf8 (pa, len); ++ if (mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR) - pa >= 2 * len) ++ *label = get_utf8 (pa, len); ++ else ++ grub_error (GRUB_ERR_BAD_FS, "can\'t parse volume label"); + } + + fail: +-- +2.42.0 + diff --git a/0005-grub.texi-Add-net_bootp6-doument.patch b/0005-grub.texi-Add-net_bootp6-doument.patch new file mode 100644 index 0000000..85ff716 --- /dev/null +++ b/0005-grub.texi-Add-net_bootp6-doument.patch @@ -0,0 +1,50 @@ +From 2c997c8c058b41d3a59a81f2bf654288b7cdf8f2 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Tue, 5 May 2015 14:19:24 +0800 +Subject: [PATCH 5/8] grub.texi: Add net_bootp6 doument + +Update grub documentation for net_bootp6 command. + +Signed-off-by: Michael Chang +Signed-off-by: Ken Lin +--- + docs/grub.texi | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +Index: grub-2.06~rc1/docs/grub.texi +=================================================================== +--- grub-2.06~rc1.orig/docs/grub.texi ++++ grub-2.06~rc1/docs/grub.texi +@@ -5477,6 +5477,7 @@ This command is only available on AArch6 + * net_add_dns:: Add a DNS server + * net_add_route:: Add routing entry + * net_bootp:: Perform a bootp/DHCP autoconfiguration ++* net_bootp6:: Perform a DHCPv6 autoconfiguration + * net_del_addr:: Remove IP address from interface + * net_del_dns:: Remove a DNS server + * net_del_route:: Remove a route entry +@@ -5533,6 +5534,24 @@ command (@pxref{net_dhcp}). + + @end deffn + ++ ++@node net_bootp6 ++@subsection net_bootp6 ++ ++@deffn Command net_bootp6 [@var{card}] ++Perform configuration of @var{card} using DHCPv6 protocol. If no card name is ++specified, try to configure all existing cards. If configuration was ++successful, interface with name @var{card}@samp{:dhcp6} and configured address ++is added to @var{card}. ++ ++@table @samp ++@item 1 (Domain Name Server) ++Adds all servers from option value to the list of servers used during name ++resolution. ++@end table ++ ++@end deffn ++ + + @node net_del_addr + @subsection net_del_addr diff --git a/0005-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch b/0005-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch new file mode 100644 index 0000000..36b8149 --- /dev/null +++ b/0005-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch @@ -0,0 +1,103 @@ +From ee99e452b9c1aafd3eb80592830ae2c6f69eb395 Mon Sep 17 00:00:00 2001 +From: Julian Andres Klode +Date: Thu, 2 Dec 2021 15:03:53 +0100 +Subject: [PATCH 05/32] kern/efi/sb: Reject non-kernel files in the shim_lock + verifier + +We must not allow other verifiers to pass things like the GRUB modules. +Instead of maintaining a blocklist, maintain an allowlist of things +that we do not care about. + +This allowlist really should be made reusable, and shared by the +lockdown verifier, but this is the minimal patch addressing +security concerns where the TPM verifier was able to mark modules +as verified (or the OpenPGP verifier for that matter), when it +should not do so on shim-powered secure boot systems. + +Fixes: CVE-2022-28735 + +Signed-off-by: Julian Andres Klode +Reviewed-by: Daniel Kiper +--- + grub-core/kern/efi/sb.c | 39 ++++++++++++++++++++++++++++++++++++--- + include/grub/verify.h | 1 + + 2 files changed, 37 insertions(+), 3 deletions(-) + +diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c +index c52ec6226a..89c4bb3fd1 100644 +--- a/grub-core/kern/efi/sb.c ++++ b/grub-core/kern/efi/sb.c +@@ -119,10 +119,11 @@ shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)), + void **context __attribute__ ((unused)), + enum grub_verify_flags *flags) + { +- *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; ++ *flags = GRUB_VERIFY_FLAGS_NONE; + + switch (type & GRUB_FILE_TYPE_MASK) + { ++ /* Files we check. */ + case GRUB_FILE_TYPE_LINUX_KERNEL: + case GRUB_FILE_TYPE_MULTIBOOT_KERNEL: + case GRUB_FILE_TYPE_BSD_KERNEL: +@@ -130,11 +131,43 @@ shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)), + case GRUB_FILE_TYPE_PLAN9_KERNEL: + case GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE: + *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK; ++ return GRUB_ERR_NONE; + +- /* Fall through. */ ++ /* Files that do not affect secureboot state. */ ++ case GRUB_FILE_TYPE_NONE: ++ case GRUB_FILE_TYPE_LOOPBACK: ++ case GRUB_FILE_TYPE_LINUX_INITRD: ++ case GRUB_FILE_TYPE_OPENBSD_RAMDISK: ++ case GRUB_FILE_TYPE_XNU_RAMDISK: ++ case GRUB_FILE_TYPE_SIGNATURE: ++ case GRUB_FILE_TYPE_PUBLIC_KEY: ++ case GRUB_FILE_TYPE_PUBLIC_KEY_TRUST: ++ case GRUB_FILE_TYPE_PRINT_BLOCKLIST: ++ case GRUB_FILE_TYPE_TESTLOAD: ++ case GRUB_FILE_TYPE_GET_SIZE: ++ case GRUB_FILE_TYPE_FONT: ++ case GRUB_FILE_TYPE_ZFS_ENCRYPTION_KEY: ++ case GRUB_FILE_TYPE_CAT: ++ case GRUB_FILE_TYPE_HEXCAT: ++ case GRUB_FILE_TYPE_CMP: ++ case GRUB_FILE_TYPE_HASHLIST: ++ case GRUB_FILE_TYPE_TO_HASH: ++ case GRUB_FILE_TYPE_KEYBOARD_LAYOUT: ++ case GRUB_FILE_TYPE_PIXMAP: ++ case GRUB_FILE_TYPE_GRUB_MODULE_LIST: ++ case GRUB_FILE_TYPE_CONFIG: ++ case GRUB_FILE_TYPE_THEME: ++ case GRUB_FILE_TYPE_GETTEXT_CATALOG: ++ case GRUB_FILE_TYPE_FS_SEARCH: ++ case GRUB_FILE_TYPE_LOADENV: ++ case GRUB_FILE_TYPE_SAVEENV: ++ case GRUB_FILE_TYPE_VERIFY_SIGNATURE: ++ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; ++ return GRUB_ERR_NONE; + ++ /* Other files. */ + default: +- return GRUB_ERR_NONE; ++ return grub_error (GRUB_ERR_ACCESS_DENIED, N_("prohibited by secure boot policy")); + } + } + +diff --git a/include/grub/verify.h b/include/grub/verify.h +index 6fde244fc6..67448165f4 100644 +--- a/include/grub/verify.h ++++ b/include/grub/verify.h +@@ -24,6 +24,7 @@ + + enum grub_verify_flags + { ++ GRUB_VERIFY_FLAGS_NONE = 0, + GRUB_VERIFY_FLAGS_SKIP_VERIFICATION = 1, + GRUB_VERIFY_FLAGS_SINGLE_CHUNK = 2, + /* Defer verification to another authority. */ +-- +2.34.1 + diff --git a/0005-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch b/0005-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch new file mode 100644 index 0000000..9cbf611 --- /dev/null +++ b/0005-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch @@ -0,0 +1,105 @@ +From a33acb675fe0d0464637175e4f06176e4c329025 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 12 Jul 2019 09:53:32 +0200 +Subject: [PATCH 05/11] x86-efi: Use bounce buffers for reading to addresses > + 4GB + +Lots of machines apparently can't DMA correctly above 4GB during UEFI, +so use bounce buffers for the initramfs read. + +Signed-off-by: Peter Jones +--- + grub-core/loader/i386/efi/linux.c | 52 ++++++++++++++++++++++++++----- + 1 file changed, 45 insertions(+), 7 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index f3abbd025..d6bed4fb4 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -35,11 +35,16 @@ static grub_dl_t my_mod; + static int loaded; + static void *kernel_mem; + static grub_uint64_t kernel_size; +-static grub_uint8_t *initrd_mem; ++static void *initrd_mem; + static grub_uint32_t handover_offset; + struct linux_kernel_params *params; + static char *linux_cmdline; + ++#define MIN(a, b) \ ++ ({ typeof (a) _a = (a); \ ++ typeof (b) _b = (b); \ ++ _a < _b ? _a : _b; }) ++ + #define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) + + static grub_err_t +@@ -68,6 +73,44 @@ grub_linuxefi_unload (void) + return GRUB_ERR_NONE; + } + ++#define BOUNCE_BUFFER_MAX 0x10000000ull ++ ++static grub_ssize_t ++read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len) ++{ ++ grub_ssize_t bufpos = 0; ++ static grub_size_t bbufsz = 0; ++ static char *bbuf = NULL; ++ ++ if (bbufsz == 0) ++ bbufsz = MIN(BOUNCE_BUFFER_MAX, len); ++ ++ while (!bbuf && bbufsz) ++ { ++ bbuf = grub_malloc(bbufsz); ++ if (!bbuf) ++ bbufsz >>= 1; ++ } ++ if (!bbuf) ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate bounce buffer")); ++ ++ while (bufpos < (long long)len) ++ { ++ grub_ssize_t sz; ++ ++ sz = grub_file_read (file, bbuf, MIN(bbufsz, len - bufpos)); ++ if (sz < 0) ++ return sz; ++ if (sz == 0) ++ break; ++ ++ grub_memcpy(bufp + bufpos, bbuf, sz); ++ bufpos += sz; ++ } ++ ++ return bufpos; ++} ++ + static grub_err_t + grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +@@ -120,7 +163,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + for (i = 0; i < nfiles; i++) + { + grub_ssize_t cursize = grub_file_size (files[i]); +- if (grub_file_read (files[i], ptr, cursize) != cursize) ++ if (read (files[i], ptr, cursize) != cursize) + { + if (!grub_errno) + grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), +@@ -145,11 +188,6 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + return grub_errno; + } + +-#define MIN(a, b) \ +- ({ typeof (a) _a = (a); \ +- typeof (b) _b = (b); \ +- _a < _b ? _a : _b; }) +- + static grub_err_t + grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +-- +2.31.1 + diff --git a/0006-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch b/0006-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch new file mode 100644 index 0000000..c8dc68b --- /dev/null +++ b/0006-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch @@ -0,0 +1,102 @@ +From 8191aae462f8b755972a0a801f4adbdd6ecaa66c Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Thu, 14 Jul 2016 18:45:14 +0800 +Subject: [PATCH 6/8] bootp: Add processing DHCPACK packet from HTTP Boot + +The vendor class identifier with the string "HTTPClient" is used to denote the +packet as responding to HTTP boot request. In DHCP4 config, the filename for +HTTP boot is the URL of the boot file while for PXE boot it is the path to the +boot file. As a consequence, the next-server becomes obseleted because the HTTP +URL already contains the server address for the boot file. For DHCP6 config, +there's no difference definition in existing config as dhcp6.bootfile-url can +be used to specify URL for both HTTP and PXE boot file. + +This patch adds processing for "HTTPClient" vendor class identifier in DHCPACK +packet by treating it as HTTP format, not as the PXE format. + +Signed-off-by: Michael Chang +Signed-off-by: Ken Lin +--- + grub-core/net/bootp.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++-- + include/grub/net.h | 1 + + 2 files changed, 66 insertions(+), 2 deletions(-) + +Index: grub-2.06~rc1/grub-core/net/bootp.c +=================================================================== +--- grub-2.06~rc1.orig/grub-core/net/bootp.c ++++ grub-2.06~rc1/grub-core/net/bootp.c +@@ -351,6 +351,53 @@ grub_net_configure_by_dhcp_ack (const ch + if (!inter) + return 0; + ++ /* FIXME: Introduce new http flag for better synergy with existing tftp code base */ ++ if (size > OFFSET_OF (vendor, bp)) ++ { ++ char *cidvar; ++ const char *cid; ++ ++ opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER, &opt_len); ++ if (opt && opt_len) ++ grub_env_set_net_property (name, "vendor_class_identifier", (const char *) opt, opt_len); ++ cidvar = grub_xasprintf ("net_%s_%s", name, "vendor_class_identifier"); ++ cid = grub_env_get (cidvar); ++ grub_free (cidvar); ++ ++ if (cid && grub_strcmp (cid, "HTTPClient") == 0) ++ { ++ char *proto, *ip, *pa; ++ ++ /* FIXME: Provide better URL function that returns in place pointers ++ * so that we don't have to free them. ++ */ ++ if (!dissect_url (bp->boot_file, &proto, &ip, &pa)) ++ return inter; ++ ++ if (is_def) ++ { ++ grub_net_default_server = grub_strdup (ip); ++ grub_env_set ("net_default_interface", name); ++ grub_env_export ("net_default_interface"); ++ } ++ if (device && !*device) ++ { ++ *device = grub_xasprintf ("%s,%s", proto, ip); ++ grub_print_error (); ++ } ++ ++ boot_file = pa; ++ boot_file_len = grub_strlen (pa); ++ ++ /* FIXME: Don't use malloc buffer here */ ++ grub_free (proto); ++ grub_free (ip); ++ ++ /* FIXME: NEED TO FREE boot_file */ ++ goto boot_file; ++ } ++ } ++ + opt = find_dhcp_option (bp, size, GRUB_NET_DHCP_OVERLOAD, &opt_len); + if (opt && opt_len == 1) + overload = *opt; +@@ -427,6 +474,8 @@ grub_net_configure_by_dhcp_ack (const ch + } + } + ++boot_file: ++ + if (boot_file) + { + grub_env_set_net_property (name, "boot_file", boot_file, boot_file_len); +Index: grub-2.06~rc1/include/grub/net.h +=================================================================== +--- grub-2.06~rc1.orig/include/grub/net.h ++++ grub-2.06~rc1/include/grub/net.h +@@ -528,6 +528,7 @@ enum + GRUB_NET_DHCP_MESSAGE_TYPE = 53, + GRUB_NET_DHCP_SERVER_IDENTIFIER = 54, + GRUB_NET_DHCP_PARAMETER_REQUEST_LIST = 55, ++ GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER = 60, + GRUB_NET_BOOTP_CLIENT_ID = 61, + GRUB_NET_DHCP_TFTP_SERVER_NAME = 66, + GRUB_NET_DHCP_BOOTFILE_NAME = 67, diff --git a/0006-cryptodisk-Add-infrastructure-to-pass-data-from-cryp.patch b/0006-cryptodisk-Add-infrastructure-to-pass-data-from-cryp.patch new file mode 100644 index 0000000..cb0880e --- /dev/null +++ b/0006-cryptodisk-Add-infrastructure-to-pass-data-from-cryp.patch @@ -0,0 +1,252 @@ +From 0a5619abd170b3ad43e44cb8036062506d8623cc Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:55 -0600 +Subject: [PATCH 06/14] cryptodisk: Add infrastructure to pass data from + cryptomount to cryptodisk modules + +Previously, the cryptomount arguments were passed by global variable and +function call argument, neither of which are ideal. This change passes data +via a grub_cryptomount_args struct, which can be added to over time as +opposed to continually adding arguments to the cryptodisk scan and +recover_key. + +As an example, passing a password as a cryptomount argument is implemented. +However, the backends are not implemented, so testing this will return a not +implemented error. + +Also, add comments to cryptomount argument parsing to make it more obvious +which argument states are being handled. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 31 +++++++++++++++++++++---------- + grub-core/disk/geli.c | 6 +++++- + grub-core/disk/luks.c | 7 ++++++- + grub-core/disk/luks2.c | 7 ++++++- + include/grub/cryptodisk.h | 9 ++++++++- + 5 files changed, 46 insertions(+), 14 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 5a9780b14c..14c661a86e 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -41,6 +41,7 @@ static const struct grub_arg_option options[] = + /* TRANSLATORS: It's still restricted to cryptodisks only. */ + {"all", 'a', 0, N_("Mount all."), 0, 0}, + {"boot", 'b', 0, N_("Mount all volumes with `boot' flag set."), 0, 0}, ++ {"password", 'p', 0, N_("Password to open volumes."), 0, ARG_TYPE_STRING}, + {0, 0, 0, 0, 0, 0} + }; + +@@ -996,7 +997,9 @@ cryptodisk_close (grub_cryptodisk_t dev) + } + + static grub_cryptodisk_t +-grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source) ++grub_cryptodisk_scan_device_real (const char *name, ++ grub_disk_t source, ++ grub_cryptomount_args_t cargs) + { + grub_err_t err; + grub_cryptodisk_t dev; +@@ -1015,7 +1018,7 @@ grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source) + if (!dev) + continue; + +- err = cr->recover_key (source, dev); ++ err = cr->recover_key (source, dev, cargs); + if (err) + { + cryptodisk_close (dev); +@@ -1080,11 +1083,12 @@ grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat) + + static int + grub_cryptodisk_scan_device (const char *name, +- void *data __attribute__ ((unused))) ++ void *data) + { + int ret = 0; + grub_disk_t source; + grub_cryptodisk_t dev; ++ grub_cryptomount_args_t cargs = data; + grub_errno = GRUB_ERR_NONE; + + /* Try to open disk. */ +@@ -1095,7 +1099,7 @@ grub_cryptodisk_scan_device (const char *name, + return 0; + } + +- dev = grub_cryptodisk_scan_device_real (name, source); ++ dev = grub_cryptodisk_scan_device_real (name, source, cargs); + if (dev) + { + ret = (search_uuid != NULL && grub_strcasecmp (search_uuid, dev->uuid) == 0); +@@ -1124,6 +1128,7 @@ static grub_err_t + grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + { + struct grub_arg_list *state = ctxt->state; ++ struct grub_cryptomount_args cargs = {0}; + + if (argc < 1 && !state[1].set && !state[2].set) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); +@@ -1131,7 +1136,13 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + if (grub_cryptodisk_list == NULL) + return grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk modules loaded"); + +- if (state[0].set) ++ if (state[3].set) /* password */ ++ { ++ cargs.key_data = (grub_uint8_t *) state[3].arg; ++ cargs.key_len = grub_strlen (state[3].arg); ++ } ++ ++ if (state[0].set) /* uuid */ + { + int found_uuid; + grub_cryptodisk_t dev; +@@ -1146,7 +1157,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + + check_boot = state[2].set; + search_uuid = args[0]; +- found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, NULL); ++ found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, &cargs); + search_uuid = NULL; + + if (found_uuid) +@@ -1163,11 +1174,11 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + } + return grub_errno; + } +- else if (state[1].set || (argc == 0 && state[2].set)) ++ else if (state[1].set || (argc == 0 && state[2].set)) /* -a|-b */ + { + search_uuid = NULL; + check_boot = state[2].set; +- grub_device_iterate (&grub_cryptodisk_scan_device, NULL); ++ grub_device_iterate (&grub_cryptodisk_scan_device, &cargs); + search_uuid = NULL; + return GRUB_ERR_NONE; + } +@@ -1208,7 +1219,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + return GRUB_ERR_NONE; + } + +- dev = grub_cryptodisk_scan_device_real (diskname, disk); ++ dev = grub_cryptodisk_scan_device_real (diskname, disk, &cargs); + + grub_disk_close (disk); + if (disklast) +@@ -1347,7 +1358,7 @@ GRUB_MOD_INIT (cryptodisk) + { + grub_disk_dev_register (&grub_cryptodisk_dev); + cmd = grub_register_extcmd ("cryptomount", grub_cmd_cryptomount, 0, +- N_("SOURCE|-u UUID|-a|-b"), ++ N_("[-p password] "), + N_("Mount a crypto device."), options); + grub_procfs_register ("luks_script", &luks_script); + } +diff --git a/grub-core/disk/geli.c b/grub-core/disk/geli.c +index 2f34a35e6b..777da3a055 100644 +--- a/grub-core/disk/geli.c ++++ b/grub-core/disk/geli.c +@@ -398,7 +398,7 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid, + } + + static grub_err_t +-recover_key (grub_disk_t source, grub_cryptodisk_t dev) ++recover_key (grub_disk_t source, grub_cryptodisk_t dev, grub_cryptomount_args_t cargs) + { + grub_size_t keysize; + grub_uint8_t digest[GRUB_CRYPTO_MAX_MDLEN]; +@@ -414,6 +414,10 @@ recover_key (grub_disk_t source, grub_cryptodisk_t dev) + grub_disk_addr_t sector; + grub_err_t err; + ++ /* Keyfiles are not implemented yet */ ++ if (cargs->key_data != NULL || cargs->key_len) ++ return GRUB_ERR_NOT_IMPLEMENTED_YET; ++ + if (dev->cipher->cipher->blocksize > GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE) + return grub_error (GRUB_ERR_BUG, "cipher block is too long"); + +diff --git a/grub-core/disk/luks.c b/grub-core/disk/luks.c +index 13103ea6a2..c5858fcf8a 100644 +--- a/grub-core/disk/luks.c ++++ b/grub-core/disk/luks.c +@@ -152,7 +152,8 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid, + + static grub_err_t + luks_recover_key (grub_disk_t source, +- grub_cryptodisk_t dev) ++ grub_cryptodisk_t dev, ++ grub_cryptomount_args_t cargs) + { + struct grub_luks_phdr header; + grub_size_t keysize; +@@ -165,6 +166,10 @@ luks_recover_key (grub_disk_t source, + grub_size_t max_stripes = 1; + char *tmp; + ++ /* Keyfiles are not implemented yet */ ++ if (cargs->key_data != NULL || cargs->key_len) ++ return GRUB_ERR_NOT_IMPLEMENTED_YET; ++ + err = grub_disk_read (source, 0, 0, sizeof (header), &header); + if (err) + return err; +diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c +index fea196dd4a..2cbec8acc2 100644 +--- a/grub-core/disk/luks2.c ++++ b/grub-core/disk/luks2.c +@@ -545,7 +545,8 @@ luks2_decrypt_key (grub_uint8_t *out_key, + + static grub_err_t + luks2_recover_key (grub_disk_t source, +- grub_cryptodisk_t crypt) ++ grub_cryptodisk_t crypt, ++ grub_cryptomount_args_t cargs) + { + grub_uint8_t candidate_key[GRUB_CRYPTODISK_MAX_KEYLEN]; + char passphrase[MAX_PASSPHRASE], cipher[32]; +@@ -559,6 +560,10 @@ luks2_recover_key (grub_disk_t source, + grub_json_t *json = NULL, keyslots; + grub_err_t ret; + ++ /* Keyfiles are not implemented yet */ ++ if (cargs->key_data != NULL || cargs->key_len) ++ return GRUB_ERR_NOT_IMPLEMENTED_YET; ++ + ret = luks2_read_header (source, &header); + if (ret) + return ret; +diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h +index dcf17fbb3a..282f8ac456 100644 +--- a/include/grub/cryptodisk.h ++++ b/include/grub/cryptodisk.h +@@ -66,6 +66,13 @@ typedef gcry_err_code_t + (*grub_cryptodisk_rekey_func_t) (struct grub_cryptodisk *dev, + grub_uint64_t zoneno); + ++struct grub_cryptomount_args ++{ ++ grub_uint8_t *key_data; ++ grub_size_t key_len; ++}; ++typedef struct grub_cryptomount_args *grub_cryptomount_args_t; ++ + struct grub_cryptodisk + { + struct grub_cryptodisk *next; +@@ -119,7 +126,7 @@ struct grub_cryptodisk_dev + + grub_cryptodisk_t (*scan) (grub_disk_t disk, const char *check_uuid, + int boot_only); +- grub_err_t (*recover_key) (grub_disk_t disk, grub_cryptodisk_t dev); ++ grub_err_t (*recover_key) (grub_disk_t disk, grub_cryptodisk_t dev, grub_cryptomount_args_t cargs); + }; + typedef struct grub_cryptodisk_dev *grub_cryptodisk_dev_t; + +-- +2.34.1 + diff --git a/0006-docs-grub-Document-signing-grub-with-an-appended-sig.patch b/0006-docs-grub-Document-signing-grub-with-an-appended-sig.patch new file mode 100644 index 0000000..40bf90e --- /dev/null +++ b/0006-docs-grub-Document-signing-grub-with-an-appended-sig.patch @@ -0,0 +1,71 @@ +From ac539a315495792cd75fe8ab1c474f26e0a78852 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Sat, 15 Aug 2020 02:19:36 +1000 +Subject: [PATCH 06/23] docs/grub: Document signing grub with an appended + signature + +Signing grub for firmware that verifies an appended signature is a +bit fiddly. I don't want people to have to figure it out from scratch +so document it here. + +Signed-off-by: Daniel Axtens +--- + docs/grub.texi | 42 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 42 insertions(+) + +diff --git a/docs/grub.texi b/docs/grub.texi +index b1d808d93..dc1c58304 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -6074,6 +6074,48 @@ image works under UEFI secure boot and can maintain the secure-boot chain. It + will also be necessary to enrol the public key used into a relevant firmware + key database. + ++@section Signing GRUB with an appended signature ++ ++The @file{core.img} itself can be signed with a Linux kernel module-style ++appended signature. ++ ++To support IEEE1275 platforms where the boot image is often loaded directly ++from a disk partition rather than from a file system, the @file{core.img} ++can specify the size and location of the appended signature with an ELF ++note added by @command{grub-install}. ++ ++An image can be signed this way using the @command{sign-file} command from ++the Linux kernel: ++ ++@example ++@group ++# grub.key is your private key and certificate.der is your public key ++ ++# Determine the size of the appended signature. It depends on the signing ++# certificate and the hash algorithm ++touch empty ++sign-file SHA256 grub.key certificate.der empty empty.sig ++SIG_SIZE=`stat -c '%s' empty.sig` ++rm empty empty.sig ++ ++# Build a grub image with $SIG_SIZE reserved for the signature ++grub-install --appended-signature-size $SIG_SIZE --modules="..." ... ++ ++# Replace the reserved size with a signature: ++# cut off the last $SIG_SIZE bytes with truncate's minus modifier ++truncate -s -$SIG_SIZE /boot/grub/powerpc-ieee1275/core.elf core.elf.unsigned ++# sign the trimmed file with an appended signature, restoring the correct size ++sign-file SHA256 grub.key certificate.der core.elf.unsigned core.elf.signed ++ ++# Don't forget to install the signed image as required ++# (e.g. on powerpc-ieee1275, to the PReP partition) ++@end group ++@end example ++ ++As with UEFI secure boot, it is necessary to build in the required modules, ++or sign them separately. ++ ++ + @node Platform limitations + @chapter Platform limitations + +-- +2.31.1 + diff --git a/0006-efi-Set-image-base-address-before-jumping-to-the-PE-.patch b/0006-efi-Set-image-base-address-before-jumping-to-the-PE-.patch new file mode 100644 index 0000000..ad90fbb --- /dev/null +++ b/0006-efi-Set-image-base-address-before-jumping-to-the-PE-.patch @@ -0,0 +1,59 @@ +From 3741c6807923ae97b0d87e61c59c8de8af544484 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Thu, 23 Apr 2020 15:06:46 +0200 +Subject: [PATCH 6/9] efi: Set image base address before jumping to the PE/COFF + entry point + +Upstream GRUB uses the EFI LoadImage() and StartImage() to boot the Linux +kernel. But our custom EFI loader that supports Secure Boot instead uses +the EFI handover protocol (for x86) or jumping directly to the PE/COFF +entry point (for aarch64). + +This is done to allow the bootloader to verify the images using the shim +lock protocol to avoid booting untrusted binaries. + +Since the bootloader loads the kernel from the boot media instead of using +LoadImage(), it is responsible to set the Loaded Image base address before +booting the kernel. + +Otherwise the kernel EFI stub will complain that it was not set correctly +and print the following warning message: + +EFI stub: ERROR: FIRMWARE BUG: efi_loaded_image_t::image_base has bogus value + +Resolves: rhbz#1825411 + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/loader/arm64/efi/linux.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +Index: grub-2.06~rc1/grub-core/loader/arm64/efi/linux.c +=================================================================== +--- grub-2.06~rc1.orig/grub-core/loader/arm64/efi/linux.c ++++ grub-2.06~rc1/grub-core/loader/arm64/efi/linux.c +@@ -58,9 +58,24 @@ static grub_err_t + grub_efi_linux_boot (void *kernel_address, grub_off_t offset, + void *kernel_params) + { ++ grub_efi_loaded_image_t *loaded_image = NULL; + handover_func hf; + ++ /* ++ * Since the EFI loader is not calling the LoadImage() and StartImage() ++ * services for loading the kernel and booting respectively, it has to ++ * set the Loaded Image base address. ++ */ ++ loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); ++ if (loaded_image) ++ loaded_image->image_base = kernel_addr; ++ else ++ grub_dprintf ("linux", "Loaded Image base address could not be set\n"); ++ ++ grub_dprintf ("linux", "kernel_addr: %p handover_offset: %p params: %p\n", ++ kernel_address, (void *)(grub_efi_uintn_t)offset, kernel_params); + hf = (handover_func)((char *)kernel_address + offset); ++ grub_dprintf ("linux", "handover_func() = %p\n", hf); + hf (grub_efi_image_handle, grub_efi_system_table, kernel_params); + + return GRUB_ERR_BUG; diff --git a/0006-font-Fix-integer-overflow-in-BMP-index.patch b/0006-font-Fix-integer-overflow-in-BMP-index.patch new file mode 100644 index 0000000..e258526 --- /dev/null +++ b/0006-font-Fix-integer-overflow-in-BMP-index.patch @@ -0,0 +1,65 @@ +From a97e0ae72604fbd4ebea854ffee127ed59b10f75 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Mon, 15 Aug 2022 02:04:58 +0800 +Subject: [PATCH 06/12] font: Fix integer overflow in BMP index + +The BMP index (font->bmp_idx) is designed as a reverse lookup table of +char entries (font->char_index), in order to speed up lookups for BMP +chars (i.e. code < 0x10000). The values in BMP index are the subscripts +of the corresponding char entries, stored in grub_uint16_t, while 0xffff +means not found. + +This patch fixes the problem of large subscript truncated to grub_uint16_t, +leading BMP index to return wrong char entry or report false miss. The +code now checks for bounds and uses BMP index as a hint, and fallbacks +to binary-search if necessary. + +On the occasion add a comment about BMP index is initialized to 0xffff. + +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +--- + grub-core/font/font.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index d0e634040..b208a2871 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -300,6 +300,8 @@ load_font_index (grub_file_t file, grub_uint32_t sect_length, struct + font->bmp_idx = grub_malloc (0x10000 * sizeof (grub_uint16_t)); + if (!font->bmp_idx) + return 1; ++ ++ /* Init the BMP index array to 0xffff. */ + grub_memset (font->bmp_idx, 0xff, 0x10000 * sizeof (grub_uint16_t)); + + +@@ -328,7 +330,7 @@ load_font_index (grub_file_t file, grub_uint32_t sect_length, struct + return 1; + } + +- if (entry->code < 0x10000) ++ if (entry->code < 0x10000 && i < 0xffff) + font->bmp_idx[entry->code] = i; + + last_code = entry->code; +@@ -696,9 +698,12 @@ find_glyph (const grub_font_t font, grub_uint32_t code) + /* Use BMP index if possible. */ + if (code < 0x10000 && font->bmp_idx) + { +- if (font->bmp_idx[code] == 0xffff) +- return 0; +- return &table[font->bmp_idx[code]]; ++ if (font->bmp_idx[code] < 0xffff) ++ return &table[font->bmp_idx[code]]; ++ /* ++ * When we are here then lookup in BMP index result in miss, ++ * fallthough to binary-search. ++ */ + } + + /* Do a binary search in `char_index', which is ordered by code point. */ +-- +2.35.3 + diff --git a/0006-fs-ntfs-Make-code-more-readable.patch b/0006-fs-ntfs-Make-code-more-readable.patch new file mode 100644 index 0000000..065b502 --- /dev/null +++ b/0006-fs-ntfs-Make-code-more-readable.patch @@ -0,0 +1,159 @@ +From e58b870ff926415e23fc386af41ff81b2f588763 Mon Sep 17 00:00:00 2001 +From: Maxim Suhanov +Date: Mon, 28 Aug 2023 16:40:07 +0300 +Subject: [PATCH 6/6] fs/ntfs: Make code more readable + +Move some calls used to access NTFS attribute header fields into +functions with human-readable names. + +Suggested-by: Daniel Kiper +Signed-off-by: Maxim Suhanov +Reviewed-by: Daniel Kiper +--- + grub-core/fs/ntfs.c | 48 +++++++++++++++++++++++++++++++-------------- + 1 file changed, 33 insertions(+), 15 deletions(-) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index ff5e3740f..de435aa14 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -52,6 +52,24 @@ u64at (void *ptr, grub_size_t ofs) + return grub_le_to_cpu64 (grub_get_unaligned64 ((char *) ptr + ofs)); + } + ++static grub_uint16_t ++first_attr_off (void *mft_buf_ptr) ++{ ++ return u16at (mft_buf_ptr, 0x14); ++} ++ ++static grub_uint16_t ++res_attr_data_off (void *res_attr_ptr) ++{ ++ return u16at (res_attr_ptr, 0x14); ++} ++ ++static grub_uint32_t ++res_attr_data_len (void *res_attr_ptr) ++{ ++ return u32at (res_attr_ptr, 0x10); ++} ++ + grub_ntfscomp_func_t grub_ntfscomp_func; + + static grub_err_t +@@ -106,7 +124,7 @@ init_attr (struct grub_ntfs_attr *at, struct grub_ntfs_file *mft) + { + at->mft = mft; + at->flags = (mft == &mft->data->mmft) ? GRUB_NTFS_AF_MMFT : 0; +- at->attr_nxt = mft->buf + u16at (mft->buf, 0x14); ++ at->attr_nxt = mft->buf + first_attr_off (mft->buf); + at->attr_end = at->emft_buf = at->edat_buf = at->sbuf = NULL; + } + +@@ -154,7 +172,7 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + return NULL; + } + +- new_pos = &at->emft_buf[u16at (at->emft_buf, 0x14)]; ++ new_pos = &at->emft_buf[first_attr_off (at->emft_buf)]; + while (*new_pos != 0xFF) + { + if ((*new_pos == *at->attr_cur) +@@ -213,7 +231,7 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + } + else + { +- at->attr_nxt = at->attr_end + u16at (pa, 0x14); ++ at->attr_nxt = at->attr_end + res_attr_data_off (pa); + at->attr_end = at->attr_end + u32at (pa, 4); + pa_end = at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR); + } +@@ -399,20 +417,20 @@ read_data (struct grub_ntfs_attr *at, grub_uint8_t *pa, grub_uint8_t *dest, + + if (pa[8] == 0) + { +- if (ofs + len > u32at (pa, 0x10)) ++ if (ofs + len > res_attr_data_len (pa)) + return grub_error (GRUB_ERR_BAD_FS, "read out of range"); + +- if (u32at (pa, 0x10) > (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) ++ if (res_attr_data_len (pa) > (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) + return grub_error (GRUB_ERR_BAD_FS, "resident attribute too large"); + + if (pa >= at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) + return grub_error (GRUB_ERR_BAD_FS, "resident attribute out of range"); + +- if (u16at (pa, 0x14) + u32at (pa, 0x10) > ++ if (res_attr_data_off (pa) + res_attr_data_len (pa) > + (grub_addr_t) at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR) - (grub_addr_t) pa) + return grub_error (GRUB_ERR_BAD_FS, "resident attribute out of range"); + +- grub_memcpy (dest, pa + u16at (pa, 0x14) + ofs, len); ++ grub_memcpy (dest, pa + res_attr_data_off (pa) + ofs, len); + return 0; + } + +@@ -556,7 +574,7 @@ init_file (struct grub_ntfs_file *mft, grub_uint64_t mftno) + (unsigned long long) mftno); + + if (!pa[8]) +- mft->size = u32at (pa, 0x10); ++ mft->size = res_attr_data_len (pa); + else + mft->size = u64at (pa, 0x30); + +@@ -805,7 +823,7 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + (u32at (cur_pos, 0x18) != 0x490024) || + (u32at (cur_pos, 0x1C) != 0x300033)) + continue; +- cur_pos += u16at (cur_pos, 0x14); ++ cur_pos += res_attr_data_off (cur_pos); + if (*cur_pos != 0x30) /* Not filename index */ + continue; + break; +@@ -834,7 +852,7 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + { + int is_resident = (cur_pos[8] == 0); + +- bitmap_len = ((is_resident) ? u32at (cur_pos, 0x10) : ++ bitmap_len = ((is_resident) ? res_attr_data_len (cur_pos) : + u32at (cur_pos, 0x28)); + + bmp = grub_malloc (bitmap_len); +@@ -855,14 +873,14 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + goto done; + } + +- if (u16at (cur_pos, 0x14) + u32at (cur_pos, 0x10) > ++ if (res_attr_data_off (cur_pos) + res_attr_data_len (cur_pos) > + (grub_addr_t) at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR) - (grub_addr_t) cur_pos) + { + grub_error (GRUB_ERR_BAD_FS, "resident bitmap out of range"); + goto done; + } + +- grub_memcpy (bmp, cur_pos + u16at (cur_pos, 0x14), ++ grub_memcpy (bmp, cur_pos + res_attr_data_off (cur_pos), + bitmap_len); + } + else +@@ -1226,12 +1244,12 @@ grub_ntfs_label (grub_device_t device, char **label) + goto fail; + } + +- if ((pa) && (pa[8] == 0) && (u32at (pa, 0x10))) ++ if ((pa) && (pa[8] == 0) && (res_attr_data_len (pa))) + { + int len; + +- len = u32at (pa, 0x10) / 2; +- pa += u16at (pa, 0x14); ++ len = res_attr_data_len (pa) / 2; ++ pa += res_attr_data_off (pa); + if (mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR) - pa >= 2 * len) + *label = get_utf8 (pa, len); + else +-- +2.42.0 + diff --git a/0006-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch b/0006-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch new file mode 100644 index 0000000..403a8b3 --- /dev/null +++ b/0006-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch @@ -0,0 +1,41 @@ +From 77a70351615e0b6e66d663e063e9b4ba8ae129a0 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 25 Jun 2021 02:19:05 +1000 +Subject: [PATCH 06/32] kern/file: Do not leak device_name on error in + grub_file_open() + +If we have an error in grub_file_open() before we free device_name, we +will leak it. + +Free device_name in the error path and null out the pointer in the good +path once we free it there. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/kern/file.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c +index 58454458c4..ffdcaba05f 100644 +--- a/grub-core/kern/file.c ++++ b/grub-core/kern/file.c +@@ -79,6 +79,7 @@ grub_file_open (const char *name, enum grub_file_type type) + + device = grub_device_open (device_name); + grub_free (device_name); ++ device_name = NULL; + if (! device) + goto fail; + +@@ -131,6 +132,7 @@ grub_file_open (const char *name, enum grub_file_type type) + return file; + + fail: ++ grub_free (device_name); + if (device) + grub_device_close (device); + +-- +2.34.1 + diff --git a/0006-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch b/0006-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch new file mode 100644 index 0000000..e37fa51 --- /dev/null +++ b/0006-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch @@ -0,0 +1,133 @@ +From 24b5c0a3788c5c02b72ea61312f5cf8c39429db1 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 13 Sep 2018 14:42:34 -0400 +Subject: [PATCH 06/11] x86-efi: Re-arrange grub_cmd_linux() a little bit. + +This just helps the next patch be easier to read. + +Signed-off-by: Peter Jones +--- + grub-core/loader/i386/efi/linux.c | 73 +++++++++++++++++-------------- + 1 file changed, 40 insertions(+), 33 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index d6bed4fb4..096a52eb5 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -227,32 +227,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, +- BYTES_TO_PAGES(sizeof(*params))); +- if (!params) +- params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, +- BYTES_TO_PAGES(sizeof(*params))); +- if (! params) +- { +- grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); +- goto fail; +- } +- +- grub_dprintf ("linux", "params = %p\n", params); +- +- grub_memset (params, 0, sizeof(*params)); ++ lh = (struct linux_i386_kernel_header *)kernel; ++ grub_dprintf ("linux", "original lh is at %p\n", kernel); + +- setup_header_end_offset = *((grub_uint8_t *)kernel + 0x201); +- grub_dprintf ("linux", "copying %lu bytes from %p to %p\n", +- MIN((grub_size_t)0x202+setup_header_end_offset, +- sizeof (*params)) - 0x1f1, +- (grub_uint8_t *)kernel + 0x1f1, +- (grub_uint8_t *)params + 0x1f1); +- grub_memcpy ((grub_uint8_t *)params + 0x1f1, +- (grub_uint8_t *)kernel + 0x1f1, +- MIN((grub_size_t)0x202+setup_header_end_offset,sizeof (*params)) - 0x1f1); +- lh = (struct linux_i386_kernel_header *)params; +- grub_dprintf ("linux", "lh is at %p\n", lh); + grub_dprintf ("linux", "checking lh->boot_flag\n"); + if (lh->boot_flag != grub_cpu_to_le16 (0xaa55)) + { +@@ -300,6 +277,34 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + #endif + ++ params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, ++ BYTES_TO_PAGES(sizeof(*params))); ++ if (!params) ++ params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, ++ BYTES_TO_PAGES(sizeof(*params))); ++ if (! params) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); ++ goto fail; ++ } ++ ++ grub_dprintf ("linux", "params = %p\n", params); ++ ++ grub_memset (params, 0, sizeof(*params)); ++ ++ setup_header_end_offset = *((grub_uint8_t *)kernel + 0x201); ++ grub_dprintf ("linux", "copying %" PRIuGRUB_SIZE " bytes from %p to %p\n", ++ MIN((grub_size_t)0x202+setup_header_end_offset, ++ sizeof (*params)) - 0x1f1, ++ (grub_uint8_t *)kernel + 0x1f1, ++ (grub_uint8_t *)params + 0x1f1); ++ grub_memcpy ((grub_uint8_t *)params + 0x1f1, ++ (grub_uint8_t *)kernel + 0x1f1, ++ MIN((grub_size_t)0x202+setup_header_end_offset,sizeof (*params)) - 0x1f1); ++ ++ lh = (struct linux_i386_kernel_header *)params; ++ grub_dprintf ("linux", "new lh is at %p\n", lh); ++ + grub_dprintf ("linux", "setting up cmdline\n"); + linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS, + BYTES_TO_PAGES(lh->cmdline_size + 1)); +@@ -324,8 +329,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_dprintf ("linux", "setting lh->cmd_line_ptr\n"); + lh->cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline; + +- grub_dprintf ("linux", "computing handover offset\n"); + handover_offset = lh->handover_offset; ++ grub_dprintf("linux", "handover_offset: %08x\n", handover_offset); + + start = (lh->setup_sects + 1) * 512; + +@@ -342,24 +347,26 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel")); + goto fail; + } +- +- grub_dprintf ("linux", "kernel_mem = %lx\n", (unsigned long) kernel_mem); ++ grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem); + + grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); +- loaded=1; ++ ++ loaded = 1; ++ + grub_dprintf ("linux", "setting lh->code32_start to %p\n", kernel_mem); + lh->code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem; + + grub_memcpy (kernel_mem, (char *)kernel + start, filelen - start); + +- grub_dprintf ("linux", "setting lh->type_of_loader\n"); + lh->type_of_loader = 0x6; ++ grub_dprintf ("linux", "setting lh->type_of_loader = 0x%02x\n", ++ lh->type_of_loader); + +- grub_dprintf ("linux", "setting lh->ext_loader_{type,ver}\n"); + params->ext_loader_type = 0; + params->ext_loader_ver = 2; +- grub_dprintf("linux", "kernel_mem: %p handover_offset: %08x\n", +- kernel_mem, handover_offset); ++ grub_dprintf ("linux", ++ "setting lh->ext_loader_{type,ver} = {0x%02x,0x%02x}\n", ++ params->ext_loader_type, params->ext_loader_ver); + + fail: + +-- +2.31.1 + diff --git a/0007-cryptodisk-Refactor-password-input-out-of-crypto-dev.patch b/0007-cryptodisk-Refactor-password-input-out-of-crypto-dev.patch new file mode 100644 index 0000000..75acb3b --- /dev/null +++ b/0007-cryptodisk-Refactor-password-input-out-of-crypto-dev.patch @@ -0,0 +1,342 @@ +From a3ae3f800f6aa3f6036351133ed69fa47c9fa371 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:56 -0600 +Subject: [PATCH 07/14] cryptodisk: Refactor password input out of crypto dev + modules into cryptodisk + +The crypto device modules should only be setting up the crypto devices and +not getting user input. This has the added benefit of simplifying the code +such that three essentially duplicate pieces of code are merged into one. + +Add documentation of passphrase option for cryptomount as it is now usable. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + docs/grub.texi | 8 ++++-- + grub-core/disk/cryptodisk.c | 56 +++++++++++++++++++++++++++++-------- + grub-core/disk/geli.c | 26 ++++------------- + grub-core/disk/luks.c | 27 +++--------------- + grub-core/disk/luks2.c | 25 +++-------------- + include/grub/cryptodisk.h | 1 + + 6 files changed, 64 insertions(+), 79 deletions(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index f4794fddac..4504bcabec 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -4310,9 +4310,11 @@ Alias for @code{hashsum --hash crc32 arg @dots{}}. See command @command{hashsum} + @node cryptomount + @subsection cryptomount + +-@deffn Command cryptomount device|@option{-u} uuid|@option{-a}|@option{-b} +-Setup access to encrypted device. If necessary, passphrase +-is requested interactively. Option @var{device} configures specific grub device ++@deffn Command cryptomount [@option{-p} password] device|@option{-u} uuid|@option{-a}|@option{-b} ++Setup access to encrypted device. If @option{-p} is not given, a passphrase ++is requested interactively. Otherwise, the given @var{password} will be used and ++no passphrase will be requested interactively. ++Option @var{device} configures specific grub device + (@pxref{Naming convention}); option @option{-u} @var{uuid} configures device + with specified @var{uuid}; option @option{-a} configures all detected encrypted + devices; option @option{-b} configures all geli containers that have boot flag set. +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 14c661a86e..d12368a1f7 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -1001,9 +1001,11 @@ grub_cryptodisk_scan_device_real (const char *name, + grub_disk_t source, + grub_cryptomount_args_t cargs) + { +- grub_err_t err; ++ grub_err_t ret = GRUB_ERR_NONE; + grub_cryptodisk_t dev; + grub_cryptodisk_dev_t cr; ++ int askpass = 0; ++ char *part = NULL; + + dev = grub_cryptodisk_get_by_source_disk (source); + +@@ -1017,21 +1019,53 @@ grub_cryptodisk_scan_device_real (const char *name, + return NULL; + if (!dev) + continue; +- +- err = cr->recover_key (source, dev, cargs); +- if (err) +- { +- cryptodisk_close (dev); +- return NULL; +- } ++ ++ if (!cargs->key_len) ++ { ++ /* Get the passphrase from the user, if no key data. */ ++ askpass = 1; ++ if (source->partition != NULL) ++ part = grub_partition_get_name (source->partition); ++ grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, ++ source->partition != NULL ? "," : "", ++ part != NULL ? part : "", ++ dev->uuid); ++ grub_free (part); ++ ++ cargs->key_data = grub_malloc (GRUB_CRYPTODISK_MAX_PASSPHRASE); ++ if (cargs->key_data == NULL) ++ return NULL; ++ ++ if (!grub_password_get ((char *) cargs->key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE)) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "passphrase not supplied"); ++ goto error; ++ } ++ cargs->key_len = grub_strlen ((char *) cargs->key_data); ++ } ++ ++ ret = cr->recover_key (source, dev, cargs); ++ if (ret != GRUB_ERR_NONE) ++ goto error; + + grub_cryptodisk_insert (dev, name, source); + +- return dev; ++ goto cleanup; + } +- + grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk module can handle this device"); +- return NULL; ++ goto cleanup; ++ ++ error: ++ cryptodisk_close (dev); ++ dev = NULL; ++ ++ cleanup: ++ if (askpass) ++ { ++ cargs->key_len = 0; ++ grub_free (cargs->key_data); ++ } ++ return dev; + } + + #ifdef GRUB_UTIL +diff --git a/grub-core/disk/geli.c b/grub-core/disk/geli.c +index 777da3a055..7299a47d19 100644 +--- a/grub-core/disk/geli.c ++++ b/grub-core/disk/geli.c +@@ -135,8 +135,6 @@ const char *algorithms[] = { + [0x16] = "aes" + }; + +-#define MAX_PASSPHRASE 256 +- + static gcry_err_code_t + geli_rekey (struct grub_cryptodisk *dev, grub_uint64_t zoneno) + { +@@ -406,17 +404,14 @@ recover_key (grub_disk_t source, grub_cryptodisk_t dev, grub_cryptomount_args_t + grub_uint8_t verify_key[GRUB_CRYPTO_MAX_MDLEN]; + grub_uint8_t zero[GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE]; + grub_uint8_t geli_cipher_key[64]; +- char passphrase[MAX_PASSPHRASE] = ""; + unsigned i; + gcry_err_code_t gcry_err; + struct grub_geli_phdr header; +- char *tmp; + grub_disk_addr_t sector; + grub_err_t err; + +- /* Keyfiles are not implemented yet */ +- if (cargs->key_data != NULL || cargs->key_len) +- return GRUB_ERR_NOT_IMPLEMENTED_YET; ++ if (cargs->key_data == NULL || cargs->key_len == 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no key data"); + + if (dev->cipher->cipher->blocksize > GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE) + return grub_error (GRUB_ERR_BUG, "cipher block is too long"); +@@ -438,23 +433,12 @@ recover_key (grub_disk_t source, grub_cryptodisk_t dev, grub_cryptomount_args_t + + grub_puts_ (N_("Attempting to decrypt master key...")); + +- /* Get the passphrase from the user. */ +- tmp = NULL; +- if (source->partition) +- tmp = grub_partition_get_name (source->partition); +- grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, +- source->partition ? "," : "", tmp ? : "", +- dev->uuid); +- grub_free (tmp); +- if (!grub_password_get (passphrase, MAX_PASSPHRASE)) +- return grub_error (GRUB_ERR_BAD_ARGUMENT, "Passphrase not supplied"); +- + /* Calculate the PBKDF2 of the user supplied passphrase. */ + if (grub_le_to_cpu32 (header.niter) != 0) + { + grub_uint8_t pbkdf_key[64]; +- gcry_err = grub_crypto_pbkdf2 (dev->hash, (grub_uint8_t *) passphrase, +- grub_strlen (passphrase), ++ gcry_err = grub_crypto_pbkdf2 (dev->hash, cargs->key_data, ++ cargs->key_len, + header.salt, + sizeof (header.salt), + grub_le_to_cpu32 (header.niter), +@@ -477,7 +461,7 @@ recover_key (grub_disk_t source, grub_cryptodisk_t dev, grub_cryptomount_args_t + return grub_crypto_gcry_error (GPG_ERR_OUT_OF_MEMORY); + + grub_crypto_hmac_write (hnd, header.salt, sizeof (header.salt)); +- grub_crypto_hmac_write (hnd, passphrase, grub_strlen (passphrase)); ++ grub_crypto_hmac_write (hnd, cargs->key_data, cargs->key_len); + + gcry_err = grub_crypto_hmac_fini (hnd, geomkey); + if (gcry_err) +diff --git a/grub-core/disk/luks.c b/grub-core/disk/luks.c +index c5858fcf8a..39a7af6a43 100644 +--- a/grub-core/disk/luks.c ++++ b/grub-core/disk/luks.c +@@ -29,8 +29,6 @@ + + GRUB_MOD_LICENSE ("GPLv3+"); + +-#define MAX_PASSPHRASE 256 +- + #define LUKS_KEY_ENABLED 0x00AC71F3 + + /* On disk LUKS header */ +@@ -158,17 +156,14 @@ luks_recover_key (grub_disk_t source, + struct grub_luks_phdr header; + grub_size_t keysize; + grub_uint8_t *split_key = NULL; +- char passphrase[MAX_PASSPHRASE] = ""; + grub_uint8_t candidate_digest[sizeof (header.mkDigest)]; + unsigned i; + grub_size_t length; + grub_err_t err; + grub_size_t max_stripes = 1; +- char *tmp; + +- /* Keyfiles are not implemented yet */ +- if (cargs->key_data != NULL || cargs->key_len) +- return GRUB_ERR_NOT_IMPLEMENTED_YET; ++ if (cargs->key_data == NULL || cargs->key_len == 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no key data"); + + err = grub_disk_read (source, 0, 0, sizeof (header), &header); + if (err) +@@ -188,20 +183,6 @@ luks_recover_key (grub_disk_t source, + if (!split_key) + return grub_errno; + +- /* Get the passphrase from the user. */ +- tmp = NULL; +- if (source->partition) +- tmp = grub_partition_get_name (source->partition); +- grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, +- source->partition ? "," : "", tmp ? : "", +- dev->uuid); +- grub_free (tmp); +- if (!grub_password_get (passphrase, MAX_PASSPHRASE)) +- { +- grub_free (split_key); +- return grub_error (GRUB_ERR_BAD_ARGUMENT, "Passphrase not supplied"); +- } +- + /* Try to recover master key from each active keyslot. */ + for (i = 0; i < ARRAY_SIZE (header.keyblock); i++) + { +@@ -216,8 +197,8 @@ luks_recover_key (grub_disk_t source, + grub_dprintf ("luks", "Trying keyslot %d\n", i); + + /* Calculate the PBKDF2 of the user supplied passphrase. */ +- gcry_err = grub_crypto_pbkdf2 (dev->hash, (grub_uint8_t *) passphrase, +- grub_strlen (passphrase), ++ gcry_err = grub_crypto_pbkdf2 (dev->hash, cargs->key_data, ++ cargs->key_len, + header.keyblock[i].passwordSalt, + sizeof (header.keyblock[i].passwordSalt), + grub_be_to_cpu32 (header.keyblock[i]. +diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c +index 2cbec8acc2..09740b53f9 100644 +--- a/grub-core/disk/luks2.c ++++ b/grub-core/disk/luks2.c +@@ -35,8 +35,6 @@ GRUB_MOD_LICENSE ("GPLv3+"); + #define LUKS_MAGIC_1ST "LUKS\xBA\xBE" + #define LUKS_MAGIC_2ND "SKUL\xBA\xBE" + +-#define MAX_PASSPHRASE 256 +- + enum grub_luks2_kdf_type + { + LUKS2_KDF_TYPE_ARGON2I, +@@ -549,8 +547,7 @@ luks2_recover_key (grub_disk_t source, + grub_cryptomount_args_t cargs) + { + grub_uint8_t candidate_key[GRUB_CRYPTODISK_MAX_KEYLEN]; +- char passphrase[MAX_PASSPHRASE], cipher[32]; +- char *json_header = NULL, *part = NULL, *ptr; ++ char cipher[32], *json_header = NULL, *ptr; + grub_size_t candidate_key_len = 0, json_idx, size; + grub_luks2_header_t header; + grub_luks2_keyslot_t keyslot; +@@ -560,9 +557,8 @@ luks2_recover_key (grub_disk_t source, + grub_json_t *json = NULL, keyslots; + grub_err_t ret; + +- /* Keyfiles are not implemented yet */ +- if (cargs->key_data != NULL || cargs->key_len) +- return GRUB_ERR_NOT_IMPLEMENTED_YET; ++ if (cargs->key_data == NULL || cargs->key_len == 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no key data"); + + ret = luks2_read_header (source, &header); + if (ret) +@@ -589,18 +585,6 @@ luks2_recover_key (grub_disk_t source, + goto err; + } + +- /* Get the passphrase from the user. */ +- if (source->partition) +- part = grub_partition_get_name (source->partition); +- grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, +- source->partition ? "," : "", part ? : "", +- crypt->uuid); +- if (!grub_password_get (passphrase, MAX_PASSPHRASE)) +- { +- ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Passphrase not supplied"); +- goto err; +- } +- + if (grub_json_getvalue (&keyslots, json, "keyslots") || + grub_json_getsize (&size, &keyslots)) + { +@@ -725,7 +709,7 @@ luks2_recover_key (grub_disk_t source, + } + + ret = luks2_decrypt_key (candidate_key, source, crypt, &keyslot, +- (const grub_uint8_t *) passphrase, grub_strlen (passphrase)); ++ cargs->key_data, cargs->key_len); + if (ret) + { + grub_dprintf ("luks2", "Decryption with keyslot \"%" PRIuGRUB_UINT64_T "\" failed: %s\n", +@@ -777,7 +761,6 @@ luks2_recover_key (grub_disk_t source, + } + + err: +- grub_free (part); + grub_free (json_header); + grub_json_free (json); + return ret; +diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h +index 282f8ac456..5bd970692f 100644 +--- a/include/grub/cryptodisk.h ++++ b/include/grub/cryptodisk.h +@@ -59,6 +59,7 @@ typedef enum + #define GRUB_CRYPTODISK_GF_LOG_BYTES (GRUB_CRYPTODISK_GF_LOG_SIZE - 3) + #define GRUB_CRYPTODISK_GF_BYTES (1U << GRUB_CRYPTODISK_GF_LOG_BYTES) + #define GRUB_CRYPTODISK_MAX_KEYLEN 128 ++#define GRUB_CRYPTODISK_MAX_PASSPHRASE 256 + + struct grub_cryptodisk; + +-- +2.34.1 + diff --git a/0007-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch b/0007-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch new file mode 100644 index 0000000..20baf77 --- /dev/null +++ b/0007-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch @@ -0,0 +1,48 @@ +From 4773f90bdefb72dde55fb5961f7f37b467307016 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 30 Jul 2020 00:13:21 +1000 +Subject: [PATCH 07/23] dl: provide a fake grub_dl_set_persistent for the emu + target + +Trying to start grub-emu with a module that calls grub_dl_set_persistent +will crash because grub-emu fakes modules and passes NULL to the module +init function. + +Provide an empty function for the emu case. + +Fixes: ee7808e2197c (dl: Add support for persistent modules) +Signed-off-by: Daniel Axtens +--- + include/grub/dl.h | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/include/grub/dl.h b/include/grub/dl.h +index b3753c9ca..5decbe2f2 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -243,11 +243,22 @@ grub_dl_get (const char *name) + return 0; + } + ++#ifdef GRUB_MACHINE_EMU ++/* ++ * Under grub-emu, modules are faked and NULL is passed to GRUB_MOD_INIT. ++ * So we fake this out to avoid a NULL deref. ++ */ ++static inline void ++grub_dl_set_persistent (grub_dl_t mod __attribute__((unused))) ++{ ++} ++#else + static inline void + grub_dl_set_persistent (grub_dl_t mod) + { + mod->persistent = 1; + } ++#endif + + static inline int + grub_dl_is_persistent (grub_dl_t mod) +-- +2.31.1 + diff --git a/0007-efinet-Setting-network-from-UEFI-device-path.patch b/0007-efinet-Setting-network-from-UEFI-device-path.patch new file mode 100644 index 0000000..be07bc3 --- /dev/null +++ b/0007-efinet-Setting-network-from-UEFI-device-path.patch @@ -0,0 +1,389 @@ +From 369df8e3006000a4acacc674f5882d8729781811 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Sun, 10 Jul 2016 23:46:31 +0800 +Subject: [PATCH 7/8] efinet: Setting network from UEFI device path + +The PXE Base Code protocol used to obtain cached PXE DHCPACK packet is no +longer provided for HTTP Boot. Instead, we have to get the HTTP boot +information from the device path nodes defined in following UEFI Specification +sections. + + 9.3.5.12 IPv4 Device Path + 9.3.5.13 IPv6 Device Path + 9.3.5.23 Uniform Resource Identifiers (URI) Device Path + +This patch basically does: + +include/grub/efi/api.h: +Add new structure of Uniform Resource Identifiers (URI) Device Path + +grub-core/net/drivers/efi/efinet.c: +Check if PXE Base Code is available, if not it will try to obtain the netboot +information from the device path where the image booted from. The DHCPACK +packet is recoverd from the information in device patch and feed into the same +DHCP packet processing functions to ensure the network interface is setting up +the same way it used to be. + +Signed-off-by: Michael Chang +Signed-off-by: Ken Lin +--- + grub-core/net/drivers/efi/efinet.c | 268 +++++++++++++++++++++++++++++++++++-- + include/grub/efi/api.h | 11 ++ + 2 files changed, 270 insertions(+), 9 deletions(-) + +diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c +index fc90415..2d3b00f 100644 +--- a/grub-core/net/drivers/efi/efinet.c ++++ b/grub-core/net/drivers/efi/efinet.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -324,6 +325,221 @@ grub_efinet_findcards (void) + grub_free (handles); + } + ++static struct grub_net_buff * ++grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *use_ipv6) ++{ ++ grub_efi_uint16_t uri_len; ++ grub_efi_device_path_t *ldp, *ddp; ++ grub_efi_uri_device_path_t *uri_dp; ++ struct grub_net_buff *nb; ++ grub_err_t err; ++ ++ ddp = grub_efi_duplicate_device_path (dp); ++ ldp = grub_efi_find_last_device_path (ddp); ++ ++ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE ++ || GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE) ++ { ++ grub_free (ddp); ++ return NULL; ++ } ++ ++ uri_len = GRUB_EFI_DEVICE_PATH_LENGTH (ldp) > 4 ? GRUB_EFI_DEVICE_PATH_LENGTH (ldp) - 4 : 0; ++ ++ if (!uri_len) ++ { ++ grub_free (ddp); ++ return NULL; ++ } ++ ++ uri_dp = (grub_efi_uri_device_path_t *) ldp; ++ ++ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ ldp->length = sizeof (*ldp); ++ ++ ldp = grub_efi_find_last_device_path (ddp); ++ ++ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE ++ || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE ++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)) ++ { ++ grub_free (ddp); ++ return NULL; ++ } ++ ++ nb = grub_netbuff_alloc (512); ++ if (!nb) ++ return NULL; ++ ++ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE) ++ { ++ grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) ldp; ++ struct grub_net_bootp_packet *bp; ++ grub_uint8_t *ptr; ++ ++ bp = (struct grub_net_bootp_packet *) nb->tail; ++ err = grub_netbuff_put (nb, sizeof (*bp) + 4); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ ++ if (sizeof(bp->boot_file) < uri_len) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ grub_memcpy (bp->boot_file, uri_dp->uri, uri_len); ++ grub_memcpy (&bp->your_ip, ipv4->local_ip_address, sizeof (bp->your_ip)); ++ grub_memcpy (&bp->server_ip, ipv4->remote_ip_address, sizeof (bp->server_ip)); ++ ++ bp->vendor[0] = GRUB_NET_BOOTP_RFC1048_MAGIC_0; ++ bp->vendor[1] = GRUB_NET_BOOTP_RFC1048_MAGIC_1; ++ bp->vendor[2] = GRUB_NET_BOOTP_RFC1048_MAGIC_2; ++ bp->vendor[3] = GRUB_NET_BOOTP_RFC1048_MAGIC_3; ++ ++ ptr = nb->tail; ++ err = grub_netbuff_put (nb, sizeof (ipv4->subnet_mask) + 2); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ *ptr++ = GRUB_NET_BOOTP_NETMASK; ++ *ptr++ = sizeof (ipv4->subnet_mask); ++ grub_memcpy (ptr, ipv4->subnet_mask, sizeof (ipv4->subnet_mask)); ++ ++ ptr = nb->tail; ++ err = grub_netbuff_put (nb, sizeof (ipv4->gateway_ip_address) + 2); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ *ptr++ = GRUB_NET_BOOTP_ROUTER; ++ *ptr++ = sizeof (ipv4->gateway_ip_address); ++ grub_memcpy (ptr, ipv4->gateway_ip_address, sizeof (ipv4->gateway_ip_address)); ++ ++ ptr = nb->tail; ++ err = grub_netbuff_put (nb, sizeof ("HTTPClient") + 1); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ *ptr++ = GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER; ++ *ptr++ = sizeof ("HTTPClient") - 1; ++ grub_memcpy (ptr, "HTTPClient", sizeof ("HTTPClient") - 1); ++ ++ ptr = nb->tail; ++ err = grub_netbuff_put (nb, 1); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ *ptr = GRUB_NET_BOOTP_END; ++ *use_ipv6 = 0; ++ ++ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ ldp->length = sizeof (*ldp); ++ ldp = grub_efi_find_last_device_path (ddp); ++ ++ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE) ++ { ++ grub_efi_mac_address_device_path_t *mac = (grub_efi_mac_address_device_path_t *) ldp; ++ bp->hw_type = mac->if_type; ++ bp->hw_len = sizeof (bp->mac_addr); ++ grub_memcpy (bp->mac_addr, mac->mac_address, bp->hw_len); ++ } ++ } ++ else ++ { ++ grub_efi_ipv6_device_path_t *ipv6 = (grub_efi_ipv6_device_path_t *) ldp; ++ ++ struct grub_net_dhcp6_packet *d6p; ++ struct grub_net_dhcp6_option *opt; ++ struct grub_net_dhcp6_option_iana *iana; ++ struct grub_net_dhcp6_option_iaaddr *iaaddr; ++ ++ d6p = (struct grub_net_dhcp6_packet *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*d6p)); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ d6p->message_type = GRUB_NET_DHCP6_REPLY; ++ ++ opt = (struct grub_net_dhcp6_option *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*opt)); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA); ++ opt->len = grub_cpu_to_be16_compile_time (sizeof(*iana) + sizeof(*opt) + sizeof(*iaaddr)); ++ ++ err = grub_netbuff_put (nb, sizeof(*iana)); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ ++ opt = (struct grub_net_dhcp6_option *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*opt)); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IAADDR); ++ opt->len = grub_cpu_to_be16_compile_time (sizeof (*iaaddr)); ++ ++ iaaddr = (struct grub_net_dhcp6_option_iaaddr *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*iaaddr)); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ grub_memcpy (iaaddr->addr, ipv6->local_ip_address, sizeof(ipv6->local_ip_address)); ++ ++ opt = (struct grub_net_dhcp6_option *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*opt) + uri_len); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_BOOTFILE_URL); ++ opt->len = grub_cpu_to_be16 (uri_len); ++ grub_memcpy (opt->data, uri_dp->uri, uri_len); ++ ++ *use_ipv6 = 1; ++ } ++ ++ grub_free (ddp); ++ return nb; ++} ++ + static void + grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + char **path) +@@ -340,6 +556,11 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + grub_efi_device_path_t *cdp; + struct grub_efi_pxe *pxe; + struct grub_efi_pxe_mode *pxe_mode; ++ grub_uint8_t *packet_buf; ++ grub_size_t packet_bufsz ; ++ int ipv6; ++ struct grub_net_buff *nb = NULL; ++ + if (card->driver != &efidriver) + continue; + cdp = grub_efi_get_device_path (card->efi_handle); +@@ -359,11 +580,21 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + ldp = grub_efi_find_last_device_path (dp); + if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE + || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE +- && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)) ++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE ++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)) + continue; + dup_dp = grub_efi_duplicate_device_path (dp); + if (!dup_dp) + continue; ++ ++ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE) ++ { ++ dup_ldp = grub_efi_find_last_device_path (dup_dp); ++ dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ dup_ldp->length = sizeof (*dup_ldp); ++ } ++ + dup_ldp = grub_efi_find_last_device_path (dup_dp); + dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; + dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; +@@ -375,16 +606,31 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + } + pxe = grub_efi_open_protocol (hnd, &pxe_io_guid, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); +- if (! pxe) +- continue; +- pxe_mode = pxe->mode; ++ if (!pxe) ++ { ++ nb = grub_efinet_create_dhcp_ack_from_device_path (dp, &ipv6); ++ if (!nb) ++ { ++ grub_print_error (); ++ continue; ++ } ++ packet_buf = nb->head; ++ packet_bufsz = nb->tail - nb->head; ++ } ++ else ++ { ++ pxe_mode = pxe->mode; ++ packet_buf = (grub_uint8_t *) &pxe_mode->dhcp_ack; ++ packet_bufsz = sizeof (pxe_mode->dhcp_ack); ++ ipv6 = pxe_mode->using_ipv6; ++ } + +- if (pxe_mode->using_ipv6) ++ if (ipv6) + { + grub_net_configure_by_dhcpv6_reply (card->name, card, 0, + (struct grub_net_dhcp6_packet *) +- &pxe_mode->dhcp_ack, +- sizeof (pxe_mode->dhcp_ack), ++ packet_buf, ++ packet_bufsz, + 1, device, path); + if (grub_errno) + grub_print_error (); +@@ -393,10 +639,14 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + { + grub_net_configure_by_dhcp_ack (card->name, card, 0, + (struct grub_net_bootp_packet *) +- &pxe_mode->dhcp_ack, +- sizeof (pxe_mode->dhcp_ack), ++ packet_buf, ++ packet_bufsz, + 1, device, path); + } ++ ++ if (nb) ++ grub_netbuff_free (nb); ++ + return; + } + } +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index 92f9b5a..d5a1256 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -825,6 +825,8 @@ struct grub_efi_ipv4_device_path + grub_efi_uint16_t remote_port; + grub_efi_uint16_t protocol; + grub_efi_uint8_t static_ip_address; ++ grub_efi_ipv4_address_t gateway_ip_address; ++ grub_efi_ipv4_address_t subnet_mask; + } GRUB_PACKED; + typedef struct grub_efi_ipv4_device_path grub_efi_ipv4_device_path_t; + +@@ -879,6 +881,15 @@ struct grub_efi_sata_device_path + } GRUB_PACKED; + typedef struct grub_efi_sata_device_path grub_efi_sata_device_path_t; + ++#define GRUB_EFI_URI_DEVICE_PATH_SUBTYPE 24 ++ ++struct grub_efi_uri_device_path ++{ ++ grub_efi_device_path_t header; ++ grub_efi_uint8_t uri[0]; ++} GRUB_PACKED; ++typedef struct grub_efi_uri_device_path grub_efi_uri_device_path_t; ++ + #define GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE 10 + + /* Media Device Path. */ +-- +2.6.6 + diff --git a/0007-font-Fix-integer-underflow-in-binary-search-of-char-.patch b/0007-font-Fix-integer-underflow-in-binary-search-of-char-.patch new file mode 100644 index 0000000..50a5e10 --- /dev/null +++ b/0007-font-Fix-integer-underflow-in-binary-search-of-char-.patch @@ -0,0 +1,86 @@ +From 926f1515608e14c0592fc61a8ef37392d7020ca3 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Sun, 14 Aug 2022 18:09:38 +0800 +Subject: [PATCH 07/12] font: Fix integer underflow in binary search of char + index + +If search target is less than all entries in font->index then "hi" +variable is set to -1, which translates to SIZE_MAX and leads to errors. + +This patch fixes the problem by replacing the entire binary search code +with the libstdc++'s std::lower_bound() implementation. + +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +--- + grub-core/font/font.c | 40 ++++++++++++++++++++++------------------ + 1 file changed, 22 insertions(+), 18 deletions(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index b208a2871..193dfec04 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -688,12 +688,12 @@ read_be_int16 (grub_file_t file, grub_int16_t * value) + static inline struct char_index_entry * + find_glyph (const grub_font_t font, grub_uint32_t code) + { +- struct char_index_entry *table; +- grub_size_t lo; +- grub_size_t hi; +- grub_size_t mid; ++ struct char_index_entry *table, *first, *end; ++ grub_size_t len; + + table = font->char_index; ++ if (table == NULL) ++ return NULL; + + /* Use BMP index if possible. */ + if (code < 0x10000 && font->bmp_idx) +@@ -706,25 +706,29 @@ find_glyph (const grub_font_t font, grub_uint32_t code) + */ + } + +- /* Do a binary search in `char_index', which is ordered by code point. */ +- lo = 0; +- hi = font->num_chars - 1; +- +- if (!table) +- return 0; ++ /* ++ * Do a binary search in char_index which is ordered by code point. ++ * The code below is the same as libstdc++'s std::lower_bound(). ++ */ ++ first = table; ++ len = font->num_chars; ++ end = first + len; + +- while (lo <= hi) ++ while (len > 0) + { +- mid = lo + (hi - lo) / 2; +- if (code < table[mid].code) +- hi = mid - 1; +- else if (code > table[mid].code) +- lo = mid + 1; ++ grub_size_t half = len >> 1; ++ struct char_index_entry *middle = first + half; ++ ++ if (middle->code < code) ++ { ++ first = middle + 1; ++ len = len - half - 1; ++ } + else +- return &table[mid]; ++ len = half; + } + +- return 0; ++ return (first < end && first->code == code) ? first : NULL; + } + + /* Get a glyph for the Unicode character CODE in FONT. The glyph is loaded +-- +2.35.3 + diff --git a/0007-video-readers-png-Abort-sooner-if-a-read-operation-f.patch b/0007-video-readers-png-Abort-sooner-if-a-read-operation-f.patch new file mode 100644 index 0000000..50f2aa1 --- /dev/null +++ b/0007-video-readers-png-Abort-sooner-if-a-read-operation-f.patch @@ -0,0 +1,201 @@ +From 9db9558e1c75d47beca7ba378a99471c57729be5 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 6 Jul 2021 14:02:55 +1000 +Subject: [PATCH 07/32] video/readers/png: Abort sooner if a read operation + fails + +Fuzzing revealed some inputs that were taking a long time, potentially +forever, because they did not bail quickly upon encountering an I/O error. + +Try to catch I/O errors sooner and bail out. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/video/readers/png.c | 55 ++++++++++++++++++++++++++++++----- + 1 file changed, 47 insertions(+), 8 deletions(-) + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index 54dfedf435..d715c4629f 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -142,6 +142,7 @@ static grub_uint8_t + grub_png_get_byte (struct grub_png_data *data) + { + grub_uint8_t r; ++ grub_ssize_t bytes_read = 0; + + if ((data->inside_idat) && (data->idat_remain == 0)) + { +@@ -175,7 +176,14 @@ grub_png_get_byte (struct grub_png_data *data) + } + + r = 0; +- grub_file_read (data->file, &r, 1); ++ bytes_read = grub_file_read (data->file, &r, 1); ++ ++ if (bytes_read != 1) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "png: unexpected end of data"); ++ return 0; ++ } + + if (data->inside_idat) + data->idat_remain--; +@@ -231,15 +239,16 @@ grub_png_decode_image_palette (struct grub_png_data *data, + if (len == 0) + return GRUB_ERR_NONE; + +- for (i = 0; 3 * i < len && i < 256; i++) ++ grub_errno = GRUB_ERR_NONE; ++ for (i = 0; 3 * i < len && i < 256 && grub_errno == GRUB_ERR_NONE; i++) + for (j = 0; j < 3; j++) + data->palette[i][j] = grub_png_get_byte (data); +- for (i *= 3; i < len; i++) ++ for (i *= 3; i < len && grub_errno == GRUB_ERR_NONE; i++) + grub_png_get_byte (data); + + grub_png_get_dword (data); + +- return GRUB_ERR_NONE; ++ return grub_errno; + } + + static grub_err_t +@@ -256,9 +265,13 @@ grub_png_decode_image_header (struct grub_png_data *data) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: invalid image size"); + + color_bits = grub_png_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + data->is_16bit = (color_bits == 16); + + color_type = grub_png_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + /* According to PNG spec, no other types are valid. */ + if ((color_type & ~(PNG_COLOR_MASK_ALPHA | PNG_COLOR_MASK_COLOR)) +@@ -340,14 +353,20 @@ grub_png_decode_image_header (struct grub_png_data *data) + if (grub_png_get_byte (data) != PNG_COMPRESSION_BASE) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "png: compression method not supported"); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + if (grub_png_get_byte (data) != PNG_FILTER_TYPE_BASE) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "png: filter method not supported"); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + if (grub_png_get_byte (data) != PNG_INTERLACE_NONE) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "png: interlace method not supported"); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + /* Skip crc checksum. */ + grub_png_get_dword (data); +@@ -449,7 +468,7 @@ grub_png_get_huff_code (struct grub_png_data *data, struct huff_table *ht) + int code, i; + + code = 0; +- for (i = 0; i < ht->max_length; i++) ++ for (i = 0; i < ht->max_length && grub_errno == GRUB_ERR_NONE; i++) + { + code = (code << 1) + grub_png_get_bits (data, 1); + if (code < ht->maxval[i]) +@@ -504,8 +523,14 @@ grub_png_init_dynamic_block (struct grub_png_data *data) + grub_uint8_t lens[DEFLATE_HCLEN_MAX]; + + nl = DEFLATE_HLIT_BASE + grub_png_get_bits (data, 5); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + nd = DEFLATE_HDIST_BASE + grub_png_get_bits (data, 5); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + nb = DEFLATE_HCLEN_BASE + grub_png_get_bits (data, 4); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + if ((nl > DEFLATE_HLIT_MAX) || (nd > DEFLATE_HDIST_MAX) || + (nb > DEFLATE_HCLEN_MAX)) +@@ -533,7 +558,7 @@ grub_png_init_dynamic_block (struct grub_png_data *data) + data->dist_offset); + + prev = 0; +- for (i = 0; i < nl + nd; i++) ++ for (i = 0; i < nl + nd && grub_errno == GRUB_ERR_NONE; i++) + { + int n, code; + struct huff_table *ht; +@@ -721,17 +746,21 @@ grub_png_read_dynamic_block (struct grub_png_data *data) + len = cplens[n]; + if (cplext[n]) + len += grub_png_get_bits (data, cplext[n]); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + n = grub_png_get_huff_code (data, &data->dist_table); + dist = cpdist[n]; + if (cpdext[n]) + dist += grub_png_get_bits (data, cpdext[n]); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + pos = data->wp - dist; + if (pos < 0) + pos += WSIZE; + +- while (len > 0) ++ while (len > 0 && grub_errno == GRUB_ERR_NONE) + { + data->slide[data->wp] = data->slide[pos]; + grub_png_output_byte (data, data->slide[data->wp]); +@@ -759,7 +788,11 @@ grub_png_decode_image_data (struct grub_png_data *data) + int final; + + cmf = grub_png_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + flg = grub_png_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + if ((cmf & 0xF) != Z_DEFLATED) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, +@@ -774,7 +807,11 @@ grub_png_decode_image_data (struct grub_png_data *data) + int block_type; + + final = grub_png_get_bits (data, 1); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + block_type = grub_png_get_bits (data, 2); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + switch (block_type) + { +@@ -790,7 +827,7 @@ grub_png_decode_image_data (struct grub_png_data *data) + grub_png_get_byte (data); + grub_png_get_byte (data); + +- for (i = 0; i < len; i++) ++ for (i = 0; i < len && grub_errno == GRUB_ERR_NONE; i++) + grub_png_output_byte (data, grub_png_get_byte (data)); + + break; +@@ -1045,6 +1082,8 @@ grub_png_decode_png (struct grub_png_data *data) + + len = grub_png_get_dword (data); + type = grub_png_get_dword (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ break; + data->next_offset = data->file->offset + len + 4; + + switch (type) +-- +2.34.1 + diff --git a/0007-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch b/0007-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch new file mode 100644 index 0000000..21a1173 --- /dev/null +++ b/0007-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch @@ -0,0 +1,249 @@ +From 2a84f1a50c6f8770808fd4ec590eb8cff4228aed Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Wed, 12 Sep 2018 16:03:55 -0400 +Subject: [PATCH 07/11] x86-efi: Make our own allocator for kernel stuff + +This helps enable allocations above 4GB. + +Signed-off-by: Peter Jones +--- + grub-core/loader/i386/efi/linux.c | 155 ++++++++++++++++++------------ + 1 file changed, 94 insertions(+), 61 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 096a52eb5..d284db5d1 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -47,6 +47,65 @@ static char *linux_cmdline; + + #define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) + ++struct allocation_choice { ++ grub_efi_physical_address_t addr; ++ grub_efi_allocate_type_t alloc_type; ++}; ++ ++static struct allocation_choice max_addresses[] = ++ { ++ { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ { 0, 0 } ++ }; ++ ++static inline void ++kernel_free(void *addr, grub_efi_uintn_t size) ++{ ++ if (addr && size) ++ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)addr, ++ BYTES_TO_PAGES(size)); ++} ++ ++static void * ++kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) ++{ ++ void *addr = 0; ++ unsigned int i; ++ grub_efi_physical_address_t prev_max = 0; ++ ++ for (i = 0; max_addresses[i].addr != 0 && addr == 0; i++) ++ { ++ grub_uint64_t max = max_addresses[i].addr; ++ grub_efi_uintn_t pages; ++ ++ if (max == prev_max) ++ continue; ++ ++ pages = BYTES_TO_PAGES(size); ++ grub_dprintf ("linux", "Trying to allocate %" PRIuGRUB_SIZE" pages from %p\n", ++ pages, (void *)(grub_addr_t)max); ++ ++ prev_max = max; ++ addr = grub_efi_allocate_pages_real (max, pages, ++ max_addresses[i].alloc_type, ++ GRUB_EFI_LOADER_DATA); ++ if (addr) ++ grub_dprintf ("linux", "Allocated at %p\n", addr); ++ } ++ ++ while (grub_error_pop ()) ++ { ++ ; ++ } ++ ++ if (addr == NULL) ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, "%s", errmsg); ++ ++ return addr; ++} ++ + static grub_err_t + grub_linuxefi_boot (void) + { +@@ -62,14 +121,12 @@ grub_linuxefi_unload (void) + { + grub_dl_unref (my_mod); + loaded = 0; +- if (initrd_mem) +- grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)initrd_mem, BYTES_TO_PAGES(params->ramdisk_size)); +- if (linux_cmdline) +- grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)linux_cmdline, BYTES_TO_PAGES(params->cmdline_size + 1)); +- if (kernel_mem) +- grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)kernel_mem, BYTES_TO_PAGES(kernel_size)); +- if (params) +- grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)params, BYTES_TO_PAGES(16384)); ++ ++ kernel_free(initrd_mem, params->ramdisk_size); ++ kernel_free(linux_cmdline, params->cmdline_size + 1); ++ kernel_free(kernel_mem, kernel_size); ++ kernel_free(params, sizeof(*params)); ++ + return GRUB_ERR_NONE; + } + +@@ -146,17 +203,13 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + size += ALIGN_UP (grub_file_size (files[i]), 4); + } + +- initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, BYTES_TO_PAGES(size)); +- if (!initrd_mem) +- initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, BYTES_TO_PAGES(size)); +- if (!initrd_mem) +- { +- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd")); +- goto fail; +- } ++ initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); ++ if (initrd_mem == NULL) ++ goto fail; ++ grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem); + + params->ramdisk_size = size; +- params->ramdisk_image = (grub_uint32_t)(grub_addr_t) initrd_mem; ++ params->ramdisk_image = initrd_mem; + + ptr = initrd_mem; + +@@ -214,7 +267,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + filelen = grub_file_size (file); + + kernel = grub_malloc(filelen); +- + if (!kernel) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer")); +@@ -258,7 +310,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +-#if defined(__x86_64__) || defined(__aarch64__) ++#if defined(__x86_64__) + grub_dprintf ("linux", "checking lh->xloadflags\n"); + if (!(lh->xloadflags & LINUX_XLF_KERNEL_64)) + { +@@ -277,17 +329,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + #endif + +- params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, +- BYTES_TO_PAGES(sizeof(*params))); ++ params = kernel_alloc (sizeof(*params), "cannot allocate kernel parameters"); + if (!params) +- params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, +- BYTES_TO_PAGES(sizeof(*params))); +- if (! params) +- { +- grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); +- goto fail; +- } +- ++ goto fail; + grub_dprintf ("linux", "params = %p\n", params); + + grub_memset (params, 0, sizeof(*params)); +@@ -306,16 +350,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_dprintf ("linux", "new lh is at %p\n", lh); + + grub_dprintf ("linux", "setting up cmdline\n"); +- linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS, +- BYTES_TO_PAGES(lh->cmdline_size + 1)); ++ linux_cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline")); + if (!linux_cmdline) +- linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS, +- BYTES_TO_PAGES(lh->cmdline_size + 1)); +- if (!linux_cmdline) +- { +- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline")); +- goto fail; +- } ++ goto fail; ++ grub_dprintf ("linux", "linux_cmdline = %p\n", linux_cmdline); + + grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); + err = grub_create_loader_cmdline (argc, argv, +@@ -326,27 +364,24 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + + grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline); +- grub_dprintf ("linux", "setting lh->cmd_line_ptr\n"); +- lh->cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline; ++ grub_dprintf ("linux", "setting lh->cmd_line_ptr to 0x%08x\n", ++ linux_cmdline); ++ lh->cmd_line_ptr = linux_cmdline; + + handover_offset = lh->handover_offset; +- grub_dprintf("linux", "handover_offset: %08x\n", handover_offset); ++ grub_dprintf("linux", "handover_offset: 0x%08x\n", handover_offset); + + start = (lh->setup_sects + 1) * 512; + +- kernel_mem = grub_efi_allocate_pages_max(lh->pref_address, +- BYTES_TO_PAGES(lh->init_size)); +- if (!kernel_mem) +- kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS, +- BYTES_TO_PAGES(lh->init_size)); +- if (!kernel_mem) +- kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS, +- BYTES_TO_PAGES(lh->init_size)); +- if (!kernel_mem) ++ grub_dprintf ("linux", "lh->pref_address: %p\n", (void *)(grub_addr_t)lh->pref_address); ++ if (lh->pref_address < (grub_uint64_t)GRUB_EFI_MAX_ALLOCATION_ADDRESS) + { +- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel")); +- goto fail; ++ max_addresses[0].addr = lh->pref_address; ++ max_addresses[0].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS; + } ++ kernel_mem = kernel_alloc (lh->init_size, N_("can't allocate kernel")); ++ if (!kernel_mem) ++ goto fail; + grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem); + + grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); +@@ -382,16 +417,14 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + loaded = 0; + } + +- if (linux_cmdline && lh && !loaded) +- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t) +- linux_cmdline, +- BYTES_TO_PAGES(lh->cmdline_size + 1)); +- +- if (kernel_mem && !loaded) +- grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)kernel_mem, BYTES_TO_PAGES(kernel_size)); ++ if (!loaded) ++ { ++ if (lh) ++ kernel_free (linux_cmdline, lh->cmdline_size + 1); + +- if (params && !loaded) +- grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)params, BYTES_TO_PAGES(16384)); ++ kernel_free (kernel_mem, kernel_size); ++ kernel_free (params, sizeof(*params)); ++ } + + return grub_errno; + } +-- +2.31.1 + diff --git a/0008-cryptodisk-Move-global-variables-into-grub_cryptomou.patch b/0008-cryptodisk-Move-global-variables-into-grub_cryptomou.patch new file mode 100644 index 0000000..8bf205b --- /dev/null +++ b/0008-cryptodisk-Move-global-variables-into-grub_cryptomou.patch @@ -0,0 +1,248 @@ +From 5323778d84a7289acba0e50d84fb1afd45fff596 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:57 -0600 +Subject: [PATCH 08/14] cryptodisk: Move global variables into + grub_cryptomount_args struct + +Note that cargs.search_uuid does not need to be initialized in various parts +of the cryptomount argument parsing, just once when cargs is declared with +a struct initializer. The previous code used a global variable which would +retain the value across cryptomount invocations. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 24 +++++++++--------------- + grub-core/disk/geli.c | 9 ++++----- + grub-core/disk/luks.c | 9 ++++----- + grub-core/disk/luks2.c | 8 ++++---- + include/grub/cryptodisk.h | 9 +++++++-- + 5 files changed, 28 insertions(+), 31 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index d12368a1f7..7ca880402d 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -984,9 +984,6 @@ grub_util_cryptodisk_get_uuid (grub_disk_t disk) + + #endif + +-static int check_boot; +-static char *search_uuid; +- + static void + cryptodisk_close (grub_cryptodisk_t dev) + { +@@ -1014,7 +1011,7 @@ grub_cryptodisk_scan_device_real (const char *name, + + FOR_CRYPTODISK_DEVS (cr) + { +- dev = cr->scan (source, search_uuid, check_boot); ++ dev = cr->scan (source, cargs); + if (grub_errno) + return NULL; + if (!dev) +@@ -1077,6 +1074,7 @@ grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat) + grub_cryptodisk_t dev; + grub_cryptodisk_dev_t cr; + grub_disk_t source; ++ struct grub_cryptomount_args cargs = {0}; + + /* Try to open disk. */ + source = grub_disk_open (sourcedev); +@@ -1093,7 +1091,7 @@ grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat) + + FOR_CRYPTODISK_DEVS (cr) + { +- dev = cr->scan (source, search_uuid, check_boot); ++ dev = cr->scan (source, &cargs); + if (grub_errno) + return grub_errno; + if (!dev) +@@ -1136,7 +1134,7 @@ grub_cryptodisk_scan_device (const char *name, + dev = grub_cryptodisk_scan_device_real (name, source, cargs); + if (dev) + { +- ret = (search_uuid != NULL && grub_strcasecmp (search_uuid, dev->uuid) == 0); ++ ret = (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, dev->uuid) == 0); + goto cleanup; + } + +@@ -1147,7 +1145,7 @@ grub_cryptodisk_scan_device (const char *name, + if (grub_errno == GRUB_ERR_BAD_MODULE) + grub_error_pop (); + +- if (search_uuid != NULL) ++ if (cargs->search_uuid != NULL) + /* Push error onto stack to save for cryptomount. */ + grub_error_push (); + else +@@ -1189,10 +1187,9 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + return GRUB_ERR_NONE; + } + +- check_boot = state[2].set; +- search_uuid = args[0]; ++ cargs.check_boot = state[2].set; ++ cargs.search_uuid = args[0]; + found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, &cargs); +- search_uuid = NULL; + + if (found_uuid) + return GRUB_ERR_NONE; +@@ -1210,10 +1207,8 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + } + else if (state[1].set || (argc == 0 && state[2].set)) /* -a|-b */ + { +- search_uuid = NULL; +- check_boot = state[2].set; ++ cargs.check_boot = state[2].set; + grub_device_iterate (&grub_cryptodisk_scan_device, &cargs); +- search_uuid = NULL; + return GRUB_ERR_NONE; + } + else +@@ -1224,8 +1219,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + char *disklast = NULL; + grub_size_t len; + +- search_uuid = NULL; +- check_boot = state[2].set; ++ cargs.check_boot = state[2].set; + diskname = args[0]; + len = grub_strlen (diskname); + if (len && diskname[0] == '(' && diskname[len - 1] == ')') +diff --git a/grub-core/disk/geli.c b/grub-core/disk/geli.c +index 7299a47d19..23789c43f3 100644 +--- a/grub-core/disk/geli.c ++++ b/grub-core/disk/geli.c +@@ -240,8 +240,7 @@ grub_util_get_geli_uuid (const char *dev) + #endif + + static grub_cryptodisk_t +-configure_ciphers (grub_disk_t disk, const char *check_uuid, +- int boot_only) ++configure_ciphers (grub_disk_t disk, grub_cryptomount_args_t cargs) + { + grub_cryptodisk_t newdev; + struct grub_geli_phdr header; +@@ -289,7 +288,7 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid, + return NULL; + } + +- if (boot_only && !(grub_le_to_cpu32 (header.flags) & GRUB_GELI_FLAGS_BOOT)) ++ if (cargs->check_boot && !(grub_le_to_cpu32 (header.flags) & GRUB_GELI_FLAGS_BOOT)) + { + grub_dprintf ("geli", "not a boot volume\n"); + return NULL; +@@ -302,9 +301,9 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid, + return NULL; + } + +- if (check_uuid && grub_strcasecmp (check_uuid, uuid) != 0) ++ if (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, uuid) != 0) + { +- grub_dprintf ("geli", "%s != %s\n", uuid, check_uuid); ++ grub_dprintf ("geli", "%s != %s\n", uuid, cargs->search_uuid); + return NULL; + } + +diff --git a/grub-core/disk/luks.c b/grub-core/disk/luks.c +index 39a7af6a43..f0feb38447 100644 +--- a/grub-core/disk/luks.c ++++ b/grub-core/disk/luks.c +@@ -63,8 +63,7 @@ gcry_err_code_t AF_merge (const gcry_md_spec_t * hash, grub_uint8_t * src, + grub_size_t blocknumbers); + + static grub_cryptodisk_t +-configure_ciphers (grub_disk_t disk, const char *check_uuid, +- int check_boot) ++configure_ciphers (grub_disk_t disk, grub_cryptomount_args_t cargs) + { + grub_cryptodisk_t newdev; + const char *iptr; +@@ -76,7 +75,7 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid, + char hashspec[sizeof (header.hashSpec) + 1]; + grub_err_t err; + +- if (check_boot) ++ if (cargs->check_boot) + return NULL; + + /* Read the LUKS header. */ +@@ -103,9 +102,9 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid, + } + *optr = 0; + +- if (check_uuid && grub_strcasecmp (check_uuid, uuid) != 0) ++ if (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, uuid) != 0) + { +- grub_dprintf ("luks", "%s != %s\n", uuid, check_uuid); ++ grub_dprintf ("luks", "%s != %s\n", uuid, cargs->search_uuid); + return NULL; + } + +diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c +index 09740b53f9..ccfacb63a3 100644 +--- a/grub-core/disk/luks2.c ++++ b/grub-core/disk/luks2.c +@@ -346,14 +346,14 @@ luks2_read_header (grub_disk_t disk, grub_luks2_header_t *outhdr) + } + + static grub_cryptodisk_t +-luks2_scan (grub_disk_t disk, const char *check_uuid, int check_boot) ++luks2_scan (grub_disk_t disk, grub_cryptomount_args_t cargs) + { + grub_cryptodisk_t cryptodisk; + grub_luks2_header_t header; + char uuid[sizeof (header.uuid) + 1]; + grub_size_t i, j; + +- if (check_boot) ++ if (cargs->check_boot) + return NULL; + + if (luks2_read_header (disk, &header)) +@@ -367,9 +367,9 @@ luks2_scan (grub_disk_t disk, const char *check_uuid, int check_boot) + uuid[j++] = header.uuid[i]; + uuid[j] = '\0'; + +- if (check_uuid && grub_strcasecmp (check_uuid, uuid) != 0) ++ if (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, uuid) != 0) + { +- grub_dprintf ("luks2", "%s != %s\n", uuid, check_uuid); ++ grub_dprintf ("luks2", "%s != %s\n", uuid, cargs->search_uuid); + return NULL; + } + +diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h +index 5bd970692f..c6524c9ea9 100644 +--- a/include/grub/cryptodisk.h ++++ b/include/grub/cryptodisk.h +@@ -69,7 +69,13 @@ typedef gcry_err_code_t + + struct grub_cryptomount_args + { ++ /* scan: Flag to indicate that only bootable volumes should be decrypted */ ++ grub_uint32_t check_boot : 1; ++ /* scan: Only volumes matching this UUID should be decrpyted */ ++ char *search_uuid; ++ /* recover_key: Key data used to decrypt voume */ + grub_uint8_t *key_data; ++ /* recover_key: Length of key_data */ + grub_size_t key_len; + }; + typedef struct grub_cryptomount_args *grub_cryptomount_args_t; +@@ -125,8 +131,7 @@ struct grub_cryptodisk_dev + struct grub_cryptodisk_dev *next; + struct grub_cryptodisk_dev **prev; + +- grub_cryptodisk_t (*scan) (grub_disk_t disk, const char *check_uuid, +- int boot_only); ++ grub_cryptodisk_t (*scan) (grub_disk_t disk, grub_cryptomount_args_t cargs); + grub_err_t (*recover_key) (grub_disk_t disk, grub_cryptodisk_t dev, grub_cryptomount_args_t cargs); + }; + typedef struct grub_cryptodisk_dev *grub_cryptodisk_dev_t; +-- +2.34.1 + diff --git a/0008-efinet-Setting-DNS-server-from-UEFI-protocol.patch b/0008-efinet-Setting-DNS-server-from-UEFI-protocol.patch new file mode 100644 index 0000000..fb63634 --- /dev/null +++ b/0008-efinet-Setting-DNS-server-from-UEFI-protocol.patch @@ -0,0 +1,337 @@ +From 0c7ae6d7527d08e54a6eeebddb6c5c697c4b37d2 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Thu, 14 Jul 2016 17:48:45 +0800 +Subject: [PATCH 8/8] efinet: Setting DNS server from UEFI protocol + +In the URI device path node, any name rahter than address can be used for +looking up the resources so that DNS service become needed to get answer of the +name's address. Unfortunately the DNS is not defined in any of the device path +nodes so that we use the EFI_IP4_CONFIG2_PROTOCOL and EFI_IP6_CONFIG_PROTOCOL +to obtain it. + +These two protcols are defined the sections of UEFI specification. + + 27.5 EFI IPv4 Configuration II Protocol + 27.7 EFI IPv6 Configuration Protocol + +include/grub/efi/api.h: +Add new structure and protocol UUID of EFI_IP4_CONFIG2_PROTOCOL and +EFI_IP6_CONFIG_PROTOCOL. + +grub-core/net/drivers/efi/efinet.c: +Use the EFI_IP4_CONFIG2_PROTOCOL and EFI_IP6_CONFIG_PROTOCOL to obtain the list +of DNS server address for IPv4 and IPv6 respectively. The address of DNS +servers is structured into DHCPACK packet and feed into the same DHCP packet +processing functions to ensure the network interface is setting up the same way +it used to be. + +Signed-off-by: Michael Chang +Signed-off-by: Ken Lin +--- + grub-core/net/drivers/efi/efinet.c | 163 +++++++++++++++++++++++++++++++++++++ + include/grub/efi/api.h | 76 +++++++++++++++++ + 2 files changed, 239 insertions(+) + +Index: grub-2.06~rc1/grub-core/net/drivers/efi/efinet.c +=================================================================== +--- grub-2.06~rc1.orig/grub-core/net/drivers/efi/efinet.c ++++ grub-2.06~rc1/grub-core/net/drivers/efi/efinet.c +@@ -30,6 +30,8 @@ GRUB_MOD_LICENSE ("GPLv3+"); + /* GUID. */ + static grub_efi_guid_t net_io_guid = GRUB_EFI_SIMPLE_NETWORK_GUID; + static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID; ++static grub_efi_guid_t ip4_config_guid = GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID; ++static grub_efi_guid_t ip6_config_guid = GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID; + + static grub_err_t + send_card_buffer (struct grub_net_card *dev, +@@ -325,6 +327,125 @@ grub_efinet_findcards (void) + grub_free (handles); + } + ++static grub_efi_handle_t ++grub_efi_locate_device_path (grub_efi_guid_t *protocol, grub_efi_device_path_t *device_path, ++ grub_efi_device_path_t **r_device_path) ++{ ++ grub_efi_handle_t handle; ++ grub_efi_status_t status; ++ ++ status = efi_call_3 (grub_efi_system_table->boot_services->locate_device_path, ++ protocol, &device_path, &handle); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ ++ if (r_device_path) ++ *r_device_path = device_path; ++ ++ return handle; ++} ++ ++static grub_efi_ipv4_address_t * ++grub_dns_server_ip4_address (grub_efi_device_path_t *dp, grub_efi_uintn_t *num_dns) ++{ ++ grub_efi_handle_t hnd; ++ grub_efi_status_t status; ++ grub_efi_ip4_config2_protocol_t *conf; ++ grub_efi_ipv4_address_t *addrs; ++ grub_efi_uintn_t data_size = 1 * sizeof (grub_efi_ipv4_address_t); ++ ++ hnd = grub_efi_locate_device_path (&ip4_config_guid, dp, NULL); ++ ++ if (!hnd) ++ return 0; ++ ++ conf = grub_efi_open_protocol (hnd, &ip4_config_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ ++ if (!conf) ++ return 0; ++ ++ addrs = grub_malloc (data_size); ++ if (!addrs) ++ return 0; ++ ++ status = efi_call_4 (conf->get_data, conf, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER, ++ &data_size, addrs); ++ ++ if (status == GRUB_EFI_BUFFER_TOO_SMALL) ++ { ++ grub_free (addrs); ++ addrs = grub_malloc (data_size); ++ if (!addrs) ++ return 0; ++ ++ status = efi_call_4 (conf->get_data, conf, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER, ++ &data_size, addrs); ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (addrs); ++ return 0; ++ } ++ ++ *num_dns = data_size / sizeof (grub_efi_ipv4_address_t); ++ return addrs; ++} ++ ++static grub_efi_ipv6_address_t * ++grub_dns_server_ip6_address (grub_efi_device_path_t *dp, grub_efi_uintn_t *num_dns) ++{ ++ grub_efi_handle_t hnd; ++ grub_efi_status_t status; ++ grub_efi_ip6_config_protocol_t *conf; ++ grub_efi_ipv6_address_t *addrs; ++ grub_efi_uintn_t data_size = 1 * sizeof (grub_efi_ipv6_address_t); ++ ++ hnd = grub_efi_locate_device_path (&ip6_config_guid, dp, NULL); ++ ++ if (!hnd) ++ return 0; ++ ++ conf = grub_efi_open_protocol (hnd, &ip6_config_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ ++ if (!conf) ++ return 0; ++ ++ addrs = grub_malloc (data_size); ++ if (!addrs) ++ return 0; ++ ++ status = efi_call_4 (conf->get_data, conf, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER, ++ &data_size, addrs); ++ ++ if (status == GRUB_EFI_BUFFER_TOO_SMALL) ++ { ++ grub_free (addrs); ++ addrs = grub_malloc (data_size); ++ if (!addrs) ++ return 0; ++ ++ status = efi_call_4 (conf->get_data, conf, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER, ++ &data_size, addrs); ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (addrs); ++ return 0; ++ } ++ ++ *num_dns = data_size / sizeof (grub_efi_ipv6_address_t); ++ return addrs; ++} ++ + static struct grub_net_buff * + grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *use_ipv6) + { +@@ -377,6 +498,8 @@ grub_efinet_create_dhcp_ack_from_device_ + grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) ldp; + struct grub_net_bootp_packet *bp; + grub_uint8_t *ptr; ++ grub_efi_ipv4_address_t *dns; ++ grub_efi_uintn_t num_dns; + + bp = (struct grub_net_bootp_packet *) nb->tail; + err = grub_netbuff_put (nb, sizeof (*bp) + 4); +@@ -438,6 +561,25 @@ grub_efinet_create_dhcp_ack_from_device_ + *ptr++ = sizeof ("HTTPClient") - 1; + grub_memcpy (ptr, "HTTPClient", sizeof ("HTTPClient") - 1); + ++ dns = grub_dns_server_ip4_address (dp, &num_dns); ++ if (dns) ++ { ++ grub_efi_uintn_t size_dns = sizeof (*dns) * num_dns; ++ ++ ptr = nb->tail; ++ err = grub_netbuff_put (nb, size_dns + 2); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ *ptr++ = GRUB_NET_BOOTP_DNS; ++ *ptr++ = size_dns; ++ grub_memcpy (ptr, dns, size_dns); ++ grub_free (dns); ++ } ++ + ptr = nb->tail; + err = grub_netbuff_put (nb, 1); + if (err) +@@ -470,6 +612,8 @@ grub_efinet_create_dhcp_ack_from_device_ + struct grub_net_dhcp6_option *opt; + struct grub_net_dhcp6_option_iana *iana; + struct grub_net_dhcp6_option_iaaddr *iaaddr; ++ grub_efi_ipv6_address_t *dns; ++ grub_efi_uintn_t num_dns; + + d6p = (struct grub_net_dhcp6_packet *)nb->tail; + err = grub_netbuff_put (nb, sizeof(*d6p)); +@@ -533,6 +677,25 @@ grub_efinet_create_dhcp_ack_from_device_ + opt->len = grub_cpu_to_be16 (uri_len); + grub_memcpy (opt->data, uri_dp->uri, uri_len); + ++ dns = grub_dns_server_ip6_address (dp, &num_dns); ++ if (dns) ++ { ++ grub_efi_uintn_t size_dns = sizeof (*dns) * num_dns; ++ ++ opt = (struct grub_net_dhcp6_option *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*opt) + size_dns); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_DNS_SERVERS); ++ opt->len = grub_cpu_to_be16 (size_dns); ++ grub_memcpy (opt->data, dns, size_dns); ++ grub_free (dns); ++ } ++ + *use_ipv6 = 1; + } + +Index: grub-2.06~rc1/include/grub/efi/api.h +=================================================================== +--- grub-2.06~rc1.orig/include/grub/efi/api.h ++++ grub-2.06~rc1/include/grub/efi/api.h +@@ -354,6 +354,16 @@ + { 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44 } \ + } + ++#define GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID \ ++ { 0x5b446ed1, 0xe30b, 0x4faa, \ ++ { 0x87, 0x1a, 0x36, 0x54, 0xec, 0xa3, 0x60, 0x80 } \ ++ } ++ ++#define GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID \ ++ { 0x937fe521, 0x95ae, 0x4d1a, \ ++ { 0x89, 0x29, 0x48, 0xbc, 0xd9, 0x0a, 0xd3, 0x1a } \ ++ } ++ + struct grub_efi_sal_system_table + { + grub_uint32_t signature; +@@ -1793,6 +1803,72 @@ struct grub_efi_rng_protocol + }; + typedef struct grub_efi_rng_protocol grub_efi_rng_protocol_t; + ++enum grub_efi_ip4_config2_data_type { ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_POLICY, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_GATEWAY, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MAXIMUM ++}; ++typedef enum grub_efi_ip4_config2_data_type grub_efi_ip4_config2_data_type_t; ++ ++struct grub_efi_ip4_config2_protocol ++{ ++ grub_efi_status_t (*set_data) (struct grub_efi_ip4_config2_protocol *this, ++ grub_efi_ip4_config2_data_type_t data_type, ++ grub_efi_uintn_t data_size, ++ void *data); ++ ++ grub_efi_status_t (*get_data) (struct grub_efi_ip4_config2_protocol *this, ++ grub_efi_ip4_config2_data_type_t data_type, ++ grub_efi_uintn_t *data_size, ++ void *data); ++ ++ grub_efi_status_t (*register_data_notify) (struct grub_efi_ip4_config2_protocol *this, ++ grub_efi_ip4_config2_data_type_t data_type, ++ grub_efi_event_t event); ++ ++ grub_efi_status_t (*unregister_datanotify) (struct grub_efi_ip4_config2_protocol *this, ++ grub_efi_ip4_config2_data_type_t data_type, ++ grub_efi_event_t event); ++}; ++typedef struct grub_efi_ip4_config2_protocol grub_efi_ip4_config2_protocol_t; ++ ++enum grub_efi_ip6_config_data_type { ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_ALT_INTERFACEID, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_POLICY, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DUP_ADDR_DETECT_TRANSMITS, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_GATEWAY, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MAXIMUM ++}; ++typedef enum grub_efi_ip6_config_data_type grub_efi_ip6_config_data_type_t; ++ ++struct grub_efi_ip6_config_protocol ++{ ++ grub_efi_status_t (*set_data) (struct grub_efi_ip6_config_protocol *this, ++ grub_efi_ip6_config_data_type_t data_type, ++ grub_efi_uintn_t data_size, ++ void *data); ++ ++ grub_efi_status_t (*get_data) (struct grub_efi_ip6_config_protocol *this, ++ grub_efi_ip6_config_data_type_t data_type, ++ grub_efi_uintn_t *data_size, ++ void *data); ++ ++ grub_efi_status_t (*register_data_notify) (struct grub_efi_ip6_config_protocol *this, ++ grub_efi_ip6_config_data_type_t data_type, ++ grub_efi_event_t event); ++ ++ grub_efi_status_t (*unregister_datanotify) (struct grub_efi_ip6_config_protocol *this, ++ grub_efi_ip6_config_data_type_t data_type, ++ grub_efi_event_t event); ++}; ++typedef struct grub_efi_ip6_config_protocol grub_efi_ip6_config_protocol_t; ++ + #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \ + || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) \ + || defined(__riscv) diff --git a/0008-fbutil-Fix-integer-overflow.patch b/0008-fbutil-Fix-integer-overflow.patch new file mode 100644 index 0000000..71b926f --- /dev/null +++ b/0008-fbutil-Fix-integer-overflow.patch @@ -0,0 +1,85 @@ +From 17e9006484e3da9a38a79f5f0f28f18a15fc4cf8 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Tue, 6 Sep 2022 03:03:21 +0800 +Subject: [PATCH 08/12] fbutil: Fix integer overflow + +Expressions like u64 = u32 * u32 are unsafe because their products are +truncated to u32 even if left hand side is u64. This patch fixes all +problems like that one in fbutil. + +To get right result not only left hand side have to be u64 but it's also +necessary to cast at least one of the operands of all leaf operators of +right hand side to u64, e.g. u64 = u32 * u32 + u32 * u32 should be +u64 = (u64)u32 * u32 + (u64)u32 * u32. + +For 1-bit bitmaps grub_uint64_t have to be used. It's safe because any +combination of values in (grub_uint64_t)u32 * u32 + u32 expression will +not overflow grub_uint64_t. + +Other expressions like ptr + u32 * u32 + u32 * u32 are also vulnerable. +They should be ptr + (grub_addr_t)u32 * u32 + (grub_addr_t)u32 * u32. + +This patch also adds a comment to grub_video_fb_get_video_ptr() which +says it's arguments must be valid and no sanity check is performed +(like its siblings in grub-core/video/fb/fbutil.c). + +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +--- + grub-core/video/fb/fbutil.c | 4 ++-- + include/grub/fbutil.h | 13 +++++++++---- + 2 files changed, 11 insertions(+), 6 deletions(-) + +diff --git a/grub-core/video/fb/fbutil.c b/grub-core/video/fb/fbutil.c +index b98bb51fe..25ef39f47 100644 +--- a/grub-core/video/fb/fbutil.c ++++ b/grub-core/video/fb/fbutil.c +@@ -67,7 +67,7 @@ get_pixel (struct grub_video_fbblit_info *source, + case 1: + if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED) + { +- int bit_index = y * source->mode_info->width + x; ++ grub_uint64_t bit_index = (grub_uint64_t) y * source->mode_info->width + x; + grub_uint8_t *ptr = source->data + bit_index / 8; + int bit_pos = 7 - bit_index % 8; + color = (*ptr >> bit_pos) & 0x01; +@@ -138,7 +138,7 @@ set_pixel (struct grub_video_fbblit_info *source, + case 1: + if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED) + { +- int bit_index = y * source->mode_info->width + x; ++ grub_uint64_t bit_index = (grub_uint64_t) y * source->mode_info->width + x; + grub_uint8_t *ptr = source->data + bit_index / 8; + int bit_pos = 7 - bit_index % 8; + *ptr = (*ptr & ~(1 << bit_pos)) | ((color & 0x01) << bit_pos); +diff --git a/include/grub/fbutil.h b/include/grub/fbutil.h +index 4205eb917..78a1ab3b4 100644 +--- a/include/grub/fbutil.h ++++ b/include/grub/fbutil.h +@@ -31,14 +31,19 @@ struct grub_video_fbblit_info + grub_uint8_t *data; + }; + +-/* Don't use for 1-bit bitmaps, addressing needs to be done at the bit level +- and it doesn't make sense, in general, to ask for a pointer +- to a particular pixel's data. */ ++/* ++ * Don't use for 1-bit bitmaps, addressing needs to be done at the bit level ++ * and it doesn't make sense, in general, to ask for a pointer ++ * to a particular pixel's data. ++ * ++ * This function assumes that bounds checking has been done in previous phase ++ * and they are opted out in here. ++ */ + static inline void * + grub_video_fb_get_video_ptr (struct grub_video_fbblit_info *source, + unsigned int x, unsigned int y) + { +- return source->data + y * source->mode_info->pitch + x * source->mode_info->bytes_per_pixel; ++ return source->data + (grub_addr_t) y * source->mode_info->pitch + (grub_addr_t) x * source->mode_info->bytes_per_pixel; + } + + /* Advance pointer by VAL bytes. If there is no unaligned access available, +-- +2.35.3 + diff --git a/0008-pgp-factor-out-rsa_pad.patch b/0008-pgp-factor-out-rsa_pad.patch new file mode 100644 index 0000000..e4a3187 --- /dev/null +++ b/0008-pgp-factor-out-rsa_pad.patch @@ -0,0 +1,194 @@ +From 923c8f6807cbd93b72d4dcb16c213d0d2a6b5b9a Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 1 Oct 2020 20:23:48 +1000 +Subject: [PATCH 08/23] pgp: factor out rsa_pad + +rsa_pad does the PKCS#1 v1.5 padding for the RSA signature scheme. +We want to use it in other RSA signature verification applications. + +I considered and rejected putting it in lib/crypto.c. That file doesn't +currently require any MPI functions, but rsa_pad does. That's not so +much of a problem for the grub kernel and modules, but crypto.c also +gets built into all the grub utilities. So - despite the utils not +using any asymmetric ciphers - we would need to built the entire MPI +infrastructure in to them. + +A better and simpler solution is just to spin rsa_pad out into its own +PKCS#1 v1.5 module. + +Signed-off-by: Daniel Axtens +--- + grub-core/Makefile.core.def | 8 +++++ + grub-core/commands/pgp.c | 28 ++---------------- + grub-core/lib/pkcs1_v15.c | 59 +++++++++++++++++++++++++++++++++++++ + include/grub/pkcs1_v15.h | 27 +++++++++++++++++ + 4 files changed, 96 insertions(+), 26 deletions(-) + create mode 100644 grub-core/lib/pkcs1_v15.c + create mode 100644 include/grub/pkcs1_v15.h + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 46a488131..5525aa194 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2504,6 +2504,14 @@ module = { + cppflags = '$(CPPFLAGS_GCRY)'; + }; + ++module = { ++ name = pkcs1_v15; ++ common = lib/pkcs1_v15.c; ++ ++ cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls -Wno-sign-compare'; ++ cppflags = '$(CPPFLAGS_GCRY)'; ++}; ++ + module = { + name = all_video; + common = lib/fake_module.c; +diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c +index 5daa1e9d0..2408db499 100644 +--- a/grub-core/commands/pgp.c ++++ b/grub-core/commands/pgp.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -411,32 +412,7 @@ static int + rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval, + const gcry_md_spec_t *hash, struct grub_public_subkey *sk) + { +- grub_size_t tlen, emlen, fflen; +- grub_uint8_t *em, *emptr; +- unsigned nbits = gcry_mpi_get_nbits (sk->mpis[0]); +- int ret; +- tlen = hash->mdlen + hash->asnlen; +- emlen = (nbits + 7) / 8; +- if (emlen < tlen + 11) +- return 1; +- +- em = grub_malloc (emlen); +- if (!em) +- return 1; +- +- em[0] = 0x00; +- em[1] = 0x01; +- fflen = emlen - tlen - 3; +- for (emptr = em + 2; emptr < em + 2 + fflen; emptr++) +- *emptr = 0xff; +- *emptr++ = 0x00; +- grub_memcpy (emptr, hash->asnoid, hash->asnlen); +- emptr += hash->asnlen; +- grub_memcpy (emptr, hval, hash->mdlen); +- +- ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0); +- grub_free (em); +- return ret; ++ return grub_crypto_rsa_pad(hmpi, hval, hash, sk->mpis[0]); + } + + struct grub_pubkey_context +diff --git a/grub-core/lib/pkcs1_v15.c b/grub-core/lib/pkcs1_v15.c +new file mode 100644 +index 000000000..dbacd563d +--- /dev/null ++++ b/grub-core/lib/pkcs1_v15.c +@@ -0,0 +1,59 @@ ++/* ++ * 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 . ++ */ ++ ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++/* ++ * Given a hash value 'hval', of hash specification 'hash', perform ++ * the EMSA-PKCS1-v1_5 padding suitable for a key with modulus 'mod' ++ * (see RFC 8017 s 9.2) and place the result in 'hmpi'. ++ */ ++gcry_err_code_t ++grub_crypto_rsa_pad (gcry_mpi_t * hmpi, grub_uint8_t * hval, ++ const gcry_md_spec_t * hash, gcry_mpi_t mod) ++{ ++ grub_size_t tlen, emlen, fflen; ++ grub_uint8_t *em, *emptr; ++ unsigned nbits = gcry_mpi_get_nbits (mod); ++ int ret; ++ tlen = hash->mdlen + hash->asnlen; ++ emlen = (nbits + 7) / 8; ++ if (emlen < tlen + 11) ++ return GPG_ERR_TOO_SHORT; ++ ++ em = grub_malloc (emlen); ++ if (!em) ++ return 1; ++ ++ em[0] = 0x00; ++ em[1] = 0x01; ++ fflen = emlen - tlen - 3; ++ for (emptr = em + 2; emptr < em + 2 + fflen; emptr++) ++ *emptr = 0xff; ++ *emptr++ = 0x00; ++ grub_memcpy (emptr, hash->asnoid, hash->asnlen); ++ emptr += hash->asnlen; ++ grub_memcpy (emptr, hval, hash->mdlen); ++ ++ ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0); ++ grub_free (em); ++ return ret; ++} +diff --git a/include/grub/pkcs1_v15.h b/include/grub/pkcs1_v15.h +new file mode 100644 +index 000000000..5c338c84a +--- /dev/null ++++ b/include/grub/pkcs1_v15.h +@@ -0,0 +1,27 @@ ++/* ++ * 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 . ++ */ ++ ++/* ++ * Given a hash value 'hval', of hash specification 'hash', perform ++ * the EMSA-PKCS1-v1_5 padding suitable for a key with modulus 'mod' ++ * (See RFC 8017 s 9.2) ++ */ ++gcry_err_code_t ++grub_crypto_rsa_pad (gcry_mpi_t * hmpi, grub_uint8_t * hval, ++ const gcry_md_spec_t * hash, gcry_mpi_t mod); ++ +-- +2.31.1 + diff --git a/0008-video-readers-png-Refuse-to-handle-multiple-image-he.patch b/0008-video-readers-png-Refuse-to-handle-multiple-image-he.patch new file mode 100644 index 0000000..13182f0 --- /dev/null +++ b/0008-video-readers-png-Refuse-to-handle-multiple-image-he.patch @@ -0,0 +1,31 @@ +From 2ca24e4cc44effd08fe6dfa05ad8417a9b186f42 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 6 Jul 2021 14:13:40 +1000 +Subject: [PATCH 08/32] video/readers/png: Refuse to handle multiple image + headers + +This causes the bitmap to be leaked. Do not permit multiple image headers. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/video/readers/png.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index d715c4629f..35ae553c8e 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -258,6 +258,9 @@ grub_png_decode_image_header (struct grub_png_data *data) + int color_bits; + enum grub_video_blit_format blt; + ++ if (data->image_width || data->image_height) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: two image headers found"); ++ + data->image_width = grub_png_get_dword (data); + data->image_height = grub_png_get_dword (data); + +-- +2.34.1 + diff --git a/0008-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch b/0008-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch new file mode 100644 index 0000000..c63d532 --- /dev/null +++ b/0008-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch @@ -0,0 +1,175 @@ +From 8fbcf9f2e97c98bdb63ae7d544aa9bb273022403 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Wed, 12 Sep 2018 16:12:27 -0400 +Subject: [PATCH 08/11] x86-efi: Allow initrd+params+cmdline allocations above + 4GB. + +This enables everything except the kernel itself to be above 4GB. +Putting the kernel up there still doesn't work, because of the way +params->code32_start is used. + +Signed-off-by: Peter Jones +--- + grub-core/loader/i386/efi/linux.c | 67 +++++++++++++++++++++++++++---- + include/grub/i386/linux.h | 6 ++- + 2 files changed, 65 insertions(+), 8 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index d284db5d1..d49749269 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -52,13 +52,22 @@ struct allocation_choice { + grub_efi_allocate_type_t alloc_type; + }; + +-static struct allocation_choice max_addresses[] = ++static struct allocation_choice max_addresses[4] = + { ++ /* the kernel overrides this one with pref_address and ++ * GRUB_EFI_ALLOCATE_ADDRESS */ + { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ /* this one is always below 4GB, which we still *prefer* even if the flag ++ * is set. */ + { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ /* If the flag in params is set, this one gets changed to be above 4GB. */ + { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, + { 0, 0 } + }; ++static struct allocation_choice saved_addresses[4]; ++ ++#define save_addresses() grub_memcpy(saved_addresses, max_addresses, sizeof(max_addresses)) ++#define restore_addresses() grub_memcpy(max_addresses, saved_addresses, sizeof(max_addresses)) + + static inline void + kernel_free(void *addr, grub_efi_uintn_t size) +@@ -80,6 +89,11 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) + grub_uint64_t max = max_addresses[i].addr; + grub_efi_uintn_t pages; + ++ /* ++ * When we're *not* loading the kernel, or >4GB allocations aren't ++ * supported, these entries are basically all the same, so don't re-try ++ * the same parameters. ++ */ + if (max == prev_max) + continue; + +@@ -168,6 +182,9 @@ read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len) + return bufpos; + } + ++#define LOW_U32(val) ((grub_uint32_t)(((grub_addr_t)(val)) & 0xffffffffull)) ++#define HIGH_U32(val) ((grub_uint32_t)(((grub_addr_t)(val) >> 32) & 0xffffffffull)) ++ + static grub_err_t + grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +@@ -208,8 +225,12 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + goto fail; + grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem); + +- params->ramdisk_size = size; +- params->ramdisk_image = initrd_mem; ++ params->ramdisk_size = LOW_U32(size); ++ params->ramdisk_image = LOW_U32(initrd_mem); ++#if defined(__x86_64__) ++ params->ext_ramdisk_size = HIGH_U32(size); ++ params->ext_ramdisk_image = HIGH_U32(initrd_mem); ++#endif + + ptr = initrd_mem; + +@@ -329,6 +350,18 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + #endif + ++#if defined(__x86_64__) ++ if (lh->xloadflags & LINUX_XLF_CAN_BE_LOADED_ABOVE_4G) ++ { ++ grub_dprintf ("linux", "Loading kernel above 4GB is supported; enabling.\n"); ++ max_addresses[2].addr = GRUB_EFI_MAX_USABLE_ADDRESS; ++ } ++ else ++ { ++ grub_dprintf ("linux", "Loading kernel above 4GB is not supported\n"); ++ } ++#endif ++ + params = kernel_alloc (sizeof(*params), "cannot allocate kernel parameters"); + if (!params) + goto fail; +@@ -365,21 +398,40 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline); + grub_dprintf ("linux", "setting lh->cmd_line_ptr to 0x%08x\n", +- linux_cmdline); +- lh->cmd_line_ptr = linux_cmdline; ++ LOW_U32(linux_cmdline)); ++ lh->cmd_line_ptr = LOW_U32(linux_cmdline); ++#if defined(__x86_64__) ++ if ((grub_efi_uintn_t)linux_cmdline > 0xffffffffull) ++ { ++ grub_dprintf ("linux", "setting params->ext_cmd_line_ptr to 0x%08x\n", ++ HIGH_U32(linux_cmdline)); ++ params->ext_cmd_line_ptr = HIGH_U32(linux_cmdline); ++ } ++#endif + + handover_offset = lh->handover_offset; + grub_dprintf("linux", "handover_offset: 0x%08x\n", handover_offset); + + start = (lh->setup_sects + 1) * 512; + ++ /* ++ * AFAICS >4GB for kernel *cannot* work because of params->code32_start being ++ * 32-bit and getting called unconditionally in head_64.S from either entry ++ * point. ++ * ++ * so nerf that out here... ++ */ ++ save_addresses(); + grub_dprintf ("linux", "lh->pref_address: %p\n", (void *)(grub_addr_t)lh->pref_address); + if (lh->pref_address < (grub_uint64_t)GRUB_EFI_MAX_ALLOCATION_ADDRESS) + { + max_addresses[0].addr = lh->pref_address; + max_addresses[0].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS; + } ++ max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; ++ max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; + kernel_mem = kernel_alloc (lh->init_size, N_("can't allocate kernel")); ++ restore_addresses(); + if (!kernel_mem) + goto fail; + grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem); +@@ -388,8 +440,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + loaded = 1; + +- grub_dprintf ("linux", "setting lh->code32_start to %p\n", kernel_mem); +- lh->code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem; ++ grub_dprintf ("linux", "setting lh->code32_start to 0x%08x\n", ++ LOW_U32(kernel_mem)); ++ lh->code32_start = LOW_U32(kernel_mem); + + grub_memcpy (kernel_mem, (char *)kernel + start, filelen - start); + +diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h +index 25ef52c04..fac22476c 100644 +--- a/include/grub/i386/linux.h ++++ b/include/grub/i386/linux.h +@@ -236,7 +236,11 @@ struct linux_kernel_params + grub_uint32_t ofw_cif_handler; /* b8 */ + grub_uint32_t ofw_idt; /* bc */ + +- grub_uint8_t padding7[0x1b8 - 0xc0]; ++ grub_uint32_t ext_ramdisk_image; /* 0xc0 */ ++ grub_uint32_t ext_ramdisk_size; /* 0xc4 */ ++ grub_uint32_t ext_cmd_line_ptr; /* 0xc8 */ ++ ++ grub_uint8_t padding7[0x1b8 - 0xcc]; + + union + { +-- +2.31.1 + diff --git a/0009-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch b/0009-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch new file mode 100644 index 0000000..1c5309b --- /dev/null +++ b/0009-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch @@ -0,0 +1,74 @@ +From def9a985bdb1a12db49be42b748b646abc156411 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 2 Oct 2020 10:49:26 +1000 +Subject: [PATCH 09/23] crypto: move storage for grub_crypto_pk_* to crypto.c + +The way gcry_rsa and friends (the asymmetric ciphers) are loaded for the +pgp module is a bit quirky. + +include/grub/crypto.h contains: + extern struct gcry_pk_spec *grub_crypto_pk_rsa; + +commands/pgp.c contains the actual storage: + struct gcry_pk_spec *grub_crypto_pk_rsa; + +And the module itself saves to the storage in pgp.c: + GRUB_MOD_INIT(gcry_rsa) + { + grub_crypto_pk_rsa = &_gcry_pubkey_spec_rsa; + } + +This is annoying: gcry_rsa now has a dependency on pgp! + +We want to be able to bring in gcry_rsa without bringing in PGP, +so move the storage to crypto.c. + +Previously, gcry_rsa depended on pgp and mpi. Now it depends on +crypto and mpi. As pgp depends on crypto, this doesn't add any new +module dependencies using the PGP verfier. + +[FWIW, the story is different for the symmetric ciphers. cryptodisk +and friends (zfs encryption etc) use grub_crypto_lookup_cipher_by_name() +to get a cipher handle. That depends on grub_ciphers being populated +by people calling grub_cipher_register. import_gcry.py ensures that the +symmetric ciphers call it.] + +Signed-off-by: Daniel Axtens +--- + grub-core/commands/pgp.c | 4 ---- + grub-core/lib/crypto.c | 4 ++++ + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c +index 2408db499..355a43844 100644 +--- a/grub-core/commands/pgp.c ++++ b/grub-core/commands/pgp.c +@@ -147,10 +147,6 @@ const char *hashes[] = { + [0x0b] = "sha224" + }; + +-struct gcry_pk_spec *grub_crypto_pk_dsa; +-struct gcry_pk_spec *grub_crypto_pk_ecdsa; +-struct gcry_pk_spec *grub_crypto_pk_rsa; +- + static int + dsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval, + const gcry_md_spec_t *hash, struct grub_public_subkey *sk); +diff --git a/grub-core/lib/crypto.c b/grub-core/lib/crypto.c +index ca334d5a4..c578128a5 100644 +--- a/grub-core/lib/crypto.c ++++ b/grub-core/lib/crypto.c +@@ -121,6 +121,10 @@ grub_md_unregister (gcry_md_spec_t *cipher) + } + } + ++struct gcry_pk_spec *grub_crypto_pk_dsa; ++struct gcry_pk_spec *grub_crypto_pk_ecdsa; ++struct gcry_pk_spec *grub_crypto_pk_rsa; ++ + void + grub_crypto_hash (const gcry_md_spec_t *hash, void *out, const void *in, + grub_size_t inlen) +-- +2.31.1 + diff --git a/0009-cryptodisk-Improve-handling-of-partition-name-in-cry.patch b/0009-cryptodisk-Improve-handling-of-partition-name-in-cry.patch new file mode 100644 index 0000000..3159fb4 --- /dev/null +++ b/0009-cryptodisk-Improve-handling-of-partition-name-in-cry.patch @@ -0,0 +1,39 @@ +From b1acd971fa648fa3c6f3a54db4fdf45fae02ce54 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:58 -0600 +Subject: [PATCH 09/14] cryptodisk: Improve handling of partition name in + cryptomount password prompt + +Call grub_partition_get_name() unconditionally to initialize the part +variable. Then part will only be NULL when grub_partition_get_name() errors. +Note that when source->partition is NULL, then grub_partition_get_name() +returns an allocated empty string. So no comma or partition will be printed, +as desired. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 7ca880402d..497097394f 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -1021,11 +1021,10 @@ grub_cryptodisk_scan_device_real (const char *name, + { + /* Get the passphrase from the user, if no key data. */ + askpass = 1; +- if (source->partition != NULL) +- part = grub_partition_get_name (source->partition); ++ part = grub_partition_get_name (source->partition); + grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, + source->partition != NULL ? "," : "", +- part != NULL ? part : "", ++ part != NULL ? part : N_("UNKNOWN"), + dev->uuid); + grub_free (part); + +-- +2.34.1 + diff --git a/0009-font-Fix-an-integer-underflow-in-blit_comb.patch b/0009-font-Fix-an-integer-underflow-in-blit_comb.patch new file mode 100644 index 0000000..624e87b --- /dev/null +++ b/0009-font-Fix-an-integer-underflow-in-blit_comb.patch @@ -0,0 +1,91 @@ +From 79924f56f5062c1bae972fd6cd8f38e56980f34d Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Mon, 24 Oct 2022 08:05:35 +0800 +Subject: [PATCH 09/12] font: Fix an integer underflow in blit_comb() + +The expression (ctx.bounds.height - combining_glyphs[i]->height) / 2 may +evaluate to a very big invalid value even if both ctx.bounds.height and +combining_glyphs[i]->height are small integers. For example, if +ctx.bounds.height is 10 and combining_glyphs[i]->height is 12, this +expression evaluates to 2147483647 (expected -1). This is because +coordinates are allowed to be negative but ctx.bounds.height is an +unsigned int. So, the subtraction operates on unsigned ints and +underflows to a very big value. The division makes things even worse. +The quotient is still an invalid value even if converted back to int. + +This patch fixes the problem by casting ctx.bounds.height to int. As +a result the subtraction will operate on int and grub_uint16_t which +will be promoted to an int. So, the underflow will no longer happen. Other +uses of ctx.bounds.height (and ctx.bounds.width) are also casted to int, +to ensure coordinates are always calculated on signed integers. + +Fixes: CVE-2022-3775 + +Reported-by: Daniel Axtens +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +--- + grub-core/font/font.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index 193dfec04..12a5f0d08 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -1203,12 +1203,12 @@ blit_comb (const struct grub_unicode_glyph *glyph_id, + ctx.bounds.height = main_glyph->height; + + above_rightx = main_glyph->offset_x + main_glyph->width; +- above_righty = ctx.bounds.y + ctx.bounds.height; ++ above_righty = ctx.bounds.y + (int) ctx.bounds.height; + + above_leftx = main_glyph->offset_x; +- above_lefty = ctx.bounds.y + ctx.bounds.height; ++ above_lefty = ctx.bounds.y + (int) ctx.bounds.height; + +- below_rightx = ctx.bounds.x + ctx.bounds.width; ++ below_rightx = ctx.bounds.x + (int) ctx.bounds.width; + below_righty = ctx.bounds.y; + + comb = grub_unicode_get_comb (glyph_id); +@@ -1221,7 +1221,7 @@ blit_comb (const struct grub_unicode_glyph *glyph_id, + + if (!combining_glyphs[i]) + continue; +- targetx = (ctx.bounds.width - combining_glyphs[i]->width) / 2 + ctx.bounds.x; ++ targetx = ((int) ctx.bounds.width - combining_glyphs[i]->width) / 2 + ctx.bounds.x; + /* CGJ is to avoid diacritics reordering. */ + if (comb[i].code + == GRUB_UNICODE_COMBINING_GRAPHEME_JOINER) +@@ -1231,8 +1231,8 @@ blit_comb (const struct grub_unicode_glyph *glyph_id, + case GRUB_UNICODE_COMB_OVERLAY: + do_blit (combining_glyphs[i], + targetx, +- (ctx.bounds.height - combining_glyphs[i]->height) / 2 +- - (ctx.bounds.height + ctx.bounds.y), &ctx); ++ ((int) ctx.bounds.height - combining_glyphs[i]->height) / 2 ++ - ((int) ctx.bounds.height + ctx.bounds.y), &ctx); + if (min_devwidth < combining_glyphs[i]->width) + min_devwidth = combining_glyphs[i]->width; + break; +@@ -1305,7 +1305,7 @@ blit_comb (const struct grub_unicode_glyph *glyph_id, + /* Fallthrough. */ + case GRUB_UNICODE_STACK_ATTACHED_ABOVE: + do_blit (combining_glyphs[i], targetx, +- -(ctx.bounds.height + ctx.bounds.y + space ++ -((int) ctx.bounds.height + ctx.bounds.y + space + + combining_glyphs[i]->height), &ctx); + if (min_devwidth < combining_glyphs[i]->width) + min_devwidth = combining_glyphs[i]->width; +@@ -1313,7 +1313,7 @@ blit_comb (const struct grub_unicode_glyph *glyph_id, + + case GRUB_UNICODE_COMB_HEBREW_DAGESH: + do_blit (combining_glyphs[i], targetx, +- -(ctx.bounds.height / 2 + ctx.bounds.y ++ -((int) ctx.bounds.height / 2 + ctx.bounds.y + + combining_glyphs[i]->height / 2), &ctx); + if (min_devwidth < combining_glyphs[i]->width) + min_devwidth = combining_glyphs[i]->width; +-- +2.35.3 + diff --git a/0009-video-readers-png-Drop-greyscale-support-to-fix-heap.patch b/0009-video-readers-png-Drop-greyscale-support-to-fix-heap.patch new file mode 100644 index 0000000..070bcb7 --- /dev/null +++ b/0009-video-readers-png-Drop-greyscale-support-to-fix-heap.patch @@ -0,0 +1,171 @@ +From 7be3f3b1b7be0602056721526878c91d3333f8fd Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 6 Jul 2021 18:51:35 +1000 +Subject: [PATCH 09/32] video/readers/png: Drop greyscale support to fix heap + out-of-bounds write + +A 16-bit greyscale PNG without alpha is processed in the following loop: + + for (i = 0; i < (data->image_width * data->image_height); + i++, d1 += 4, d2 += 2) + { + d1[R3] = d2[1]; + d1[G3] = d2[1]; + d1[B3] = d2[1]; + } + +The increment of d1 is wrong. d1 is incremented by 4 bytes per iteration, +but there are only 3 bytes allocated for storage. This means that image +data will overwrite somewhat-attacker-controlled parts of memory - 3 bytes +out of every 4 following the end of the image. + +This has existed since greyscale support was added in 2013 in commit +3ccf16dff98f (grub-core/video/readers/png.c: Support grayscale). + +Saving starfield.png as a 16-bit greyscale image without alpha in the gimp +and attempting to load it causes grub-emu to crash - I don't think this code +has ever worked. + +Delete all PNG greyscale support. + +Fixes: CVE-2021-3695 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/video/readers/png.c | 87 +++-------------------------------- + 1 file changed, 7 insertions(+), 80 deletions(-) + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index 35ae553c8e..a3161e25b6 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -100,7 +100,7 @@ struct grub_png_data + + unsigned image_width, image_height; + int bpp, is_16bit; +- int raw_bytes, is_gray, is_alpha, is_palette; ++ int raw_bytes, is_alpha, is_palette; + int row_bytes, color_bits; + grub_uint8_t *image_data; + +@@ -296,13 +296,13 @@ grub_png_decode_image_header (struct grub_png_data *data) + data->bpp = 3; + else + { +- data->is_gray = 1; +- data->bpp = 1; ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "png: color type not supported"); + } + + if ((color_bits != 8) && (color_bits != 16) + && (color_bits != 4 +- || !(data->is_gray || data->is_palette))) ++ || !data->is_palette)) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "png: bit depth must be 8 or 16"); + +@@ -331,7 +331,7 @@ grub_png_decode_image_header (struct grub_png_data *data) + } + + #ifndef GRUB_CPU_WORDS_BIGENDIAN +- if (data->is_16bit || data->is_gray || data->is_palette) ++ if (data->is_16bit || data->is_palette) + #endif + { + data->image_data = grub_calloc (data->image_height, data->row_bytes); +@@ -899,27 +899,8 @@ grub_png_convert_image (struct grub_png_data *data) + int shift; + int mask = (1 << data->color_bits) - 1; + unsigned j; +- if (data->is_gray) +- { +- /* Generic formula is +- (0xff * i) / ((1U << data->color_bits) - 1) +- but for allowed bit depth of 1, 2 and for it's +- equivalent to +- (0xff / ((1U << data->color_bits) - 1)) * i +- Precompute the multipliers to avoid division. +- */ +- +- const grub_uint8_t multipliers[5] = { 0xff, 0xff, 0x55, 0x24, 0x11 }; +- for (i = 0; i < (1U << data->color_bits); i++) +- { +- grub_uint8_t col = multipliers[data->color_bits] * i; +- palette[i][0] = col; +- palette[i][1] = col; +- palette[i][2] = col; +- } +- } +- else +- grub_memcpy (palette, data->palette, 3 << data->color_bits); ++ ++ grub_memcpy (palette, data->palette, 3 << data->color_bits); + d1c = d1; + d2c = d2; + for (j = 0; j < data->image_height; j++, d1c += data->image_width * 3, +@@ -957,60 +938,6 @@ grub_png_convert_image (struct grub_png_data *data) + return; + } + +- if (data->is_gray) +- { +- switch (data->bpp) +- { +- case 4: +- /* 16-bit gray with alpha. */ +- for (i = 0; i < (data->image_width * data->image_height); +- i++, d1 += 4, d2 += 4) +- { +- d1[R4] = d2[3]; +- d1[G4] = d2[3]; +- d1[B4] = d2[3]; +- d1[A4] = d2[1]; +- } +- break; +- case 2: +- if (data->is_16bit) +- /* 16-bit gray without alpha. */ +- { +- for (i = 0; i < (data->image_width * data->image_height); +- i++, d1 += 4, d2 += 2) +- { +- d1[R3] = d2[1]; +- d1[G3] = d2[1]; +- d1[B3] = d2[1]; +- } +- } +- else +- /* 8-bit gray with alpha. */ +- { +- for (i = 0; i < (data->image_width * data->image_height); +- i++, d1 += 4, d2 += 2) +- { +- d1[R4] = d2[1]; +- d1[G4] = d2[1]; +- d1[B4] = d2[1]; +- d1[A4] = d2[0]; +- } +- } +- break; +- /* 8-bit gray without alpha. */ +- case 1: +- for (i = 0; i < (data->image_width * data->image_height); +- i++, d1 += 3, d2++) +- { +- d1[R3] = d2[0]; +- d1[G3] = d2[0]; +- d1[B3] = d2[0]; +- } +- break; +- } +- return; +- } +- + { + /* Only copy the upper 8 bit. */ + #ifndef GRUB_CPU_WORDS_BIGENDIAN +-- +2.34.1 + diff --git a/0009-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch b/0009-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch new file mode 100644 index 0000000..a2bd82f --- /dev/null +++ b/0009-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch @@ -0,0 +1,43 @@ +From a89b55330ff0930c998cf64ab534cd8ff7e3a74c Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Tue, 26 May 2020 16:59:28 +0200 +Subject: [PATCH 09/11] x86-efi: Reduce maximum bounce buffer size to 16 MiB + +The EFI linux loader allocates a bounce buffer to copy the initrd since in +some machines doing DMA on addresses above 4GB is not possible during EFI. + +But the verifiers framework also allocates a buffer to copy the initrd in +its grub_file_open() handler. It does this since the data to verify has to +be passed as a single chunk to modules that use the verifiers framework. + +If the initrd image size is big there may not be enough memory in the heap +to allocate two buffers of that size. This causes an allocation failure in +the verifiers framework and leads to the initrd not being read. + +To prevent these allocation failures, let's reduce the maximum size of the +bounce buffer used in the EFI loader. Since the data read can be copied to +the actual initrd address in multilple chunks. + +Resolves: rhbz#1838633 + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/loader/i386/efi/linux.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index d49749269..652212227 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -144,7 +144,7 @@ grub_linuxefi_unload (void) + return GRUB_ERR_NONE; + } + +-#define BOUNCE_BUFFER_MAX 0x10000000ull ++#define BOUNCE_BUFFER_MAX 0x1000000ull + + static grub_ssize_t + read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len) +-- +2.31.1 + diff --git a/0010-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch b/0010-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch new file mode 100644 index 0000000..3a5e5c2 --- /dev/null +++ b/0010-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch @@ -0,0 +1,52 @@ +From 1fc593b372bfe9bba82f4c59236d5a0cffebd8e2 Mon Sep 17 00:00:00 2001 +From: Colin Watson +Date: Fri, 24 Jul 2020 17:18:09 +0100 +Subject: [PATCH 10/11] efilinux: Fix integer overflows in grub_cmd_initrd + +These could be triggered by an extremely large number of arguments to +the initrd command on 32-bit architectures, or a crafted filesystem with +very large files on any architecture. + +Signed-off-by: Colin Watson +--- + grub-core/loader/i386/efi/linux.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 652212227..6b06a8f2f 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -28,6 +28,8 @@ + #include + #include + #include ++#include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -206,7 +208,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- files = grub_zalloc (argc * sizeof (files[0])); ++ files = grub_calloc (argc, sizeof (files[0])); + if (!files) + goto fail; + +@@ -217,7 +219,11 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + if (! files[i]) + goto fail; + nfiles++; +- size += ALIGN_UP (grub_file_size (files[i]), 4); ++ if (grub_add (size, ALIGN_UP (grub_file_size (files[i]), 4), &size)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); ++ goto fail; ++ } + } + + initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); +-- +2.31.1 + diff --git a/0010-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch b/0010-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch new file mode 100644 index 0000000..78fe462 --- /dev/null +++ b/0010-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch @@ -0,0 +1,75 @@ +From f3b30e0d782f36634a9a7ab9d18851b0b7a1bce5 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Mon, 24 Oct 2022 07:15:41 +0800 +Subject: [PATCH 10/12] font: Harden grub_font_blit_glyph() and + grub_font_blit_glyph_mirror() + +As a mitigation and hardening measure add sanity checks to +grub_font_blit_glyph() and grub_font_blit_glyph_mirror(). This patch +makes these two functions do nothing if target blitting area isn't fully +contained in target bitmap. Therefore, if complex calculations in caller +overflows and malicious coordinates are given, we are still safe because +any coordinates which result in out-of-bound-write are rejected. However, +this patch only checks for invalid coordinates, and doesn't provide any +protection against invalid source glyph or destination glyph, e.g. +mismatch between glyph size and buffer size. + +This hardening measure is designed to mitigate possible overflows in +blit_comb(). If overflow occurs, it may return invalid bounding box +during dry run and call grub_font_blit_glyph() with malicious +coordinates during actual blitting. However, we are still safe because +the scratch glyph itself is valid, although its size makes no sense, and +any invalid coordinates are rejected. + +It would be better to call grub_fatal() if illegal parameter is detected. +However, doing this may end up in a dangerous recursion because grub_fatal() +would print messages to the screen and we are in the progress of drawing +characters on the screen. + +Reported-by: Daniel Axtens +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +--- + grub-core/font/font.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index 12a5f0d08..29fbb9429 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -1069,8 +1069,15 @@ static void + grub_font_blit_glyph (struct grub_font_glyph *target, + struct grub_font_glyph *src, unsigned dx, unsigned dy) + { ++ grub_uint16_t max_x, max_y; + unsigned src_bit, tgt_bit, src_byte, tgt_byte; + unsigned i, j; ++ ++ /* Harden against out-of-bound writes. */ ++ if ((grub_add (dx, src->width, &max_x) || max_x > target->width) || ++ (grub_add (dy, src->height, &max_y) || max_y > target->height)) ++ return; ++ + for (i = 0; i < src->height; i++) + { + src_bit = (src->width * i) % 8; +@@ -1102,9 +1109,16 @@ grub_font_blit_glyph_mirror (struct grub_font_glyph *target, + struct grub_font_glyph *src, + unsigned dx, unsigned dy) + { ++ grub_uint16_t max_x, max_y; + unsigned tgt_bit, src_byte, tgt_byte; + signed src_bit; + unsigned i, j; ++ ++ /* Harden against out-of-bound writes. */ ++ if ((grub_add (dx, src->width, &max_x) || max_x > target->width) || ++ (grub_add (dy, src->height, &max_y) || max_y > target->height)) ++ return; ++ + for (i = 0; i < src->height; i++) + { + src_bit = (src->width * i + src->width - 1) % 8; +-- +2.35.3 + diff --git a/0010-posix_wrap-tweaks-in-preparation-for-libtasn1.patch b/0010-posix_wrap-tweaks-in-preparation-for-libtasn1.patch new file mode 100644 index 0000000..70c3be8 --- /dev/null +++ b/0010-posix_wrap-tweaks-in-preparation-for-libtasn1.patch @@ -0,0 +1,67 @@ +From fa3436ad10a63d5ad3d27cc330fb2594e699cc34 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Sat, 2 May 2020 00:27:57 +1000 +Subject: [PATCH 10/23] posix_wrap: tweaks in preparation for libtasn1 + + - Define SIZEOF_UNSIGNED_LONG_INT, it's the same as + SIZEOF_UNSIGNED_LONG. + + - Define WORD_BIT, the size in bits of an int. This is a defined + in the Single Unix Specification and in gnulib's limits.h. gnulib + assumes it's 32 bits on all our platforms, including 64 bit + platforms, so we also use that value. + + - Provide strto[u]l[l] preprocessor macros that resolve to + grub_strto[u]l[l]. To avoid gcrypt redefining strtoul, we + also define HAVE_STRTOUL here. + +Signed-off-by: Daniel Axtens +--- + grub-core/lib/posix_wrap/limits.h | 1 + + grub-core/lib/posix_wrap/stdlib.h | 8 ++++++++ + grub-core/lib/posix_wrap/sys/types.h | 1 + + 3 files changed, 10 insertions(+) + +diff --git a/grub-core/lib/posix_wrap/limits.h b/grub-core/lib/posix_wrap/limits.h +index 7217138ff..591dbf328 100644 +--- a/grub-core/lib/posix_wrap/limits.h ++++ b/grub-core/lib/posix_wrap/limits.h +@@ -37,5 +37,6 @@ + #define LONG_MAX GRUB_LONG_MAX + + #define CHAR_BIT 8 ++#define WORD_BIT 32 + + #endif +diff --git a/grub-core/lib/posix_wrap/stdlib.h b/grub-core/lib/posix_wrap/stdlib.h +index 7a8d385e9..4634db09f 100644 +--- a/grub-core/lib/posix_wrap/stdlib.h ++++ b/grub-core/lib/posix_wrap/stdlib.h +@@ -58,4 +58,12 @@ abs (int c) + return (c >= 0) ? c : -c; + } + ++#define strtol grub_strtol ++ ++/* for libgcrypt */ ++#define HAVE_STRTOUL ++#define strtoul grub_strtoul ++ ++#define strtoull grub_strtoull ++ + #endif +diff --git a/grub-core/lib/posix_wrap/sys/types.h b/grub-core/lib/posix_wrap/sys/types.h +index 854eb0122..f63412c8d 100644 +--- a/grub-core/lib/posix_wrap/sys/types.h ++++ b/grub-core/lib/posix_wrap/sys/types.h +@@ -51,6 +51,7 @@ typedef grub_uint8_t byte; + typedef grub_addr_t uintptr_t; + + #define SIZEOF_UNSIGNED_LONG GRUB_CPU_SIZEOF_LONG ++#define SIZEOF_UNSIGNED_LONG_INT GRUB_CPU_SIZEOF_LONG + #define SIZEOF_UNSIGNED_INT 4 + #define SIZEOF_UNSIGNED_LONG_LONG 8 + #define SIZEOF_UNSIGNED_SHORT 2 +-- +2.31.1 + diff --git a/0010-protectors-Add-key-protectors-framework.patch b/0010-protectors-Add-key-protectors-framework.patch new file mode 100644 index 0000000..08f3ea1 --- /dev/null +++ b/0010-protectors-Add-key-protectors-framework.patch @@ -0,0 +1,189 @@ +From 2d959549857305d5e4d95a19a0850885f85179d6 Mon Sep 17 00:00:00 2001 +From: Hernan Gatta +Date: Tue, 1 Feb 2022 05:02:53 -0800 +Subject: [PATCH 10/14] protectors: Add key protectors framework + +A key protector encapsulates functionality to retrieve an unlocking key for a +fully-encrypted disk from a specific source. A key protector module registers +itself with the key protectors framework when it is loaded and unregisters when +unloaded. Additionally, a key protector may accept parameters that describe how +it should operate. + +The key protectors framework, besides offering registration and unregistration +functions, also offers a one-stop routine for finding and invoking a key +protector by name. If a key protector with the specified name exists and if an +unlocking key is successfully retrieved by it, the function returns to the +caller the retrieved key and its length. + +Signed-off-by: Hernan Gatta +--- + grub-core/Makefile.am | 1 + + grub-core/Makefile.core.def | 1 + + grub-core/kern/protectors.c | 75 +++++++++++++++++++++++++++++++++++++ + include/grub/protector.h | 48 ++++++++++++++++++++++++ + 4 files changed, 125 insertions(+) + create mode 100644 grub-core/kern/protectors.c + create mode 100644 include/grub/protector.h + +diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am +index de241f0d04..dc07ba6f87 100644 +--- a/grub-core/Makefile.am ++++ b/grub-core/Makefile.am +@@ -90,6 +90,7 @@ endif + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/mm.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/parser.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/partition.h ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/protector.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/stack_protector.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/term.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/time.h +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index f3140815b8..b0001a33cf 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -138,6 +138,7 @@ kernel = { + common = kern/misc.c; + common = kern/parser.c; + common = kern/partition.c; ++ common = kern/protectors.c; + common = kern/rescue_parser.c; + common = kern/rescue_reader.c; + common = kern/term.c; +diff --git a/grub-core/kern/protectors.c b/grub-core/kern/protectors.c +new file mode 100644 +index 0000000000..21954dfa48 +--- /dev/null ++++ b/grub-core/kern/protectors.c +@@ -0,0 +1,75 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * 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 . ++ */ ++ ++#include ++#include ++#include ++#include ++ ++struct grub_key_protector *grub_key_protectors = NULL; ++ ++grub_err_t ++grub_key_protector_register (struct grub_key_protector *protector) ++{ ++ if (!protector || !protector->name || !grub_strlen(protector->name)) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ if (grub_key_protectors && ++ grub_named_list_find (GRUB_AS_NAMED_LIST (grub_key_protectors), ++ protector->name)) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ grub_list_push (GRUB_AS_LIST_P (&grub_key_protectors), ++ GRUB_AS_LIST (protector)); ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_key_protector_unregister (struct grub_key_protector *protector) ++{ ++ if (!protector) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ grub_list_remove (GRUB_AS_LIST (protector)); ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_key_protector_recover_key (const char *protector, grub_uint8_t **key, ++ grub_size_t *key_size) ++{ ++ struct grub_key_protector *kp = NULL; ++ ++ if (!grub_key_protectors) ++ return GRUB_ERR_OUT_OF_RANGE; ++ ++ if (!protector || !grub_strlen (protector)) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ kp = grub_named_list_find (GRUB_AS_NAMED_LIST (grub_key_protectors), ++ protector); ++ if (!kp) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("A key protector with name '%s' could not be found. " ++ "Is the name spelled correctly and is the " ++ "corresponding module loaded?"), protector); ++ ++ return kp->recover_key (key, key_size); ++} +diff --git a/include/grub/protector.h b/include/grub/protector.h +new file mode 100644 +index 0000000000..179020a344 +--- /dev/null ++++ b/include/grub/protector.h +@@ -0,0 +1,48 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * 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 . ++ */ ++ ++#ifndef GRUB_PROTECTOR_HEADER ++#define GRUB_PROTECTOR_HEADER 1 ++ ++#include ++#include ++ ++struct grub_key_protector ++{ ++ struct grub_key_protector *next; ++ struct grub_key_protector **prev; ++ ++ const char *name; ++ ++ grub_err_t (*recover_key) (grub_uint8_t **key, grub_size_t *key_size); ++}; ++ ++extern struct grub_key_protector *EXPORT_VAR (grub_key_protectors); ++ ++grub_err_t ++EXPORT_FUNC (grub_key_protector_register) (struct grub_key_protector *protector); ++ ++grub_err_t ++EXPORT_FUNC (grub_key_protector_unregister) (struct grub_key_protector *protector); ++ ++grub_err_t ++EXPORT_FUNC (grub_key_protector_recover_key) (const char *protector, ++ grub_uint8_t **key, ++ grub_size_t *key_size); ++ ++#endif /* ! GRUB_PROTECTOR_HEADER */ +-- +2.34.1 + diff --git a/0010-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch b/0010-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch new file mode 100644 index 0000000..389922d --- /dev/null +++ b/0010-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch @@ -0,0 +1,42 @@ +From 8ebb6943eae81d3c31963bbae42d5d1f168c8dd5 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 6 Jul 2021 23:25:07 +1000 +Subject: [PATCH 10/32] video/readers/png: Avoid heap OOB R/W inserting huff + table items + +In fuzzing we observed crashes where a code would attempt to be inserted +into a huffman table before the start, leading to a set of heap OOB reads +and writes as table entries with negative indices were shifted around and +the new code written in. + +Catch the case where we would underflow the array and bail. + +Fixes: CVE-2021-3696 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/video/readers/png.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index a3161e25b6..d7ed5aa6cf 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -438,6 +438,13 @@ grub_png_insert_huff_item (struct huff_table *ht, int code, int len) + for (i = len; i < ht->max_length; i++) + n += ht->maxval[i]; + ++ if (n > ht->num_values) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "png: out of range inserting huffman table item"); ++ return; ++ } ++ + for (i = 0; i < n; i++) + ht->values[ht->num_values - i] = ht->values[ht->num_values - i - 1]; + +-- +2.34.1 + diff --git a/0011-Also-define-GRUB_EFI_MAX_ALLOCATION_ADDRESS-for-RISC.patch b/0011-Also-define-GRUB_EFI_MAX_ALLOCATION_ADDRESS-for-RISC.patch new file mode 100644 index 0000000..dc84300 --- /dev/null +++ b/0011-Also-define-GRUB_EFI_MAX_ALLOCATION_ADDRESS-for-RISC.patch @@ -0,0 +1,27 @@ +From 76caed15754338f7261b2a95a3c7cc15a25f6a01 Mon Sep 17 00:00:00 2001 +From: David Abdurachmanov +Date: Thu, 16 Jan 2020 13:10:10 +0100 +Subject: [PATCH 11/11] Also define GRUB_EFI_MAX_ALLOCATION_ADDRESS for RISC-V + +The commit "Try to pick better locations for kernel and initrd" missed to +define this macro for the RISC-V (riscv64) architecture, so add it there. + +Signed-off-by: David Abdurachmanov +--- + include/grub/riscv64/efi/memory.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/grub/riscv64/efi/memory.h b/include/grub/riscv64/efi/memory.h +index c6cb32417..acb61dca4 100644 +--- a/include/grub/riscv64/efi/memory.h ++++ b/include/grub/riscv64/efi/memory.h +@@ -2,5 +2,6 @@ + #include + + #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffffffffULL ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +-- +2.31.1 + diff --git a/0011-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch b/0011-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch new file mode 100644 index 0000000..d8fe4c4 --- /dev/null +++ b/0011-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch @@ -0,0 +1,36 @@ +From bcda6538ffeb516987a1921fbe533aaf8b8c981b Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Fri, 28 Oct 2022 17:29:16 +0800 +Subject: [PATCH 11/12] font: Assign null_font to glyphs in ascii_font_glyph[] + +The calculations in blit_comb() need information from glyph's font, e.g. +grub_font_get_xheight(main_glyph->font). However, main_glyph->font is +NULL if main_glyph comes from ascii_font_glyph[]. Therefore +grub_font_get_*() crashes because of NULL pointer. + +There is already a solution, the null_font. So, assign it to those glyphs +in ascii_font_glyph[]. + +Reported-by: Daniel Axtens +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +--- + grub-core/font/font.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index 29fbb9429..e6616e610 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -137,7 +137,7 @@ ascii_glyph_lookup (grub_uint32_t code) + ascii_font_glyph[current]->offset_x = 0; + ascii_font_glyph[current]->offset_y = -2; + ascii_font_glyph[current]->device_width = 8; +- ascii_font_glyph[current]->font = NULL; ++ ascii_font_glyph[current]->font = &null_font; + + grub_memcpy (ascii_font_glyph[current]->bitmap, + &ascii_bitmaps[current * ASCII_BITMAP_SIZE], +-- +2.35.3 + diff --git a/0011-libtasn1-import-libtasn1-4.18.0.patch b/0011-libtasn1-import-libtasn1-4.18.0.patch new file mode 100644 index 0000000..9e1d7e9 --- /dev/null +++ b/0011-libtasn1-import-libtasn1-4.18.0.patch @@ -0,0 +1,9044 @@ +From c3a6fbeb436470aff90a63bb98444eb897fbe2f6 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Wed, 10 Jun 2020 16:31:22 +1000 +Subject: [PATCH 11/23] libtasn1: import libtasn1-4.18.0 + +Import a very trimmed-down set of libtasn1 files: + +pushd /tmp +wget https://ftp.gnu.org/gnu/libtasn1/libtasn1-4.18.0.tar.gz +tar -xf libtasn1-4.18.0.tar.gz +popd +pushd grub-core/lib +rm -rf libtasn1 +mkdir libtasn1 +cp /tmp/libtasn1-4.18.0/{README.md,COPYING} libtasn1/ +mkdir libtasn1/lib +cp /tmp/libtasn1-4.18.0/lib/{coding.c,decoding.c,element.c,element.h,errors.c,gstr.c,gstr.h,int.h,parser_aux.c,parser_aux.h,structure.c,structure.h} libtasn1/lib +cp /tmp/libtasn1-4.18.0/lib/includes/libtasn1.h ../../include/grub/ +git add libtasn1/ ../../include/grub/libtasn1.h +popd + +Signed-off-by: Daniel Axtens +--- + grub-core/lib/libtasn1/COPYING | 16 + + grub-core/lib/libtasn1/README.md | 98 + + grub-core/lib/libtasn1/lib/coding.c | 1425 +++++++++++++ + grub-core/lib/libtasn1/lib/decoding.c | 2501 +++++++++++++++++++++++ + grub-core/lib/libtasn1/lib/element.c | 1109 ++++++++++ + grub-core/lib/libtasn1/lib/element.h | 42 + + grub-core/lib/libtasn1/lib/errors.c | 100 + + grub-core/lib/libtasn1/lib/gstr.c | 74 + + grub-core/lib/libtasn1/lib/gstr.h | 50 + + grub-core/lib/libtasn1/lib/int.h | 221 ++ + grub-core/lib/libtasn1/lib/parser_aux.c | 1178 +++++++++++ + grub-core/lib/libtasn1/lib/parser_aux.h | 172 ++ + grub-core/lib/libtasn1/lib/structure.c | 1225 +++++++++++ + grub-core/lib/libtasn1/lib/structure.h | 46 + + include/grub/libtasn1.h | 639 ++++++ + 15 files changed, 8896 insertions(+) + create mode 100644 grub-core/lib/libtasn1/COPYING + create mode 100644 grub-core/lib/libtasn1/README.md + create mode 100644 grub-core/lib/libtasn1/lib/coding.c + create mode 100644 grub-core/lib/libtasn1/lib/decoding.c + create mode 100644 grub-core/lib/libtasn1/lib/element.c + create mode 100644 grub-core/lib/libtasn1/lib/element.h + create mode 100644 grub-core/lib/libtasn1/lib/errors.c + create mode 100644 grub-core/lib/libtasn1/lib/gstr.c + create mode 100644 grub-core/lib/libtasn1/lib/gstr.h + create mode 100644 grub-core/lib/libtasn1/lib/int.h + create mode 100644 grub-core/lib/libtasn1/lib/parser_aux.c + create mode 100644 grub-core/lib/libtasn1/lib/parser_aux.h + create mode 100644 grub-core/lib/libtasn1/lib/structure.c + create mode 100644 grub-core/lib/libtasn1/lib/structure.h + create mode 100644 include/grub/libtasn1.h + +diff --git a/grub-core/lib/libtasn1/COPYING b/grub-core/lib/libtasn1/COPYING +new file mode 100644 +index 000000000..e8b3628db +--- /dev/null ++++ b/grub-core/lib/libtasn1/COPYING +@@ -0,0 +1,16 @@ ++LICENSING ++========= ++ ++The libtasn1 library is released under the GNU Lesser General Public ++License (LGPL) version 2.1 or later; see [COPYING.LESSER](doc/COPYING.LESSER) ++for the license terms. ++ ++The GNU LGPL applies to the main libtasn1 library, while the ++included applications library are under the GNU GPL version 3. ++The libtasn1 library is located in the lib directory, while the applications ++in src/. ++ ++The documentation in doc/ is under the GNU FDL license 1.3. ++ ++For any copyright year range specified as YYYY-ZZZZ in this package ++note that the range specifies every single year in that closed interval. +diff --git a/grub-core/lib/libtasn1/README.md b/grub-core/lib/libtasn1/README.md +new file mode 100644 +index 000000000..b0305b93e +--- /dev/null ++++ b/grub-core/lib/libtasn1/README.md +@@ -0,0 +1,98 @@ ++# Libtasn1 README -- Introduction information ++ ++This is GNU Libtasn1, a small ASN.1 library. ++ ++The C library (libtasn1.*) is licensed under the GNU Lesser General ++Public License version 2.1 or later. See the file COPYING.LIB. ++ ++The command line tool, self tests, examples, and other auxilliary ++files, are licensed under the GNU General Public License version 3.0 ++or later. See the file COPYING. ++ ++## Building the library ++ ++We require several tools to build the software, including: ++ ++* [Make](https://www.gnu.org/software/make/) ++* [Automake](https://www.gnu.org/software/automake/) (use 1.11.3 or later) ++* [Autoconf](https://www.gnu.org/software/autoconf/) ++* [Libtool](https://www.gnu.org/software/libtool/) ++* [Texinfo](https://www.gnu.org/software/texinfo/) ++* [help2man](http://www.gnu.org/software/help2man/) ++* [Tar](https://www.gnu.org/software/tar/) ++* [Gzip](https://www.gnu.org/software/gzip/) ++* [bison](https://www.gnu.org/software/bison/) ++* [Texlive & epsf](https://www.tug.org/texlive/) (for PDF manual) ++* [GTK-DOC](https://www.gtk.org/gtk-doc/) (for API manual) ++* [Git](https://git-scm.com/) ++* [libabigail](https://pagure.io/libabigail/) (for abi comparison in make dist) ++* [Valgrind](https://valgrind.org/) (optional) ++ ++The required software is typically distributed with your operating ++system, and the instructions for installing them differ. Here are ++some hints: ++ ++Debian/Ubuntu: ++``` ++sudo apt-get install make git autoconf automake libtool bison ++sudo apt-get install texinfo help2man gtk-doc-tools valgrind abigail-tools ++``` ++ ++PDF manual - Debian <= stretch: ++``` ++sudo apt-get install texlive-generic-recommended texlive texlive-extra-utils ++``` ++ ++PDF manual - Debian >= buster: ++``` ++sudo apt-get install texlive-plain-generic texlive texlive-extra-utils ++``` ++ ++The next step is to run autoreconf, ./configure, etc: ++ ++``` ++$ ./bootstrap ++``` ++ ++Then build the project normally: ++ ++``` ++$ ./configure ++$ make check ++``` ++ ++Happy hacking! ++ ++ ++## Manual ++ ++The manual is in the `doc/` directory of the release. ++ ++You can also browse the manual online at: ++ ++ - https://www.gnu.org/software/libtasn1/manual/ ++ - https://gnutls.gitlab.io/libtasn1/manual/ ++ - https://gnutls.gitlab.io/libtasn1/manual/libtasn1.html ++ - https://gnutls.gitlab.io/libtasn1/manual/libtasn1.pdf ++ - https://gnutls.gitlab.io/libtasn1/reference/ ++ - https://gnutls.gitlab.io/libtasn1/reference/libtasn1.pdf ++ ++ ++## Code coverage report ++ ++The coverage report is at: ++ ++ - https://gnutls.gitlab.io/libtasn1/coverage ++ ++ ++## Issue trackers ++ ++ - [Main issue tracker](https://gitlab.com/gnutls/libtasn1/issues) ++ - [oss-fuzz found issues](https://bugs.chromium.org/p/oss-fuzz/issues/list?q=libtasn1&can=2) ++ ++ ++## Homepage ++ ++The project homepage at the gnu site is at: ++ ++https://www.gnu.org/software/libtasn1/ +diff --git a/grub-core/lib/libtasn1/lib/coding.c b/grub-core/lib/libtasn1/lib/coding.c +new file mode 100644 +index 000000000..671104f63 +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/coding.c +@@ -0,0 +1,1425 @@ ++/* ++ * Copyright (C) 2002-2021 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 library is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++ ++/*****************************************************/ ++/* File: coding.c */ ++/* Description: Functions to create a DER coding of */ ++/* an ASN1 type. */ ++/*****************************************************/ ++ ++#include ++#include "parser_aux.h" ++#include ++#include "element.h" ++#include "minmax.h" ++#include ++ ++#define MAX_TAG_LEN 16 ++ ++/******************************************************/ ++/* Function : _asn1_error_description_value_not_found */ ++/* Description: creates the ErrorDescription string */ ++/* for the ASN1_VALUE_NOT_FOUND error. */ ++/* Parameters: */ ++/* node: node of the tree where the value is NULL. */ ++/* ErrorDescription: string returned. */ ++/* Return: */ ++/******************************************************/ ++static void ++_asn1_error_description_value_not_found (asn1_node node, ++ char *ErrorDescription) ++{ ++ ++ if (ErrorDescription == NULL) ++ return; ++ ++ Estrcpy (ErrorDescription, ":: value of element '"); ++ _asn1_hierarchical_name (node, ErrorDescription + strlen (ErrorDescription), ++ ASN1_MAX_ERROR_DESCRIPTION_SIZE - 40); ++ Estrcat (ErrorDescription, "' not found"); ++ ++} ++ ++/** ++ * asn1_length_der: ++ * @len: value to convert. ++ * @der: buffer to hold the returned encoding (may be %NULL). ++ * @der_len: number of meaningful bytes of ANS (der[0]..der[der_len-1]). ++ * ++ * Creates the DER encoding of the provided length value. ++ * The @der buffer must have enough room for the output. The maximum ++ * length this function will encode is %ASN1_MAX_LENGTH_SIZE. ++ * ++ * To know the size of the DER encoding use a %NULL value for @der. ++ **/ ++void ++asn1_length_der (unsigned long int len, unsigned char *der, int *der_len) ++{ ++ int k; ++ unsigned char temp[ASN1_MAX_LENGTH_SIZE]; ++#if SIZEOF_UNSIGNED_LONG_INT > 8 ++ len &= 0xFFFFFFFFFFFFFFFF; ++#endif ++ ++ if (len < 128) ++ { ++ /* short form */ ++ if (der != NULL) ++ der[0] = (unsigned char) len; ++ *der_len = 1; ++ } ++ else ++ { ++ /* Long form */ ++ k = 0; ++ while (len) ++ { ++ temp[k++] = len & 0xFF; ++ len = len >> 8; ++ } ++ *der_len = k + 1; ++ if (der != NULL) ++ { ++ der[0] = ((unsigned char) k & 0x7F) + 128; ++ while (k--) ++ der[*der_len - 1 - k] = temp[k]; ++ } ++ } ++} ++ ++/******************************************************/ ++/* Function : _asn1_tag_der */ ++/* Description: creates the DER coding for the CLASS */ ++/* and TAG parameters. */ ++/* It is limited by the ASN1_MAX_TAG_SIZE variable */ ++/* Parameters: */ ++/* class: value to convert. */ ++/* tag_value: value to convert. */ ++/* ans: string returned. */ ++/* ans_len: number of meaningful bytes of ANS */ ++/* (ans[0]..ans[ans_len-1]). */ ++/* Return: */ ++/******************************************************/ ++static void ++_asn1_tag_der (unsigned char class, unsigned int tag_value, ++ unsigned char ans[ASN1_MAX_TAG_SIZE], int *ans_len) ++{ ++ int k; ++ unsigned char temp[ASN1_MAX_TAG_SIZE]; ++ ++ if (tag_value < 31) ++ { ++ /* short form */ ++ ans[0] = (class & 0xE0) + ((unsigned char) (tag_value & 0x1F)); ++ *ans_len = 1; ++ } ++ else ++ { ++ /* Long form */ ++ ans[0] = (class & 0xE0) + 31; ++ k = 0; ++ while (tag_value != 0) ++ { ++ temp[k++] = tag_value & 0x7F; ++ tag_value >>= 7; ++ ++ if (k > ASN1_MAX_TAG_SIZE - 1) ++ break; /* will not encode larger tags */ ++ } ++ *ans_len = k + 1; ++ while (k--) ++ ans[*ans_len - 1 - k] = temp[k] + 128; ++ ans[*ans_len - 1] -= 128; ++ } ++} ++ ++/** ++ * asn1_octet_der: ++ * @str: the input data. ++ * @str_len: STR length (str[0]..str[*str_len-1]). ++ * @der: encoded string returned. ++ * @der_len: number of meaningful bytes of DER (der[0]..der[der_len-1]). ++ * ++ * Creates a length-value DER encoding for the input data. ++ * The DER encoding of the input data will be placed in the @der variable. ++ * ++ * Note that the OCTET STRING tag is not included in the output. ++ * ++ * This function does not return any value because it is expected ++ * that @der_len will contain enough bytes to store the string ++ * plus the DER encoding. The DER encoding size can be obtained using ++ * asn1_length_der(). ++ **/ ++void ++asn1_octet_der (const unsigned char *str, int str_len, ++ unsigned char *der, int *der_len) ++{ ++ int len_len; ++ ++ if (der == NULL || str_len < 0) ++ return; ++ ++ asn1_length_der (str_len, der, &len_len); ++ memcpy (der + len_len, str, str_len); ++ *der_len = str_len + len_len; ++} ++ ++ ++/** ++ * asn1_encode_simple_der: ++ * @etype: The type of the string to be encoded (ASN1_ETYPE_) ++ * @str: the string data. ++ * @str_len: the string length ++ * @tl: the encoded tag and length ++ * @tl_len: the bytes of the @tl field ++ * ++ * Creates the DER encoding for various simple ASN.1 types like strings etc. ++ * It stores the tag and length in @tl, which should have space for at least ++ * %ASN1_MAX_TL_SIZE bytes. Initially @tl_len should contain the size of @tl. ++ * ++ * The complete DER encoding should consist of the value in @tl appended ++ * with the provided @str. ++ * ++ * Returns: %ASN1_SUCCESS if successful or an error value. ++ **/ ++int ++asn1_encode_simple_der (unsigned int etype, const unsigned char *str, ++ unsigned int str_len, unsigned char *tl, ++ unsigned int *tl_len) ++{ ++ int tag_len, len_len; ++ unsigned tlen; ++ unsigned char der_tag[ASN1_MAX_TAG_SIZE]; ++ unsigned char der_length[ASN1_MAX_LENGTH_SIZE]; ++ unsigned char *p; ++ ++ if (str == NULL) ++ return ASN1_VALUE_NOT_VALID; ++ ++ if (ETYPE_OK (etype) == 0) ++ return ASN1_VALUE_NOT_VALID; ++ ++ /* doesn't handle constructed classes */ ++ if (ETYPE_CLASS (etype) != ASN1_CLASS_UNIVERSAL) ++ return ASN1_VALUE_NOT_VALID; ++ ++ _asn1_tag_der (ETYPE_CLASS (etype), ETYPE_TAG (etype), der_tag, &tag_len); ++ ++ asn1_length_der (str_len, der_length, &len_len); ++ ++ if (tag_len <= 0 || len_len <= 0) ++ return ASN1_VALUE_NOT_VALID; ++ ++ tlen = tag_len + len_len; ++ ++ if (*tl_len < tlen) ++ return ASN1_MEM_ERROR; ++ ++ p = tl; ++ memcpy (p, der_tag, tag_len); ++ p += tag_len; ++ memcpy (p, der_length, len_len); ++ ++ *tl_len = tlen; ++ ++ return ASN1_SUCCESS; ++} ++ ++/******************************************************/ ++/* Function : _asn1_time_der */ ++/* Description: creates the DER coding for a TIME */ ++/* type (length included). */ ++/* Parameters: */ ++/* str: TIME null-terminated string. */ ++/* der: string returned. */ ++/* der_len: number of meaningful bytes of DER */ ++/* (der[0]..der[ans_len-1]). Initially it */ ++/* if must store the lenght of DER. */ ++/* Return: */ ++/* ASN1_MEM_ERROR when DER isn't big enough */ ++/* ASN1_SUCCESS otherwise */ ++/******************************************************/ ++static int ++_asn1_time_der (unsigned char *str, int str_len, unsigned char *der, ++ int *der_len) ++{ ++ int len_len; ++ int max_len; ++ ++ max_len = *der_len; ++ ++ asn1_length_der (str_len, (max_len > 0) ? der : NULL, &len_len); ++ ++ if ((len_len + str_len) <= max_len) ++ memcpy (der + len_len, str, str_len); ++ *der_len = len_len + str_len; ++ ++ if ((*der_len) > max_len) ++ return ASN1_MEM_ERROR; ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++/* ++void ++_asn1_get_utctime_der(unsigned char *der,int *der_len,unsigned char *str) ++{ ++ int len_len,str_len; ++ char temp[20]; ++ ++ if(str==NULL) return; ++ str_len=asn1_get_length_der(der,*der_len,&len_len); ++ if (str_len<0) return; ++ memcpy(temp,der+len_len,str_len); ++ *der_len=str_len+len_len; ++ switch(str_len) ++ { ++ case 11: ++ temp[10]=0; ++ strcat(temp,"00+0000"); ++ break; ++ case 13: ++ temp[12]=0; ++ strcat(temp,"+0000"); ++ break; ++ case 15: ++ temp[15]=0; ++ memmove(temp+12,temp+10,6); ++ temp[10]=temp[11]='0'; ++ break; ++ case 17: ++ temp[17]=0; ++ break; ++ default: ++ return; ++ } ++ strcpy(str,temp); ++} ++*/ ++ ++static void ++encode_val (uint64_t val, unsigned char *der, int max_len, int *der_len) ++{ ++ int first, k; ++ unsigned char bit7; ++ ++ first = 0; ++ for (k = sizeof (val); k >= 0; k--) ++ { ++ bit7 = (val >> (k * 7)) & 0x7F; ++ if (bit7 || first || !k) ++ { ++ if (k) ++ bit7 |= 0x80; ++ if (max_len > (*der_len)) ++ der[*der_len] = bit7; ++ (*der_len)++; ++ first = 1; ++ } ++ } ++} ++ ++/******************************************************/ ++/* Function : _asn1_object_id_der */ ++/* Description: creates the DER coding for an */ ++/* OBJECT IDENTIFIER type (length included). */ ++/* Parameters: */ ++/* str: OBJECT IDENTIFIER null-terminated string. */ ++/* der: string returned. */ ++/* der_len: number of meaningful bytes of DER */ ++/* (der[0]..der[ans_len-1]). Initially it */ ++/* must store the length of DER. */ ++/* Return: */ ++/* ASN1_MEM_ERROR when DER isn't big enough */ ++/* ASN1_SUCCESS if succesful */ ++/* or an error value. */ ++/******************************************************/ ++static int ++_asn1_object_id_der (const char *str, unsigned char *der, int *der_len) ++{ ++ int len_len, counter, max_len; ++ char *temp, *n_end, *n_start; ++ uint64_t val, val1 = 0; ++ int str_len = _asn1_strlen (str); ++ ++ max_len = *der_len; ++ *der_len = 0; ++ ++ if (der == NULL && max_len > 0) ++ return ASN1_VALUE_NOT_VALID; ++ ++ temp = malloc (str_len + 2); ++ if (temp == NULL) ++ return ASN1_MEM_ALLOC_ERROR; ++ ++ memcpy (temp, str, str_len); ++ temp[str_len] = '.'; ++ temp[str_len + 1] = 0; ++ ++ counter = 0; ++ n_start = temp; ++ while ((n_end = strchr (n_start, '.'))) ++ { ++ *n_end = 0; ++ val = _asn1_strtou64 (n_start, NULL, 10); ++ counter++; ++ ++ if (counter == 1) ++ { ++ val1 = val; ++ } ++ else if (counter == 2) ++ { ++ uint64_t val0; ++ ++ if (val1 > 2) ++ { ++ free (temp); ++ return ASN1_VALUE_NOT_VALID; ++ } ++ else if ((val1 == 0 || val1 == 1) && val > 39) ++ { ++ free (temp); ++ return ASN1_VALUE_NOT_VALID; ++ } ++ ++ val0 = 40 * val1 + val; ++ encode_val (val0, der, max_len, der_len); ++ } ++ else ++ { ++ encode_val (val, der, max_len, der_len); ++ } ++ n_start = n_end + 1; ++ } ++ ++ asn1_length_der (*der_len, NULL, &len_len); ++ if (max_len >= (*der_len + len_len)) ++ { ++ memmove (der + len_len, der, *der_len); ++ asn1_length_der (*der_len, der, &len_len); ++ } ++ *der_len += len_len; ++ ++ free (temp); ++ ++ if (max_len < (*der_len)) ++ return ASN1_MEM_ERROR; ++ ++ return ASN1_SUCCESS; ++} ++ ++/** ++ * asn1_object_id_der: ++ * @str: An object identifier in numeric, dot format. ++ * @der: buffer to hold the returned encoding (may be %NULL). ++ * @der_len: initially the size of @der; will hold the final size. ++ * @flags: must be zero ++ * ++ * Creates the DER encoding of the provided object identifier. ++ * ++ * Returns: %ASN1_SUCCESS if DER encoding was OK, %ASN1_VALUE_NOT_VALID ++ * if @str is not a valid OID, %ASN1_MEM_ERROR if the @der ++ * vector isn't big enough and in this case @der_len will contain the ++ * length needed. ++ **/ ++int ++asn1_object_id_der (const char *str, unsigned char *der, int *der_len, ++ unsigned flags) ++{ ++ unsigned char tag_der[MAX_TAG_LEN]; ++ int tag_len = 0, r; ++ int max_len = *der_len; ++ ++ *der_len = 0; ++ ++ _asn1_tag_der (ETYPE_CLASS (ASN1_ETYPE_OBJECT_ID), ++ ETYPE_TAG (ASN1_ETYPE_OBJECT_ID), tag_der, &tag_len); ++ ++ if (max_len > tag_len) ++ { ++ memcpy (der, tag_der, tag_len); ++ } ++ max_len -= tag_len; ++ der += tag_len; ++ ++ r = _asn1_object_id_der (str, der, &max_len); ++ if (r == ASN1_MEM_ERROR || r == ASN1_SUCCESS) ++ { ++ *der_len = max_len + tag_len; ++ } ++ ++ return r; ++} ++ ++static const unsigned char bit_mask[] = ++ { 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80 }; ++ ++/** ++ * asn1_bit_der: ++ * @str: BIT string. ++ * @bit_len: number of meaningful bits in STR. ++ * @der: string returned. ++ * @der_len: number of meaningful bytes of DER ++ * (der[0]..der[ans_len-1]). ++ * ++ * Creates a length-value DER encoding for the input data ++ * as it would have been for a BIT STRING. ++ * The DER encoded data will be copied in @der. ++ * ++ * Note that the BIT STRING tag is not included in the output. ++ * ++ * This function does not return any value because it is expected ++ * that @der_len will contain enough bytes to store the string ++ * plus the DER encoding. The DER encoding size can be obtained using ++ * asn1_length_der(). ++ **/ ++void ++asn1_bit_der (const unsigned char *str, int bit_len, ++ unsigned char *der, int *der_len) ++{ ++ int len_len, len_byte, len_pad; ++ ++ if (der == NULL) ++ return; ++ ++ len_byte = bit_len >> 3; ++ len_pad = 8 - (bit_len & 7); ++ if (len_pad == 8) ++ len_pad = 0; ++ else ++ len_byte++; ++ asn1_length_der (len_byte + 1, der, &len_len); ++ der[len_len] = len_pad; ++ ++ if (str) ++ memcpy (der + len_len + 1, str, len_byte); ++ der[len_len + len_byte] &= bit_mask[len_pad]; ++ *der_len = len_byte + len_len + 1; ++} ++ ++ ++/******************************************************/ ++/* Function : _asn1_complete_explicit_tag */ ++/* Description: add the length coding to the EXPLICIT */ ++/* tags. */ ++/* Parameters: */ ++/* node: pointer to the tree element. */ ++/* der: string with the DER coding of the whole tree*/ ++/* counter: number of meaningful bytes of DER */ ++/* (der[0]..der[*counter-1]). */ ++/* max_len: size of der vector */ ++/* Return: */ ++/* ASN1_MEM_ERROR if der vector isn't big enough, */ ++/* otherwise ASN1_SUCCESS. */ ++/******************************************************/ ++static int ++_asn1_complete_explicit_tag (asn1_node node, unsigned char *der, ++ int *counter, int *max_len) ++{ ++ asn1_node p; ++ int is_tag_implicit, len2, len3; ++ unsigned char temp[SIZEOF_UNSIGNED_INT]; ++ ++ if (der == NULL && *max_len > 0) ++ return ASN1_VALUE_NOT_VALID; ++ ++ is_tag_implicit = 0; ++ ++ if (node->type & CONST_TAG) ++ { ++ p = node->down; ++ if (p == NULL) ++ return ASN1_DER_ERROR; ++ /* When there are nested tags we must complete them reverse to ++ the order they were created. This is because completing a tag ++ modifies all data within it, including the incomplete tags ++ which store buffer positions -- simon@josefsson.org 2002-09-06 ++ */ ++ while (p->right) ++ p = p->right; ++ while (p && p != node->down->left) ++ { ++ if (type_field (p->type) == ASN1_ETYPE_TAG) ++ { ++ if (p->type & CONST_EXPLICIT) ++ { ++ len2 = strtol (p->name, NULL, 10); ++ _asn1_set_name (p, NULL); ++ ++ asn1_length_der (*counter - len2, temp, &len3); ++ if (len3 <= (*max_len)) ++ { ++ memmove (der + len2 + len3, der + len2, ++ *counter - len2); ++ memcpy (der + len2, temp, len3); ++ } ++ *max_len -= len3; ++ *counter += len3; ++ is_tag_implicit = 0; ++ } ++ else ++ { /* CONST_IMPLICIT */ ++ if (!is_tag_implicit) ++ { ++ is_tag_implicit = 1; ++ } ++ } ++ } ++ p = p->left; ++ } ++ } ++ ++ if (*max_len < 0) ++ return ASN1_MEM_ERROR; ++ ++ return ASN1_SUCCESS; ++} ++ ++const tag_and_class_st _asn1_tags[] = { ++ [ASN1_ETYPE_GENERALSTRING] = ++ {ASN1_TAG_GENERALSTRING, ASN1_CLASS_UNIVERSAL, "type:GENERALSTRING"}, ++ [ASN1_ETYPE_NUMERIC_STRING] = ++ {ASN1_TAG_NUMERIC_STRING, ASN1_CLASS_UNIVERSAL, "type:NUMERIC_STR"}, ++ [ASN1_ETYPE_IA5_STRING] = ++ {ASN1_TAG_IA5_STRING, ASN1_CLASS_UNIVERSAL, "type:IA5_STR"}, ++ [ASN1_ETYPE_TELETEX_STRING] = ++ {ASN1_TAG_TELETEX_STRING, ASN1_CLASS_UNIVERSAL, "type:TELETEX_STR"}, ++ [ASN1_ETYPE_PRINTABLE_STRING] = ++ {ASN1_TAG_PRINTABLE_STRING, ASN1_CLASS_UNIVERSAL, "type:PRINTABLE_STR"}, ++ [ASN1_ETYPE_UNIVERSAL_STRING] = ++ {ASN1_TAG_UNIVERSAL_STRING, ASN1_CLASS_UNIVERSAL, "type:UNIVERSAL_STR"}, ++ [ASN1_ETYPE_BMP_STRING] = ++ {ASN1_TAG_BMP_STRING, ASN1_CLASS_UNIVERSAL, "type:BMP_STR"}, ++ [ASN1_ETYPE_UTF8_STRING] = ++ {ASN1_TAG_UTF8_STRING, ASN1_CLASS_UNIVERSAL, "type:UTF8_STR"}, ++ [ASN1_ETYPE_VISIBLE_STRING] = ++ {ASN1_TAG_VISIBLE_STRING, ASN1_CLASS_UNIVERSAL, "type:VISIBLE_STR"}, ++ [ASN1_ETYPE_OCTET_STRING] = ++ {ASN1_TAG_OCTET_STRING, ASN1_CLASS_UNIVERSAL, "type:OCT_STR"}, ++ [ASN1_ETYPE_BIT_STRING] = ++ {ASN1_TAG_BIT_STRING, ASN1_CLASS_UNIVERSAL, "type:BIT_STR"}, ++ [ASN1_ETYPE_OBJECT_ID] = ++ {ASN1_TAG_OBJECT_ID, ASN1_CLASS_UNIVERSAL, "type:OBJ_ID"}, ++ [ASN1_ETYPE_NULL] = {ASN1_TAG_NULL, ASN1_CLASS_UNIVERSAL, "type:NULL"}, ++ [ASN1_ETYPE_BOOLEAN] = ++ {ASN1_TAG_BOOLEAN, ASN1_CLASS_UNIVERSAL, "type:BOOLEAN"}, ++ [ASN1_ETYPE_INTEGER] = ++ {ASN1_TAG_INTEGER, ASN1_CLASS_UNIVERSAL, "type:INTEGER"}, ++ [ASN1_ETYPE_ENUMERATED] = ++ {ASN1_TAG_ENUMERATED, ASN1_CLASS_UNIVERSAL, "type:ENUMERATED"}, ++ [ASN1_ETYPE_SEQUENCE] = ++ {ASN1_TAG_SEQUENCE, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED, ++ "type:SEQUENCE"}, ++ [ASN1_ETYPE_SEQUENCE_OF] = ++ {ASN1_TAG_SEQUENCE, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED, ++ "type:SEQ_OF"}, ++ [ASN1_ETYPE_SET] = ++ {ASN1_TAG_SET, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED, "type:SET"}, ++ [ASN1_ETYPE_SET_OF] = ++ {ASN1_TAG_SET, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED, ++ "type:SET_OF"}, ++ [ASN1_ETYPE_GENERALIZED_TIME] = ++ {ASN1_TAG_GENERALIZEDTime, ASN1_CLASS_UNIVERSAL, "type:GENERALIZED_TIME"}, ++ [ASN1_ETYPE_UTC_TIME] = ++ {ASN1_TAG_UTCTime, ASN1_CLASS_UNIVERSAL, "type:UTC_TIME"}, ++}; ++ ++unsigned int _asn1_tags_size = sizeof (_asn1_tags) / sizeof (_asn1_tags[0]); ++ ++/******************************************************/ ++/* Function : _asn1_insert_tag_der */ ++/* Description: creates the DER coding of tags of one */ ++/* NODE. */ ++/* Parameters: */ ++/* node: pointer to the tree element. */ ++/* der: string returned */ ++/* counter: number of meaningful bytes of DER */ ++/* (counter[0]..der[*counter-1]). */ ++/* max_len: size of der vector */ ++/* Return: */ ++/* ASN1_GENERIC_ERROR if the type is unknown, */ ++/* ASN1_MEM_ERROR if der vector isn't big enough, */ ++/* otherwise ASN1_SUCCESS. */ ++/******************************************************/ ++static int ++_asn1_insert_tag_der (asn1_node node, unsigned char *der, int *counter, ++ int *max_len) ++{ ++ asn1_node p; ++ int tag_len, is_tag_implicit; ++ unsigned char class, class_implicit = ++ 0, temp[MAX (SIZEOF_UNSIGNED_INT * 3 + 1, LTOSTR_MAX_SIZE)]; ++ unsigned long tag_implicit = 0; ++ unsigned char tag_der[MAX_TAG_LEN]; ++ ++ is_tag_implicit = 0; ++ ++ if (node->type & CONST_TAG) ++ { ++ p = node->down; ++ while (p) ++ { ++ if (type_field (p->type) == ASN1_ETYPE_TAG) ++ { ++ if (p->type & CONST_APPLICATION) ++ class = ASN1_CLASS_APPLICATION; ++ else if (p->type & CONST_UNIVERSAL) ++ class = ASN1_CLASS_UNIVERSAL; ++ else if (p->type & CONST_PRIVATE) ++ class = ASN1_CLASS_PRIVATE; ++ else ++ class = ASN1_CLASS_CONTEXT_SPECIFIC; ++ ++ if (p->type & CONST_EXPLICIT) ++ { ++ if (is_tag_implicit) ++ _asn1_tag_der (class_implicit, tag_implicit, tag_der, ++ &tag_len); ++ else ++ _asn1_tag_der (class | ASN1_CLASS_STRUCTURED, ++ _asn1_strtoul (p->value, NULL, 10), ++ tag_der, &tag_len); ++ ++ *max_len -= tag_len; ++ if (der && *max_len >= 0) ++ memcpy (der + *counter, tag_der, tag_len); ++ *counter += tag_len; ++ ++ _asn1_ltostr (*counter, (char *) temp); ++ _asn1_set_name (p, (const char *) temp); ++ ++ is_tag_implicit = 0; ++ } ++ else ++ { /* CONST_IMPLICIT */ ++ if (!is_tag_implicit) ++ { ++ if ((type_field (node->type) == ASN1_ETYPE_SEQUENCE) || ++ (type_field (node->type) == ASN1_ETYPE_SEQUENCE_OF) ++ || (type_field (node->type) == ASN1_ETYPE_SET) ++ || (type_field (node->type) == ASN1_ETYPE_SET_OF)) ++ class |= ASN1_CLASS_STRUCTURED; ++ class_implicit = class; ++ tag_implicit = _asn1_strtoul (p->value, NULL, 10); ++ is_tag_implicit = 1; ++ } ++ } ++ } ++ p = p->right; ++ } ++ } ++ ++ if (is_tag_implicit) ++ { ++ _asn1_tag_der (class_implicit, tag_implicit, tag_der, &tag_len); ++ } ++ else ++ { ++ unsigned type = type_field (node->type); ++ switch (type) ++ { ++ CASE_HANDLED_ETYPES: ++ _asn1_tag_der (_asn1_tags[type].class, _asn1_tags[type].tag, ++ tag_der, &tag_len); ++ break; ++ case ASN1_ETYPE_TAG: ++ case ASN1_ETYPE_CHOICE: ++ case ASN1_ETYPE_ANY: ++ tag_len = 0; ++ break; ++ default: ++ return ASN1_GENERIC_ERROR; ++ } ++ } ++ ++ *max_len -= tag_len; ++ if (der && *max_len >= 0) ++ memcpy (der + *counter, tag_der, tag_len); ++ *counter += tag_len; ++ ++ if (*max_len < 0) ++ return ASN1_MEM_ERROR; ++ ++ return ASN1_SUCCESS; ++} ++ ++/******************************************************/ ++/* Function : _asn1_ordering_set */ ++/* Description: puts the elements of a SET type in */ ++/* the correct order according to DER rules. */ ++/* Parameters: */ ++/* der: string with the DER coding. */ ++/* node: pointer to the SET element. */ ++/* Return: */ ++/* ASN1_SUCCESS if successful */ ++/* or an error value. */ ++/******************************************************/ ++static int ++_asn1_ordering_set (unsigned char *der, int der_len, asn1_node node) ++{ ++ struct vet ++ { ++ int end; ++ unsigned long value; ++ struct vet *next, *prev; ++ }; ++ ++ int counter, len, len2; ++ struct vet *first, *last, *p_vet, *p2_vet; ++ asn1_node p; ++ unsigned char class, *temp; ++ unsigned long tag, t; ++ int err; ++ ++ counter = 0; ++ ++ if (type_field (node->type) != ASN1_ETYPE_SET) ++ return ASN1_VALUE_NOT_VALID; ++ ++ p = node->down; ++ while (p && ((type_field (p->type) == ASN1_ETYPE_TAG) || ++ (type_field (p->type) == ASN1_ETYPE_SIZE))) ++ p = p->right; ++ ++ if ((p == NULL) || (p->right == NULL)) ++ return ASN1_SUCCESS; ++ ++ first = last = NULL; ++ while (p) ++ { ++ p_vet = malloc (sizeof (struct vet)); ++ if (p_vet == NULL) ++ { ++ err = ASN1_MEM_ALLOC_ERROR; ++ goto error; ++ } ++ ++ p_vet->next = NULL; ++ p_vet->prev = last; ++ if (first == NULL) ++ first = p_vet; ++ else ++ last->next = p_vet; ++ last = p_vet; ++ ++ /* tag value calculation */ ++ err = asn1_get_tag_der (der + counter, der_len - counter, &class, &len2, ++ &tag); ++ if (err != ASN1_SUCCESS) ++ goto error; ++ ++ t = ((unsigned int) class) << 24; ++ p_vet->value = t | tag; ++ counter += len2; ++ ++ /* extraction and length */ ++ len2 = asn1_get_length_der (der + counter, der_len - counter, &len); ++ if (len2 < 0) ++ { ++ err = ASN1_DER_ERROR; ++ goto error; ++ } ++ counter += len + len2; ++ ++ p_vet->end = counter; ++ p = p->right; ++ } ++ ++ p_vet = first; ++ ++ while (p_vet) ++ { ++ p2_vet = p_vet->next; ++ counter = 0; ++ while (p2_vet) ++ { ++ if (p_vet->value > p2_vet->value) ++ { ++ /* change position */ ++ temp = malloc (p_vet->end - counter); ++ if (temp == NULL) ++ { ++ err = ASN1_MEM_ALLOC_ERROR; ++ goto error; ++ } ++ ++ memcpy (temp, der + counter, p_vet->end - counter); ++ memcpy (der + counter, der + p_vet->end, ++ p2_vet->end - p_vet->end); ++ memcpy (der + counter + p2_vet->end - p_vet->end, temp, ++ p_vet->end - counter); ++ free (temp); ++ ++ tag = p_vet->value; ++ p_vet->value = p2_vet->value; ++ p2_vet->value = tag; ++ ++ p_vet->end = counter + (p2_vet->end - p_vet->end); ++ } ++ counter = p_vet->end; ++ ++ p2_vet = p2_vet->next; ++ p_vet = p_vet->next; ++ } ++ ++ if (p_vet != first) ++ p_vet->prev->next = NULL; ++ else ++ first = NULL; ++ free (p_vet); ++ p_vet = first; ++ } ++ return ASN1_SUCCESS; ++ ++error: ++ while (first != NULL) ++ { ++ p_vet = first; ++ first = first->next; ++ free (p_vet); ++ } ++ return err; ++} ++ ++struct vet ++{ ++ unsigned char *ptr; ++ int size; ++}; ++ ++static int ++setof_compar (const void *_e1, const void *_e2) ++{ ++ unsigned length; ++ const struct vet *e1 = _e1, *e2 = _e2; ++ int rval; ++ ++ /* The encodings of the component values of a set-of value shall ++ * appear in ascending order, the encodings being compared ++ * as octet strings with the shorter components being ++ * padded at their trailing end with 0-octets. ++ * The padding octets are for comparison purposes and ++ * do not appear in the encodings. ++ */ ++ length = MIN (e1->size, e2->size); ++ ++ rval = memcmp (e1->ptr, e2->ptr, length); ++ if (rval == 0 && e1->size != e2->size) ++ { ++ if (e1->size > e2->size) ++ rval = 1; ++ else if (e2->size > e1->size) ++ rval = -1; ++ } ++ ++ return rval; ++} ++ ++/******************************************************/ ++/* Function : _asn1_ordering_set_of */ ++/* Description: puts the elements of a SET OF type in */ ++/* the correct order according to DER rules. */ ++/* Parameters: */ ++/* der: string with the DER coding. */ ++/* node: pointer to the SET OF element. */ ++/* Return: */ ++/* ASN1_SUCCESS if successful */ ++/* or an error value. */ ++/******************************************************/ ++static int ++_asn1_ordering_set_of (unsigned char *der, int der_len, asn1_node node) ++{ ++ int counter, len, len2; ++ struct vet *list = NULL, *tlist; ++ unsigned list_size = 0; ++ struct vet *p_vet; ++ asn1_node p; ++ unsigned char class; ++ unsigned i; ++ unsigned char *out = NULL; ++ int err; ++ ++ counter = 0; ++ ++ if (type_field (node->type) != ASN1_ETYPE_SET_OF) ++ return ASN1_VALUE_NOT_VALID; ++ ++ p = node->down; ++ while (p && ((type_field (p->type) == ASN1_ETYPE_TAG) || ++ (type_field (p->type) == ASN1_ETYPE_SIZE))) ++ p = p->right; ++ if (p == NULL) ++ return ASN1_VALUE_NOT_VALID; ++ p = p->right; ++ ++ if ((p == NULL) || (p->right == NULL)) ++ return ASN1_SUCCESS; ++ ++ while (p) ++ { ++ list_size++; ++ tlist = realloc (list, list_size * sizeof (struct vet)); ++ if (tlist == NULL) ++ { ++ err = ASN1_MEM_ALLOC_ERROR; ++ goto error; ++ } ++ list = tlist; ++ p_vet = &list[list_size - 1]; ++ ++ p_vet->ptr = der + counter; ++ p_vet->size = 0; ++ ++ /* extraction of tag and length */ ++ if (der_len - counter > 0) ++ { ++ err = asn1_get_tag_der (der + counter, der_len - counter, &class, ++ &len, NULL); ++ if (err != ASN1_SUCCESS) ++ goto error; ++ counter += len; ++ p_vet->size += len; ++ ++ len2 = asn1_get_length_der (der + counter, der_len - counter, &len); ++ if (len2 < 0) ++ { ++ err = ASN1_DER_ERROR; ++ goto error; ++ } ++ counter += len + len2; ++ p_vet->size += len + len2; ++ ++ } ++ else ++ { ++ err = ASN1_DER_ERROR; ++ goto error; ++ } ++ p = p->right; ++ } ++ ++ if (counter > der_len) ++ { ++ err = ASN1_DER_ERROR; ++ goto error; ++ } ++ ++ qsort (list, list_size, sizeof (struct vet), setof_compar); ++ ++ out = malloc (der_len); ++ if (out == NULL) ++ { ++ err = ASN1_MEM_ERROR; ++ goto error; ++ } ++ ++ /* the sum of p_vet->size == der_len */ ++ counter = 0; ++ for (i = 0; i < list_size; i++) ++ { ++ p_vet = &list[i]; ++ memcpy (out + counter, p_vet->ptr, p_vet->size); ++ counter += p_vet->size; ++ } ++ memcpy (der, out, der_len); ++ free (out); ++ ++ err = ASN1_SUCCESS; ++ ++error: ++ free (list); ++ return err; ++} ++ ++/** ++ * asn1_der_coding: ++ * @element: pointer to an ASN1 element ++ * @name: the name of the structure you want to encode (it must be ++ * inside *POINTER). ++ * @ider: vector that will contain the DER encoding. DER must be a ++ * pointer to memory cells already allocated. ++ * @len: number of bytes of *@ider: @ider[0]..@ider[len-1], Initialy ++ * holds the sizeof of der vector. ++ * @ErrorDescription: return the error description or an empty ++ * string if success. ++ * ++ * Creates the DER encoding for the NAME structure (inside *POINTER ++ * structure). ++ * ++ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND ++ * if @name is not a valid element, %ASN1_VALUE_NOT_FOUND if there ++ * is an element without a value, %ASN1_MEM_ERROR if the @ider ++ * vector isn't big enough and in this case @len will contain the ++ * length needed. ++ **/ ++int ++asn1_der_coding (asn1_node_const element, const char *name, void *ider, ++ int *len, char *ErrorDescription) ++{ ++ asn1_node node, p, p2; ++ unsigned char temp[MAX (LTOSTR_MAX_SIZE, SIZEOF_UNSIGNED_LONG_INT * 3 + 1)]; ++ int counter, counter_old, len2, len3, move, max_len, max_len_old; ++ int err; ++ unsigned char *der = ider; ++ unsigned char dummy; ++ ++ if (ErrorDescription) ++ ErrorDescription[0] = 0; ++ ++ node = asn1_find_node (element, name); ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ /* Node is now a locally allocated variable. ++ * That is because in some point we modify the ++ * structure, and I don't know why! --nmav ++ */ ++ node = _asn1_copy_structure3 (node); ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ max_len = *len; ++ ++ if (der == NULL && max_len > 0) ++ { ++ err = ASN1_VALUE_NOT_VALID; ++ goto error; ++ } ++ ++ counter = 0; ++ move = DOWN; ++ p = node; ++ ++ while (1) ++ { ++ ++ counter_old = counter; ++ max_len_old = max_len; ++ if (move != UP) ++ { ++ p->start = counter; ++ err = _asn1_insert_tag_der (p, der, &counter, &max_len); ++ if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR) ++ goto error; ++ } ++ switch (type_field (p->type)) ++ { ++ case ASN1_ETYPE_NULL: ++ max_len--; ++ if (der != NULL && max_len >= 0) ++ der[counter] = 0; ++ counter++; ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_BOOLEAN: ++ if ((p->type & CONST_DEFAULT) && (p->value == NULL)) ++ { ++ counter = counter_old; ++ max_len = max_len_old; ++ } ++ else ++ { ++ if (p->value == NULL) ++ { ++ _asn1_error_description_value_not_found (p, ++ ErrorDescription); ++ err = ASN1_VALUE_NOT_FOUND; ++ goto error; ++ } ++ max_len -= 2; ++ if (der != NULL && max_len >= 0) ++ { ++ der[counter++] = 1; ++ if (p->value[0] == 'F') ++ der[counter++] = 0; ++ else ++ der[counter++] = 0xFF; ++ } ++ else ++ counter += 2; ++ } ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_INTEGER: ++ case ASN1_ETYPE_ENUMERATED: ++ if ((p->type & CONST_DEFAULT) && (p->value == NULL)) ++ { ++ counter = counter_old; ++ max_len = max_len_old; ++ } ++ else ++ { ++ if (p->value == NULL) ++ { ++ _asn1_error_description_value_not_found (p, ++ ErrorDescription); ++ err = ASN1_VALUE_NOT_FOUND; ++ goto error; ++ } ++ len2 = asn1_get_length_der (p->value, p->value_len, &len3); ++ if (len2 < 0) ++ { ++ err = ASN1_DER_ERROR; ++ goto error; ++ } ++ max_len -= len2 + len3; ++ if (der != NULL && max_len >= 0) ++ memcpy (der + counter, p->value, len3 + len2); ++ counter += len3 + len2; ++ } ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_OBJECT_ID: ++ if ((p->type & CONST_DEFAULT) && (p->value == NULL)) ++ { ++ counter = counter_old; ++ max_len = max_len_old; ++ } ++ else ++ { ++ if (p->value == NULL) ++ { ++ _asn1_error_description_value_not_found (p, ++ ErrorDescription); ++ err = ASN1_VALUE_NOT_FOUND; ++ goto error; ++ } ++ len2 = max_len; ++ err = ++ _asn1_object_id_der ((char *) p->value, ++ der ? der + counter : &dummy, &len2); ++ if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR) ++ goto error; ++ ++ max_len -= len2; ++ counter += len2; ++ } ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_GENERALIZED_TIME: ++ case ASN1_ETYPE_UTC_TIME: ++ if (p->value == NULL) ++ { ++ _asn1_error_description_value_not_found (p, ErrorDescription); ++ err = ASN1_VALUE_NOT_FOUND; ++ goto error; ++ } ++ len2 = max_len; ++ err = ++ _asn1_time_der (p->value, p->value_len, ++ der ? der + counter : &dummy, &len2); ++ if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR) ++ goto error; ++ ++ max_len -= len2; ++ counter += len2; ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_OCTET_STRING: ++ case ASN1_ETYPE_GENERALSTRING: ++ case ASN1_ETYPE_NUMERIC_STRING: ++ case ASN1_ETYPE_IA5_STRING: ++ case ASN1_ETYPE_TELETEX_STRING: ++ case ASN1_ETYPE_PRINTABLE_STRING: ++ case ASN1_ETYPE_UNIVERSAL_STRING: ++ case ASN1_ETYPE_BMP_STRING: ++ case ASN1_ETYPE_UTF8_STRING: ++ case ASN1_ETYPE_VISIBLE_STRING: ++ case ASN1_ETYPE_BIT_STRING: ++ if (p->value == NULL) ++ { ++ _asn1_error_description_value_not_found (p, ErrorDescription); ++ err = ASN1_VALUE_NOT_FOUND; ++ goto error; ++ } ++ len2 = asn1_get_length_der (p->value, p->value_len, &len3); ++ if (len2 < 0) ++ { ++ err = ASN1_DER_ERROR; ++ goto error; ++ } ++ max_len -= len2 + len3; ++ if (der != NULL && max_len >= 0) ++ memcpy (der + counter, p->value, len3 + len2); ++ counter += len3 + len2; ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_SEQUENCE: ++ case ASN1_ETYPE_SET: ++ if (move != UP) ++ { ++ p->tmp_ival = counter; ++ if (p->down == NULL) ++ { ++ move = UP; ++ continue; ++ } ++ else ++ { ++ p2 = p->down; ++ while (p2 && (type_field (p2->type) == ASN1_ETYPE_TAG)) ++ p2 = p2->right; ++ if (p2) ++ { ++ p = p2; ++ move = RIGHT; ++ continue; ++ } ++ move = UP; ++ continue; ++ } ++ } ++ else ++ { /* move==UP */ ++ len2 = p->tmp_ival; ++ p->tmp_ival = 0; ++ if ((type_field (p->type) == ASN1_ETYPE_SET) && (max_len >= 0)) ++ { ++ err = ++ _asn1_ordering_set (der ? der + len2 : &dummy, ++ counter - len2, p); ++ if (err != ASN1_SUCCESS) ++ goto error; ++ } ++ asn1_length_der (counter - len2, temp, &len3); ++ max_len -= len3; ++ if (der != NULL && max_len >= 0) ++ { ++ memmove (der + len2 + len3, der + len2, counter - len2); ++ memcpy (der + len2, temp, len3); ++ } ++ counter += len3; ++ move = RIGHT; ++ } ++ break; ++ case ASN1_ETYPE_SEQUENCE_OF: ++ case ASN1_ETYPE_SET_OF: ++ if (move != UP) ++ { ++ p->tmp_ival = counter; ++ p = p->down; ++ while ((type_field (p->type) == ASN1_ETYPE_TAG) ++ || (type_field (p->type) == ASN1_ETYPE_SIZE)) ++ p = p->right; ++ if (p->right) ++ { ++ p = p->right; ++ move = RIGHT; ++ continue; ++ } ++ else ++ p = _asn1_find_up (p); ++ move = UP; ++ } ++ if (move == UP) ++ { ++ len2 = p->tmp_ival; ++ p->tmp_ival = 0; ++ if ((type_field (p->type) == ASN1_ETYPE_SET_OF) ++ && (counter - len2 > 0) && (max_len >= 0)) ++ { ++ err = ++ _asn1_ordering_set_of (der ? der + len2 : &dummy, ++ counter - len2, p); ++ if (err != ASN1_SUCCESS) ++ goto error; ++ } ++ asn1_length_der (counter - len2, temp, &len3); ++ max_len -= len3; ++ if (der != NULL && max_len >= 0) ++ { ++ memmove (der + len2 + len3, der + len2, counter - len2); ++ memcpy (der + len2, temp, len3); ++ } ++ counter += len3; ++ move = RIGHT; ++ } ++ break; ++ case ASN1_ETYPE_ANY: ++ if (p->value == NULL) ++ { ++ _asn1_error_description_value_not_found (p, ErrorDescription); ++ err = ASN1_VALUE_NOT_FOUND; ++ goto error; ++ } ++ len2 = asn1_get_length_der (p->value, p->value_len, &len3); ++ if (len2 < 0) ++ { ++ err = ASN1_DER_ERROR; ++ goto error; ++ } ++ max_len -= len2; ++ if (der != NULL && max_len >= 0) ++ memcpy (der + counter, p->value + len3, len2); ++ counter += len2; ++ move = RIGHT; ++ break; ++ default: ++ move = (move == UP) ? RIGHT : DOWN; ++ break; ++ } ++ ++ if ((move != DOWN) && (counter != counter_old)) ++ { ++ p->end = counter - 1; ++ err = _asn1_complete_explicit_tag (p, der, &counter, &max_len); ++ if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR) ++ goto error; ++ } ++ ++ if (p == node && move != DOWN) ++ break; ++ ++ if (move == DOWN) ++ { ++ if (p->down) ++ p = p->down; ++ else ++ move = RIGHT; ++ } ++ if (move == RIGHT) ++ { ++ if (p->right) ++ p = p->right; ++ else ++ move = UP; ++ } ++ if (move == UP) ++ p = _asn1_find_up (p); ++ } ++ ++ *len = counter; ++ ++ if (max_len < 0) ++ { ++ err = ASN1_MEM_ERROR; ++ goto error; ++ } ++ ++ err = ASN1_SUCCESS; ++ ++error: ++ asn1_delete_structure (&node); ++ return err; ++} +diff --git a/grub-core/lib/libtasn1/lib/decoding.c b/grub-core/lib/libtasn1/lib/decoding.c +new file mode 100644 +index 000000000..b1a35356f +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/decoding.c +@@ -0,0 +1,2501 @@ ++/* ++ * Copyright (C) 2002-2021 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 library is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++ ++/*****************************************************/ ++/* File: decoding.c */ ++/* Description: Functions to manage DER decoding */ ++/*****************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "c-ctype.h" ++ ++#ifdef DEBUG ++# define warn() fprintf(stderr, "%s: %d\n", __func__, __LINE__) ++#else ++# define warn() ++#endif ++ ++#define IS_ERR(len, flags) (len < -1 || ((flags & ASN1_DECODE_FLAG_STRICT_DER) && len < 0)) ++ ++#define HAVE_TWO(x) (x>=2?1:0) ++ ++/* Decoding flags (dflags) used in several decoding functions. ++ * DECODE_FLAG_HAVE_TAG: The provided buffer includes a tag ++ * DECODE_FLAG_CONSTRUCTED: The provided buffer is of indefinite encoding (useful ++ * when no tags are present). ++ * DECODE_FLAG_LEVEL1: Internal flag to indicate a level of recursion for BER strings. ++ * DECODE_FLAG_LEVEL2: Internal flag to indicate two levels of recursion for BER strings. ++ * DECODE_FLAG_LEVEL3: Internal flag to indicate three levels of recursion for BER strings. ++ * This is the maximum levels of recursion possible to prevent stack ++ * exhaustion. ++ */ ++ ++#define DECODE_FLAG_HAVE_TAG 1 ++#define DECODE_FLAG_CONSTRUCTED (1<<1) ++#define DECODE_FLAG_LEVEL1 (1<<2) ++#define DECODE_FLAG_LEVEL2 (1<<3) ++#define DECODE_FLAG_LEVEL3 (1<<4) ++ ++#define DECR_LEN(l, s) do { \ ++ l -= s; \ ++ if (l < 0) { \ ++ warn(); \ ++ result = ASN1_DER_ERROR; \ ++ goto cleanup; \ ++ } \ ++ } while (0) ++ ++static int ++_asn1_get_indefinite_length_string (const unsigned char *der, int der_len, ++ int *len); ++ ++static int ++_asn1_decode_simple_ber (unsigned int etype, const unsigned char *der, ++ unsigned int _der_len, unsigned char **str, ++ unsigned int *str_len, unsigned int *ber_len, ++ unsigned dflags); ++ ++static int ++_asn1_decode_simple_der (unsigned int etype, const unsigned char *der, ++ unsigned int _der_len, const unsigned char **str, ++ unsigned int *str_len, unsigned dflags); ++ ++static void ++_asn1_error_description_tag_error (asn1_node node, char *ErrorDescription) ++{ ++ ++ Estrcpy (ErrorDescription, ":: tag error near element '"); ++ _asn1_hierarchical_name (node, ErrorDescription + strlen (ErrorDescription), ++ ASN1_MAX_ERROR_DESCRIPTION_SIZE - 40); ++ Estrcat (ErrorDescription, "'"); ++ ++} ++ ++/** ++ * asn1_get_length_der: ++ * @der: DER data to decode. ++ * @der_len: Length of DER data to decode. ++ * @len: Output variable containing the length of the DER length field. ++ * ++ * Extract a length field from DER data. ++ * ++ * Returns: Return the decoded length value, or -1 on indefinite ++ * length, or -2 when the value was too big to fit in a int, or -4 ++ * when the decoded length value plus @len would exceed @der_len. ++ **/ ++long ++asn1_get_length_der (const unsigned char *der, int der_len, int *len) ++{ ++ unsigned int ans; ++ int k, punt, sum; ++ ++ *len = 0; ++ if (der_len <= 0) ++ return 0; ++ ++ if (!(der[0] & 128)) ++ { ++ /* short form */ ++ *len = 1; ++ ans = der[0]; ++ } ++ else ++ { ++ /* Long form */ ++ k = der[0] & 0x7F; ++ punt = 1; ++ if (k) ++ { /* definite length method */ ++ ans = 0; ++ while (punt <= k && punt < der_len) ++ { ++ if (INT_MULTIPLY_OVERFLOW (ans, 256)) ++ return -2; ++ ans *= 256; ++ ++ if (INT_ADD_OVERFLOW (ans, ((unsigned) der[punt]))) ++ return -2; ++ ans += der[punt]; ++ punt++; ++ } ++ } ++ else ++ { /* indefinite length method */ ++ *len = punt; ++ return -1; ++ } ++ ++ *len = punt; ++ } ++ ++ sum = ans; ++ if (ans >= INT_MAX || INT_ADD_OVERFLOW (sum, (*len))) ++ return -2; ++ sum += *len; ++ ++ if (sum > der_len) ++ return -4; ++ ++ return ans; ++} ++ ++/** ++ * asn1_get_tag_der: ++ * @der: DER data to decode. ++ * @der_len: Length of DER data to decode. ++ * @cls: Output variable containing decoded class. ++ * @len: Output variable containing the length of the DER TAG data. ++ * @tag: Output variable containing the decoded tag (may be %NULL). ++ * ++ * Decode the class and TAG from DER code. ++ * ++ * Returns: Returns %ASN1_SUCCESS on success, or an error. ++ **/ ++int ++asn1_get_tag_der (const unsigned char *der, int der_len, ++ unsigned char *cls, int *len, unsigned long *tag) ++{ ++ unsigned int ris; ++ int punt; ++ ++ if (der == NULL || der_len < 2 || len == NULL) ++ return ASN1_DER_ERROR; ++ ++ *cls = der[0] & 0xE0; ++ if ((der[0] & 0x1F) != 0x1F) ++ { ++ /* short form */ ++ *len = 1; ++ ris = der[0] & 0x1F; ++ } ++ else ++ { ++ /* Long form */ ++ punt = 1; ++ ris = 0; ++ while (punt < der_len && der[punt] & 128) ++ { ++ ++ if (INT_MULTIPLY_OVERFLOW (ris, 128)) ++ return ASN1_DER_ERROR; ++ ris *= 128; ++ ++ if (INT_ADD_OVERFLOW (ris, ((unsigned) (der[punt] & 0x7F)))) ++ return ASN1_DER_ERROR; ++ ris += (der[punt] & 0x7F); ++ punt++; ++ } ++ ++ if (punt >= der_len) ++ return ASN1_DER_ERROR; ++ ++ if (INT_MULTIPLY_OVERFLOW (ris, 128)) ++ return ASN1_DER_ERROR; ++ ris *= 128; ++ ++ if (INT_ADD_OVERFLOW (ris, ((unsigned) (der[punt] & 0x7F)))) ++ return ASN1_DER_ERROR; ++ ris += (der[punt] & 0x7F); ++ punt++; ++ ++ *len = punt; ++ } ++ ++ if (tag) ++ *tag = ris; ++ return ASN1_SUCCESS; ++} ++ ++/** ++ * asn1_get_length_ber: ++ * @ber: BER data to decode. ++ * @ber_len: Length of BER data to decode. ++ * @len: Output variable containing the length of the BER length field. ++ * ++ * Extract a length field from BER data. The difference to ++ * asn1_get_length_der() is that this function will return a length ++ * even if the value has indefinite encoding. ++ * ++ * Returns: Return the decoded length value, or negative value when ++ * the value was too big. ++ * ++ * Since: 2.0 ++ **/ ++long ++asn1_get_length_ber (const unsigned char *ber, int ber_len, int *len) ++{ ++ int ret; ++ long err; ++ ++ ret = asn1_get_length_der (ber, ber_len, len); ++ ++ if (ret == -1 && ber_len > 1) ++ { /* indefinite length method */ ++ err = _asn1_get_indefinite_length_string (ber + 1, ber_len - 1, &ret); ++ if (err != ASN1_SUCCESS) ++ return -3; ++ } ++ ++ return ret; ++} ++ ++/** ++ * asn1_get_octet_der: ++ * @der: DER data to decode containing the OCTET SEQUENCE. ++ * @der_len: The length of the @der data to decode. ++ * @ret_len: Output variable containing the encoded length of the DER data. ++ * @str: Pre-allocated output buffer to put decoded OCTET SEQUENCE in. ++ * @str_size: Length of pre-allocated output buffer. ++ * @str_len: Output variable containing the length of the contents of the OCTET SEQUENCE. ++ * ++ * Extract an OCTET SEQUENCE from DER data. Note that this function ++ * expects the DER data past the tag field, i.e., the length and ++ * content octets. ++ * ++ * Returns: Returns %ASN1_SUCCESS on success, or an error. ++ **/ ++int ++asn1_get_octet_der (const unsigned char *der, int der_len, ++ int *ret_len, unsigned char *str, int str_size, ++ int *str_len) ++{ ++ int len_len = 0; ++ ++ if (der_len <= 0) ++ return ASN1_GENERIC_ERROR; ++ ++ *str_len = asn1_get_length_der (der, der_len, &len_len); ++ ++ if (*str_len < 0) ++ return ASN1_DER_ERROR; ++ ++ *ret_len = *str_len + len_len; ++ if (str_size >= *str_len) ++ { ++ if (*str_len > 0 && str != NULL) ++ memcpy (str, der + len_len, *str_len); ++ } ++ else ++ { ++ return ASN1_MEM_ERROR; ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++/*- ++ * _asn1_get_time_der: ++ * @type: %ASN1_ETYPE_GENERALIZED_TIME or %ASN1_ETYPE_UTC_TIME ++ * @der: DER data to decode containing the time ++ * @der_len: Length of DER data to decode. ++ * @ret_len: Output variable containing the length of the DER data. ++ * @str: Pre-allocated output buffer to put the textual time in. ++ * @str_size: Length of pre-allocated output buffer. ++ * @flags: Zero or %ASN1_DECODE_FLAG_STRICT_DER ++ * ++ * Performs basic checks in the DER encoded time object and returns its textual form. ++ * The textual form will be in the YYYYMMDD000000Z format for GeneralizedTime ++ * and YYMMDD000000Z for UTCTime. ++ * ++ * Returns: %ASN1_SUCCESS on success, or an error. ++ -*/ ++static int ++_asn1_get_time_der (unsigned type, const unsigned char *der, int der_len, ++ int *ret_len, char *str, int str_size, unsigned flags) ++{ ++ int len_len, str_len; ++ unsigned i; ++ unsigned sign_count = 0; ++ unsigned dot_count = 0; ++ const unsigned char *p; ++ ++ if (der_len <= 0 || str == NULL) ++ return ASN1_DER_ERROR; ++ ++ str_len = asn1_get_length_der (der, der_len, &len_len); ++ if (str_len <= 0 || str_size < str_len) ++ return ASN1_DER_ERROR; ++ ++ /* perform some sanity checks on the data */ ++ if (str_len < 8) ++ { ++ warn (); ++ return ASN1_TIME_ENCODING_ERROR; ++ } ++ ++ if ((flags & ASN1_DECODE_FLAG_STRICT_DER) ++ && !(flags & ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME)) ++ { ++ p = &der[len_len]; ++ for (i = 0; i < (unsigned) (str_len - 1); i++) ++ { ++ if (c_isdigit (p[i]) == 0) ++ { ++ if (type == ASN1_ETYPE_GENERALIZED_TIME) ++ { ++ /* tolerate lax encodings */ ++ if (p[i] == '.' && dot_count == 0) ++ { ++ dot_count++; ++ continue; ++ } ++ ++ /* This is not really valid DER, but there are ++ * structures using that */ ++ if (!(flags & ASN1_DECODE_FLAG_STRICT_DER) && ++ (p[i] == '+' || p[i] == '-') && sign_count == 0) ++ { ++ sign_count++; ++ continue; ++ } ++ } ++ ++ warn (); ++ return ASN1_TIME_ENCODING_ERROR; ++ } ++ } ++ ++ if (sign_count == 0 && p[str_len - 1] != 'Z') ++ { ++ warn (); ++ return ASN1_TIME_ENCODING_ERROR; ++ } ++ } ++ memcpy (str, der + len_len, str_len); ++ str[str_len] = 0; ++ *ret_len = str_len + len_len; ++ ++ return ASN1_SUCCESS; ++} ++ ++/** ++ * asn1_get_object_id_der: ++ * @der: DER data to decode containing the OBJECT IDENTIFIER ++ * @der_len: Length of DER data to decode. ++ * @ret_len: Output variable containing the length of the DER data. ++ * @str: Pre-allocated output buffer to put the textual object id in. ++ * @str_size: Length of pre-allocated output buffer. ++ * ++ * Converts a DER encoded object identifier to its textual form. This ++ * function expects the DER object identifier without the tag. ++ * ++ * Returns: %ASN1_SUCCESS on success, or an error. ++ **/ ++int ++asn1_get_object_id_der (const unsigned char *der, int der_len, int *ret_len, ++ char *str, int str_size) ++{ ++ int len_len, len, k; ++ int leading, parsed; ++ char temp[LTOSTR_MAX_SIZE]; ++ uint64_t val, val1, val0; ++ ++ *ret_len = 0; ++ if (str && str_size > 0) ++ str[0] = 0; /* no oid */ ++ ++ if (str == NULL || der_len <= 0) ++ return ASN1_GENERIC_ERROR; ++ ++ len = asn1_get_length_der (der, der_len, &len_len); ++ ++ if (len <= 0 || len + len_len > der_len) ++ return ASN1_DER_ERROR; ++ ++ /* leading octet can never be 0x80 */ ++ if (der[len_len] == 0x80) ++ return ASN1_DER_ERROR; ++ ++ val0 = 0; ++ ++ for (k = 0; k < len; k++) ++ { ++ if (INT_LEFT_SHIFT_OVERFLOW (val0, 7)) ++ return ASN1_DER_ERROR; ++ ++ val0 <<= 7; ++ val0 |= der[len_len + k] & 0x7F; ++ if (!(der[len_len + k] & 0x80)) ++ break; ++ } ++ parsed = ++k; ++ ++ /* val0 = (X*40) + Y, X={0,1,2}, Y<=39 when X={0,1} */ ++ /* X = val, Y = val1 */ ++ ++ /* check if X == 0 */ ++ val = 0; ++ val1 = val0; ++ if (val1 > 39) ++ { ++ val = 1; ++ val1 = val0 - 40; ++ if (val1 > 39) ++ { ++ val = 2; ++ val1 = val0 - 80; ++ } ++ } ++ ++ _asn1_str_cpy (str, str_size, _asn1_ltostr (val, temp)); ++ _asn1_str_cat (str, str_size, "."); ++ _asn1_str_cat (str, str_size, _asn1_ltostr (val1, temp)); ++ ++ val = 0; ++ leading = 1; ++ for (k = parsed; k < len; k++) ++ { ++ /* X.690 mandates that the leading byte must never be 0x80 ++ */ ++ if (leading != 0 && der[len_len + k] == 0x80) ++ return ASN1_DER_ERROR; ++ leading = 0; ++ ++ /* check for wrap around */ ++ if (INT_LEFT_SHIFT_OVERFLOW (val, 7)) ++ return ASN1_DER_ERROR; ++ ++ val = val << 7; ++ val |= der[len_len + k] & 0x7F; ++ ++ if (!(der[len_len + k] & 0x80)) ++ { ++ _asn1_str_cat (str, str_size, "."); ++ _asn1_str_cat (str, str_size, _asn1_ltostr (val, temp)); ++ val = 0; ++ leading = 1; ++ } ++ } ++ ++ if (INT_ADD_OVERFLOW (len, len_len)) ++ return ASN1_DER_ERROR; ++ ++ *ret_len = len + len_len; ++ ++ return ASN1_SUCCESS; ++} ++ ++/** ++ * asn1_get_bit_der: ++ * @der: DER data to decode containing the BIT SEQUENCE. ++ * @der_len: Length of DER data to decode. ++ * @ret_len: Output variable containing the length of the DER data. ++ * @str: Pre-allocated output buffer to put decoded BIT SEQUENCE in. ++ * @str_size: Length of pre-allocated output buffer. ++ * @bit_len: Output variable containing the size of the BIT SEQUENCE. ++ * ++ * Extract a BIT SEQUENCE from DER data. ++ * ++ * Returns: %ASN1_SUCCESS on success, or an error. ++ **/ ++int ++asn1_get_bit_der (const unsigned char *der, int der_len, ++ int *ret_len, unsigned char *str, int str_size, ++ int *bit_len) ++{ ++ int len_len = 0, len_byte; ++ ++ if (der_len <= 0) ++ return ASN1_GENERIC_ERROR; ++ ++ len_byte = asn1_get_length_der (der, der_len, &len_len) - 1; ++ if (len_byte < 0) ++ return ASN1_DER_ERROR; ++ ++ *ret_len = len_byte + len_len + 1; ++ *bit_len = len_byte * 8 - der[len_len]; ++ ++ if (*bit_len < 0) ++ return ASN1_DER_ERROR; ++ ++ if (str_size >= len_byte) ++ { ++ if (len_byte > 0 && str) ++ memcpy (str, der + len_len + 1, len_byte); ++ } ++ else ++ { ++ return ASN1_MEM_ERROR; ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++/* tag_len: the total tag length (explicit+inner) ++ * inner_tag_len: the inner_tag length ++ */ ++static int ++_asn1_extract_tag_der (asn1_node node, const unsigned char *der, int der_len, ++ int *tag_len, int *inner_tag_len, unsigned flags) ++{ ++ asn1_node p; ++ int counter, len2, len3, is_tag_implicit; ++ int result; ++ unsigned long tag, tag_implicit = 0; ++ unsigned char class, class2, class_implicit = 0; ++ ++ if (der_len <= 0) ++ return ASN1_GENERIC_ERROR; ++ ++ counter = is_tag_implicit = 0; ++ ++ if (node->type & CONST_TAG) ++ { ++ p = node->down; ++ while (p) ++ { ++ if (type_field (p->type) == ASN1_ETYPE_TAG) ++ { ++ if (p->type & CONST_APPLICATION) ++ class2 = ASN1_CLASS_APPLICATION; ++ else if (p->type & CONST_UNIVERSAL) ++ class2 = ASN1_CLASS_UNIVERSAL; ++ else if (p->type & CONST_PRIVATE) ++ class2 = ASN1_CLASS_PRIVATE; ++ else ++ class2 = ASN1_CLASS_CONTEXT_SPECIFIC; ++ ++ if (p->type & CONST_EXPLICIT) ++ { ++ if (asn1_get_tag_der ++ (der + counter, der_len, &class, &len2, ++ &tag) != ASN1_SUCCESS) ++ return ASN1_DER_ERROR; ++ ++ DECR_LEN (der_len, len2); ++ counter += len2; ++ ++ if (flags & ASN1_DECODE_FLAG_STRICT_DER) ++ len3 = ++ asn1_get_length_der (der + counter, der_len, &len2); ++ else ++ len3 = ++ asn1_get_length_ber (der + counter, der_len, &len2); ++ if (len3 < 0) ++ return ASN1_DER_ERROR; ++ ++ DECR_LEN (der_len, len2); ++ counter += len2; ++ ++ if (!is_tag_implicit) ++ { ++ if ((class != (class2 | ASN1_CLASS_STRUCTURED)) || ++ (tag != strtoul ((char *) p->value, NULL, 10))) ++ return ASN1_TAG_ERROR; ++ } ++ else ++ { /* ASN1_TAG_IMPLICIT */ ++ if ((class != class_implicit) || (tag != tag_implicit)) ++ return ASN1_TAG_ERROR; ++ } ++ is_tag_implicit = 0; ++ } ++ else ++ { /* ASN1_TAG_IMPLICIT */ ++ if (!is_tag_implicit) ++ { ++ if ((type_field (node->type) == ASN1_ETYPE_SEQUENCE) || ++ (type_field (node->type) == ASN1_ETYPE_SEQUENCE_OF) ++ || (type_field (node->type) == ASN1_ETYPE_SET) ++ || (type_field (node->type) == ASN1_ETYPE_SET_OF)) ++ class2 |= ASN1_CLASS_STRUCTURED; ++ class_implicit = class2; ++ tag_implicit = strtoul ((char *) p->value, NULL, 10); ++ is_tag_implicit = 1; ++ } ++ } ++ } ++ p = p->right; ++ } ++ } ++ ++ if (is_tag_implicit) ++ { ++ if (asn1_get_tag_der ++ (der + counter, der_len, &class, &len2, &tag) != ASN1_SUCCESS) ++ return ASN1_DER_ERROR; ++ ++ DECR_LEN (der_len, len2); ++ ++ if ((class != class_implicit) || (tag != tag_implicit)) ++ { ++ if (type_field (node->type) == ASN1_ETYPE_OCTET_STRING) ++ { ++ class_implicit |= ASN1_CLASS_STRUCTURED; ++ if ((class != class_implicit) || (tag != tag_implicit)) ++ return ASN1_TAG_ERROR; ++ } ++ else ++ return ASN1_TAG_ERROR; ++ } ++ } ++ else ++ { ++ unsigned type = type_field (node->type); ++ if (type == ASN1_ETYPE_TAG) ++ { ++ *tag_len = 0; ++ if (inner_tag_len) ++ *inner_tag_len = 0; ++ return ASN1_SUCCESS; ++ } ++ ++ if (asn1_get_tag_der ++ (der + counter, der_len, &class, &len2, &tag) != ASN1_SUCCESS) ++ return ASN1_DER_ERROR; ++ ++ DECR_LEN (der_len, len2); ++ ++ switch (type) ++ { ++ case ASN1_ETYPE_NULL: ++ case ASN1_ETYPE_BOOLEAN: ++ case ASN1_ETYPE_INTEGER: ++ case ASN1_ETYPE_ENUMERATED: ++ case ASN1_ETYPE_OBJECT_ID: ++ case ASN1_ETYPE_GENERALSTRING: ++ case ASN1_ETYPE_NUMERIC_STRING: ++ case ASN1_ETYPE_IA5_STRING: ++ case ASN1_ETYPE_TELETEX_STRING: ++ case ASN1_ETYPE_PRINTABLE_STRING: ++ case ASN1_ETYPE_UNIVERSAL_STRING: ++ case ASN1_ETYPE_BMP_STRING: ++ case ASN1_ETYPE_UTF8_STRING: ++ case ASN1_ETYPE_VISIBLE_STRING: ++ case ASN1_ETYPE_BIT_STRING: ++ case ASN1_ETYPE_SEQUENCE: ++ case ASN1_ETYPE_SEQUENCE_OF: ++ case ASN1_ETYPE_SET: ++ case ASN1_ETYPE_SET_OF: ++ case ASN1_ETYPE_GENERALIZED_TIME: ++ case ASN1_ETYPE_UTC_TIME: ++ if ((class != _asn1_tags[type].class) ++ || (tag != _asn1_tags[type].tag)) ++ return ASN1_DER_ERROR; ++ break; ++ ++ case ASN1_ETYPE_OCTET_STRING: ++ /* OCTET STRING is handled differently to allow ++ * BER encodings (structured class). */ ++ if (((class != ASN1_CLASS_UNIVERSAL) ++ && (class != (ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED))) ++ || (tag != ASN1_TAG_OCTET_STRING)) ++ return ASN1_DER_ERROR; ++ break; ++ case ASN1_ETYPE_ANY: ++ counter -= len2; ++ break; ++ case ASN1_ETYPE_CHOICE: ++ counter -= len2; ++ break; ++ default: ++ return ASN1_DER_ERROR; ++ break; ++ } ++ } ++ ++ counter += len2; ++ *tag_len = counter; ++ if (inner_tag_len) ++ *inner_tag_len = len2; ++ return ASN1_SUCCESS; ++ ++cleanup: ++ return result; ++} ++ ++static int ++extract_tag_der_recursive (asn1_node node, const unsigned char *der, ++ int der_len, int *ret_len, int *inner_len, ++ unsigned flags) ++{ ++ asn1_node p; ++ int ris = ASN1_DER_ERROR; ++ ++ if (type_field (node->type) == ASN1_ETYPE_CHOICE) ++ { ++ p = node->down; ++ while (p) ++ { ++ ris = ++ _asn1_extract_tag_der (p, der, der_len, ret_len, inner_len, ++ flags); ++ if (ris == ASN1_SUCCESS) ++ break; ++ p = p->right; ++ } ++ ++ *ret_len = 0; ++ return ris; ++ } ++ else ++ return _asn1_extract_tag_der (node, der, der_len, ret_len, inner_len, ++ flags); ++} ++ ++static int ++_asn1_delete_not_used (asn1_node node) ++{ ++ asn1_node p, p2; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = node; ++ while (p) ++ { ++ if (p->type & CONST_NOT_USED) ++ { ++ p2 = NULL; ++ if (p != node) ++ { ++ p2 = _asn1_find_left (p); ++ if (!p2) ++ p2 = _asn1_find_up (p); ++ } ++ asn1_delete_structure (&p); ++ p = p2; ++ } ++ ++ if (!p) ++ break; /* reach node */ ++ ++ if (p->down) ++ { ++ p = p->down; ++ } ++ else ++ { ++ if (p == node) ++ p = NULL; ++ else if (p->right) ++ p = p->right; ++ else ++ { ++ while (1) ++ { ++ p = _asn1_find_up (p); ++ if (p == node) ++ { ++ p = NULL; ++ break; ++ } ++ if (p->right) ++ { ++ p = p->right; ++ break; ++ } ++ } ++ } ++ } ++ } ++ return ASN1_SUCCESS; ++} ++ ++static int ++_asn1_get_indefinite_length_string (const unsigned char *der, ++ int der_len, int *len) ++{ ++ int len2, len3, counter, indefinite; ++ int result; ++ unsigned long tag; ++ unsigned char class; ++ ++ counter = indefinite = 0; ++ ++ while (1) ++ { ++ if (HAVE_TWO (der_len) && (der[counter] == 0) ++ && (der[counter + 1] == 0)) ++ { ++ counter += 2; ++ DECR_LEN (der_len, 2); ++ ++ indefinite--; ++ if (indefinite <= 0) ++ break; ++ else ++ continue; ++ } ++ ++ if (asn1_get_tag_der ++ (der + counter, der_len, &class, &len2, &tag) != ASN1_SUCCESS) ++ return ASN1_DER_ERROR; ++ ++ DECR_LEN (der_len, len2); ++ counter += len2; ++ ++ len2 = asn1_get_length_der (der + counter, der_len, &len3); ++ if (len2 < -1) ++ return ASN1_DER_ERROR; ++ ++ if (len2 == -1) ++ { ++ indefinite++; ++ counter += 1; ++ DECR_LEN (der_len, 1); ++ } ++ else ++ { ++ counter += len2 + len3; ++ DECR_LEN (der_len, len2 + len3); ++ } ++ } ++ ++ *len = counter; ++ return ASN1_SUCCESS; ++ ++cleanup: ++ return result; ++} ++ ++static void ++delete_unneeded_choice_fields (asn1_node p) ++{ ++ asn1_node p2; ++ ++ while (p->right) ++ { ++ p2 = p->right; ++ asn1_delete_structure (&p2); ++ } ++} ++ ++ ++/** ++ * asn1_der_decoding2 ++ * @element: pointer to an ASN1 structure. ++ * @ider: vector that contains the DER encoding. ++ * @max_ider_len: pointer to an integer giving the information about the ++ * maximal number of bytes occupied by *@ider. The real size of the DER ++ * encoding is returned through this pointer. ++ * @flags: flags controlling the behaviour of the function. ++ * @errorDescription: null-terminated string contains details when an ++ * error occurred. ++ * ++ * Fill the structure *@element with values of a DER encoding string. The ++ * structure must just be created with function asn1_create_element(). ++ * ++ * If %ASN1_DECODE_FLAG_ALLOW_PADDING flag is set then the function will ignore ++ * padding after the decoded DER data. Upon a successful return the value of ++ * *@max_ider_len will be set to the number of bytes decoded. ++ * ++ * If %ASN1_DECODE_FLAG_STRICT_DER flag is set then the function will ++ * not decode any BER-encoded elements. ++ * ++ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND ++ * if @ELEMENT is %NULL, and %ASN1_TAG_ERROR or ++ * %ASN1_DER_ERROR if the der encoding doesn't match the structure ++ * name (*@ELEMENT deleted). ++ **/ ++int ++asn1_der_decoding2 (asn1_node * element, const void *ider, int *max_ider_len, ++ unsigned int flags, char *errorDescription) ++{ ++ asn1_node node, p, p2, p3; ++ char temp[128]; ++ int counter, len2, len3, len4, move, ris, tlen; ++ struct node_tail_cache_st tcache = { NULL, NULL }; ++ unsigned char class; ++ unsigned long tag; ++ int tag_len; ++ int indefinite, result, total_len = *max_ider_len, ider_len = *max_ider_len; ++ int inner_tag_len; ++ unsigned char *ptmp; ++ const unsigned char *ptag; ++ const unsigned char *der = ider; ++ ++ node = *element; ++ ++ if (errorDescription != NULL) ++ errorDescription[0] = 0; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ if (node->type & CONST_OPTION) ++ { ++ result = ASN1_GENERIC_ERROR; ++ warn (); ++ goto cleanup; ++ } ++ ++ counter = 0; ++ move = DOWN; ++ p = node; ++ while (1) ++ { ++ tag_len = 0; ++ inner_tag_len = 0; ++ ris = ASN1_SUCCESS; ++ if (move != UP) ++ { ++ if (p->type & CONST_SET) ++ { ++ p2 = _asn1_find_up (p); ++ len2 = p2->tmp_ival; ++ if (len2 == -1) ++ { ++ if (HAVE_TWO (ider_len) && !der[counter] ++ && !der[counter + 1]) ++ { ++ p = p2; ++ move = UP; ++ counter += 2; ++ DECR_LEN (ider_len, 2); ++ continue; ++ } ++ } ++ else if (counter == len2) ++ { ++ p = p2; ++ move = UP; ++ continue; ++ } ++ else if (counter > len2) ++ { ++ result = ASN1_DER_ERROR; ++ warn (); ++ goto cleanup; ++ } ++ p2 = p2->down; ++ while (p2) ++ { ++ if ((p2->type & CONST_SET) && (p2->type & CONST_NOT_USED)) ++ { ++ ris = ++ extract_tag_der_recursive (p2, der + counter, ++ ider_len, &len2, NULL, ++ flags); ++ if (ris == ASN1_SUCCESS) ++ { ++ p2->type &= ~CONST_NOT_USED; ++ p = p2; ++ break; ++ } ++ } ++ p2 = p2->right; ++ } ++ if (p2 == NULL) ++ { ++ result = ASN1_DER_ERROR; ++ warn (); ++ goto cleanup; ++ } ++ } ++ ++ /* the position in the DER structure this starts */ ++ p->start = counter; ++ p->end = total_len - 1; ++ ++ if ((p->type & CONST_OPTION) || (p->type & CONST_DEFAULT)) ++ { ++ p2 = _asn1_find_up (p); ++ len2 = p2->tmp_ival; ++ if (counter == len2) ++ { ++ if (p->right) ++ { ++ p2 = p->right; ++ move = RIGHT; ++ } ++ else ++ move = UP; ++ ++ if (p->type & CONST_OPTION) ++ asn1_delete_structure (&p); ++ ++ p = p2; ++ continue; ++ } ++ } ++ ++ if (type_field (p->type) == ASN1_ETYPE_CHOICE) ++ { ++ while (p->down) ++ { ++ ris = ++ extract_tag_der_recursive (p->down, der + counter, ++ ider_len, &len2, NULL, flags); ++ ++ if (ris == ASN1_SUCCESS) ++ { ++ delete_unneeded_choice_fields (p->down); ++ break; ++ } ++ else if (ris == ASN1_ERROR_TYPE_ANY) ++ { ++ result = ASN1_ERROR_TYPE_ANY; ++ warn (); ++ goto cleanup; ++ } ++ else ++ { ++ p2 = p->down; ++ asn1_delete_structure (&p2); ++ } ++ } ++ ++ if (p->down == NULL) ++ { ++ if (!(p->type & CONST_OPTION)) ++ { ++ result = ASN1_DER_ERROR; ++ warn (); ++ goto cleanup; ++ } ++ } ++ else if (type_field (p->type) != ASN1_ETYPE_CHOICE) ++ p = p->down; ++ ++ p->start = counter; ++ } ++ ++ if ((p->type & CONST_OPTION) || (p->type & CONST_DEFAULT)) ++ { ++ p2 = _asn1_find_up (p); ++ len2 = p2->tmp_ival; ++ ++ if ((len2 != -1) && (counter > len2)) ++ ris = ASN1_TAG_ERROR; ++ } ++ ++ if (ris == ASN1_SUCCESS) ++ ris = ++ extract_tag_der_recursive (p, der + counter, ider_len, ++ &tag_len, &inner_tag_len, flags); ++ ++ if (ris != ASN1_SUCCESS) ++ { ++ if (p->type & CONST_OPTION) ++ { ++ p->type |= CONST_NOT_USED; ++ move = RIGHT; ++ } ++ else if (p->type & CONST_DEFAULT) ++ { ++ _asn1_set_value (p, NULL, 0); ++ move = RIGHT; ++ } ++ else ++ { ++ if (errorDescription != NULL) ++ _asn1_error_description_tag_error (p, errorDescription); ++ ++ result = ASN1_TAG_ERROR; ++ warn (); ++ goto cleanup; ++ } ++ } ++ else ++ { ++ DECR_LEN (ider_len, tag_len); ++ counter += tag_len; ++ } ++ } ++ ++ if (ris == ASN1_SUCCESS) ++ { ++ switch (type_field (p->type)) ++ { ++ case ASN1_ETYPE_NULL: ++ DECR_LEN (ider_len, 1); ++ if (der[counter]) ++ { ++ result = ASN1_DER_ERROR; ++ warn (); ++ goto cleanup; ++ } ++ counter++; ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_BOOLEAN: ++ DECR_LEN (ider_len, 2); ++ ++ if (der[counter++] != 1) ++ { ++ result = ASN1_DER_ERROR; ++ warn (); ++ goto cleanup; ++ } ++ if (der[counter++] == 0) ++ _asn1_set_value (p, "F", 1); ++ else ++ _asn1_set_value (p, "T", 1); ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_INTEGER: ++ case ASN1_ETYPE_ENUMERATED: ++ len2 = asn1_get_length_der (der + counter, ider_len, &len3); ++ if (len2 < 0) ++ { ++ result = ASN1_DER_ERROR; ++ warn (); ++ goto cleanup; ++ } ++ ++ DECR_LEN (ider_len, len3 + len2); ++ ++ _asn1_set_value (p, der + counter, len3 + len2); ++ counter += len3 + len2; ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_OBJECT_ID: ++ result = ++ asn1_get_object_id_der (der + counter, ider_len, &len2, ++ temp, sizeof (temp)); ++ if (result != ASN1_SUCCESS) ++ { ++ warn (); ++ goto cleanup; ++ } ++ ++ DECR_LEN (ider_len, len2); ++ ++ tlen = strlen (temp); ++ if (tlen > 0) ++ _asn1_set_value (p, temp, tlen + 1); ++ ++ counter += len2; ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_GENERALIZED_TIME: ++ case ASN1_ETYPE_UTC_TIME: ++ result = ++ _asn1_get_time_der (type_field (p->type), der + counter, ++ ider_len, &len2, temp, sizeof (temp) - 1, ++ flags); ++ if (result != ASN1_SUCCESS) ++ { ++ warn (); ++ goto cleanup; ++ } ++ ++ DECR_LEN (ider_len, len2); ++ ++ tlen = strlen (temp); ++ if (tlen > 0) ++ _asn1_set_value (p, temp, tlen); ++ ++ counter += len2; ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_OCTET_STRING: ++ if (counter < inner_tag_len) ++ { ++ result = ASN1_DER_ERROR; ++ warn (); ++ goto cleanup; ++ } ++ ++ ptag = der + counter - inner_tag_len; ++ if ((flags & ASN1_DECODE_FLAG_STRICT_DER) ++ || !(ptag[0] & ASN1_CLASS_STRUCTURED)) ++ { ++ if (ptag[0] & ASN1_CLASS_STRUCTURED) ++ { ++ result = ASN1_DER_ERROR; ++ warn (); ++ goto cleanup; ++ } ++ ++ len2 = asn1_get_length_der (der + counter, ider_len, &len3); ++ if (len2 < 0) ++ { ++ result = ASN1_DER_ERROR; ++ warn (); ++ goto cleanup; ++ } ++ ++ DECR_LEN (ider_len, len3 + len2); ++ ++ _asn1_set_value (p, der + counter, len3 + len2); ++ counter += len3 + len2; ++ } ++ else ++ { ++ unsigned dflags = 0, vlen, ber_len; ++ ++ if (ptag[0] & ASN1_CLASS_STRUCTURED) ++ dflags |= DECODE_FLAG_CONSTRUCTED; ++ ++ result = ++ _asn1_decode_simple_ber (type_field (p->type), ++ der + counter, ider_len, &ptmp, ++ &vlen, &ber_len, dflags); ++ if (result != ASN1_SUCCESS) ++ { ++ warn (); ++ goto cleanup; ++ } ++ ++ DECR_LEN (ider_len, ber_len); ++ ++ _asn1_set_value_lv (p, ptmp, vlen); ++ ++ counter += ber_len; ++ free (ptmp); ++ } ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_GENERALSTRING: ++ case ASN1_ETYPE_NUMERIC_STRING: ++ case ASN1_ETYPE_IA5_STRING: ++ case ASN1_ETYPE_TELETEX_STRING: ++ case ASN1_ETYPE_PRINTABLE_STRING: ++ case ASN1_ETYPE_UNIVERSAL_STRING: ++ case ASN1_ETYPE_BMP_STRING: ++ case ASN1_ETYPE_UTF8_STRING: ++ case ASN1_ETYPE_VISIBLE_STRING: ++ case ASN1_ETYPE_BIT_STRING: ++ len2 = asn1_get_length_der (der + counter, ider_len, &len3); ++ if (len2 < 0) ++ { ++ result = ASN1_DER_ERROR; ++ warn (); ++ goto cleanup; ++ } ++ ++ DECR_LEN (ider_len, len3 + len2); ++ ++ _asn1_set_value (p, der + counter, len3 + len2); ++ counter += len3 + len2; ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_SEQUENCE: ++ case ASN1_ETYPE_SET: ++ if (move == UP) ++ { ++ len2 = p->tmp_ival; ++ p->tmp_ival = 0; ++ if (len2 == -1) ++ { /* indefinite length method */ ++ DECR_LEN (ider_len, 2); ++ if ((der[counter]) || der[counter + 1]) ++ { ++ result = ASN1_DER_ERROR; ++ warn (); ++ goto cleanup; ++ } ++ counter += 2; ++ } ++ else ++ { /* definite length method */ ++ if (len2 != counter) ++ { ++ result = ASN1_DER_ERROR; ++ warn (); ++ goto cleanup; ++ } ++ } ++ move = RIGHT; ++ } ++ else ++ { /* move==DOWN || move==RIGHT */ ++ len3 = asn1_get_length_der (der + counter, ider_len, &len2); ++ if (IS_ERR (len3, flags)) ++ { ++ result = ASN1_DER_ERROR; ++ warn (); ++ goto cleanup; ++ } ++ ++ DECR_LEN (ider_len, len2); ++ counter += len2; ++ ++ if (len3 > 0) ++ { ++ p->tmp_ival = counter + len3; ++ move = DOWN; ++ } ++ else if (len3 == 0) ++ { ++ p2 = p->down; ++ while (p2) ++ { ++ if (type_field (p2->type) != ASN1_ETYPE_TAG) ++ { ++ p3 = p2->right; ++ asn1_delete_structure (&p2); ++ p2 = p3; ++ } ++ else ++ p2 = p2->right; ++ } ++ move = RIGHT; ++ } ++ else ++ { /* indefinite length method */ ++ p->tmp_ival = -1; ++ move = DOWN; ++ } ++ } ++ break; ++ case ASN1_ETYPE_SEQUENCE_OF: ++ case ASN1_ETYPE_SET_OF: ++ if (move == UP) ++ { ++ len2 = p->tmp_ival; ++ if (len2 == -1) ++ { /* indefinite length method */ ++ if (!HAVE_TWO (ider_len) ++ || ((der[counter]) || der[counter + 1])) ++ { ++ result = _asn1_append_sequence_set (p, &tcache); ++ if (result != 0) ++ { ++ warn (); ++ goto cleanup; ++ } ++ p = tcache.tail; ++ move = RIGHT; ++ continue; ++ } ++ ++ p->tmp_ival = 0; ++ tcache.tail = NULL; /* finished decoding this structure */ ++ tcache.head = NULL; ++ DECR_LEN (ider_len, 2); ++ counter += 2; ++ } ++ else ++ { /* definite length method */ ++ if (len2 > counter) ++ { ++ result = _asn1_append_sequence_set (p, &tcache); ++ if (result != 0) ++ { ++ warn (); ++ goto cleanup; ++ } ++ p = tcache.tail; ++ move = RIGHT; ++ continue; ++ } ++ ++ p->tmp_ival = 0; ++ tcache.tail = NULL; /* finished decoding this structure */ ++ tcache.head = NULL; ++ ++ if (len2 != counter) ++ { ++ result = ASN1_DER_ERROR; ++ warn (); ++ goto cleanup; ++ } ++ } ++ } ++ else ++ { /* move==DOWN || move==RIGHT */ ++ len3 = asn1_get_length_der (der + counter, ider_len, &len2); ++ if (IS_ERR (len3, flags)) ++ { ++ result = ASN1_DER_ERROR; ++ warn (); ++ goto cleanup; ++ } ++ ++ DECR_LEN (ider_len, len2); ++ counter += len2; ++ if (len3) ++ { ++ if (len3 > 0) ++ { /* definite length method */ ++ p->tmp_ival = counter + len3; ++ } ++ else ++ { /* indefinite length method */ ++ p->tmp_ival = -1; ++ } ++ ++ p2 = p->down; ++ if (p2 == NULL) ++ { ++ result = ASN1_DER_ERROR; ++ warn (); ++ goto cleanup; ++ } ++ ++ while ((type_field (p2->type) == ASN1_ETYPE_TAG) ++ || (type_field (p2->type) == ASN1_ETYPE_SIZE)) ++ p2 = p2->right; ++ if (p2->right == NULL) ++ { ++ result = _asn1_append_sequence_set (p, &tcache); ++ if (result != 0) ++ { ++ warn (); ++ goto cleanup; ++ } ++ } ++ p = p2; ++ } ++ } ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_ANY: ++ /* Check indefinite lenth method in an EXPLICIT TAG */ ++ ++ if (!(flags & ASN1_DECODE_FLAG_STRICT_DER) ++ && (p->type & CONST_TAG) && tag_len == 2 ++ && (der[counter - 1] == 0x80)) ++ indefinite = 1; ++ else ++ indefinite = 0; ++ ++ if (asn1_get_tag_der ++ (der + counter, ider_len, &class, &len2, ++ &tag) != ASN1_SUCCESS) ++ { ++ result = ASN1_DER_ERROR; ++ warn (); ++ goto cleanup; ++ } ++ ++ DECR_LEN (ider_len, len2); ++ ++ len4 = ++ asn1_get_length_der (der + counter + len2, ider_len, &len3); ++ if (IS_ERR (len4, flags)) ++ { ++ result = ASN1_DER_ERROR; ++ warn (); ++ goto cleanup; ++ } ++ if (len4 != -1) /* definite */ ++ { ++ len2 += len4; ++ ++ DECR_LEN (ider_len, len4 + len3); ++ _asn1_set_value_lv (p, der + counter, len2 + len3); ++ counter += len2 + len3; ++ } ++ else /* == -1 */ ++ { /* indefinite length */ ++ ider_len += len2; /* undo DECR_LEN */ ++ ++ if (counter == 0) ++ { ++ result = ASN1_DER_ERROR; ++ warn (); ++ goto cleanup; ++ } ++ ++ result = ++ _asn1_get_indefinite_length_string (der + counter, ++ ider_len, &len2); ++ if (result != ASN1_SUCCESS) ++ { ++ warn (); ++ goto cleanup; ++ } ++ ++ DECR_LEN (ider_len, len2); ++ _asn1_set_value_lv (p, der + counter, len2); ++ counter += len2; ++ ++ } ++ ++ /* Check if a couple of 0x00 are present due to an EXPLICIT TAG with ++ an indefinite length method. */ ++ if (indefinite) ++ { ++ DECR_LEN (ider_len, 2); ++ if (!der[counter] && !der[counter + 1]) ++ { ++ counter += 2; ++ } ++ else ++ { ++ result = ASN1_DER_ERROR; ++ warn (); ++ goto cleanup; ++ } ++ } ++ ++ move = RIGHT; ++ break; ++ default: ++ move = (move == UP) ? RIGHT : DOWN; ++ break; ++ } ++ } ++ ++ if (p) ++ { ++ p->end = counter - 1; ++ } ++ ++ if (p == node && move != DOWN) ++ break; ++ ++ if (move == DOWN) ++ { ++ if (p->down) ++ p = p->down; ++ else ++ move = RIGHT; ++ } ++ if ((move == RIGHT) && !(p->type & CONST_SET)) ++ { ++ if (p->right) ++ p = p->right; ++ else ++ move = UP; ++ } ++ if (move == UP) ++ p = _asn1_find_up (p); ++ } ++ ++ _asn1_delete_not_used (*element); ++ ++ if ((ider_len < 0) || ++ (!(flags & ASN1_DECODE_FLAG_ALLOW_PADDING) && (ider_len != 0))) ++ { ++ warn (); ++ result = ASN1_DER_ERROR; ++ goto cleanup; ++ } ++ ++ *max_ider_len = total_len - ider_len; ++ ++ return ASN1_SUCCESS; ++ ++cleanup: ++ asn1_delete_structure (element); ++ return result; ++} ++ ++ ++/** ++ * asn1_der_decoding: ++ * @element: pointer to an ASN1 structure. ++ * @ider: vector that contains the DER encoding. ++ * @ider_len: number of bytes of *@ider: @ider[0]..@ider[len-1]. ++ * @errorDescription: null-terminated string contains details when an ++ * error occurred. ++ * ++ * Fill the structure *@element with values of a DER encoding ++ * string. The structure must just be created with function ++ * asn1_create_element(). ++ * ++ * Note that the *@element variable is provided as a pointer for ++ * historical reasons. ++ * ++ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND ++ * if @ELEMENT is %NULL, and %ASN1_TAG_ERROR or ++ * %ASN1_DER_ERROR if the der encoding doesn't match the structure ++ * name (*@ELEMENT deleted). ++ **/ ++int ++asn1_der_decoding (asn1_node * element, const void *ider, int ider_len, ++ char *errorDescription) ++{ ++ return asn1_der_decoding2 (element, ider, &ider_len, 0, errorDescription); ++} ++ ++/** ++ * asn1_der_decoding_element: ++ * @structure: pointer to an ASN1 structure ++ * @elementName: name of the element to fill ++ * @ider: vector that contains the DER encoding of the whole structure. ++ * @len: number of bytes of *der: der[0]..der[len-1] ++ * @errorDescription: null-terminated string contains details when an ++ * error occurred. ++ * ++ * Fill the element named @ELEMENTNAME with values of a DER encoding ++ * string. The structure must just be created with function ++ * asn1_create_element(). The DER vector must contain the encoding ++ * string of the whole @STRUCTURE. If an error occurs during the ++ * decoding procedure, the *@STRUCTURE is deleted and set equal to ++ * %NULL. ++ * ++ * This function is deprecated and may just be an alias to asn1_der_decoding ++ * in future versions. Use asn1_der_decoding() instead. ++ * ++ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND ++ * if ELEMENT is %NULL or @elementName == NULL, and ++ * %ASN1_TAG_ERROR or %ASN1_DER_ERROR if the der encoding doesn't ++ * match the structure @structure (*ELEMENT deleted). ++ **/ ++int ++asn1_der_decoding_element (asn1_node * structure, const char *elementName, ++ const void *ider, int len, char *errorDescription) ++{ ++ return asn1_der_decoding (structure, ider, len, errorDescription); ++} ++ ++/** ++ * asn1_der_decoding_startEnd: ++ * @element: pointer to an ASN1 element ++ * @ider: vector that contains the DER encoding. ++ * @ider_len: number of bytes of *@ider: @ider[0]..@ider[len-1] ++ * @name_element: an element of NAME structure. ++ * @start: the position of the first byte of NAME_ELEMENT decoding ++ * (@ider[*start]) ++ * @end: the position of the last byte of NAME_ELEMENT decoding ++ * (@ider[*end]) ++ * ++ * Find the start and end point of an element in a DER encoding ++ * string. I mean that if you have a der encoding and you have already ++ * used the function asn1_der_decoding() to fill a structure, it may ++ * happen that you want to find the piece of string concerning an ++ * element of the structure. ++ * ++ * One example is the sequence "tbsCertificate" inside an X509 ++ * certificate. ++ * ++ * Note that since libtasn1 3.7 the @ider and @ider_len parameters ++ * can be omitted, if the element is already decoded using asn1_der_decoding(). ++ * ++ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND ++ * if ELEMENT is %asn1_node EMPTY or @name_element is not a valid ++ * element, %ASN1_TAG_ERROR or %ASN1_DER_ERROR if the der encoding ++ * doesn't match the structure ELEMENT. ++ **/ ++int ++asn1_der_decoding_startEnd (asn1_node element, const void *ider, int ider_len, ++ const char *name_element, int *start, int *end) ++{ ++ asn1_node node, node_to_find; ++ int result = ASN1_DER_ERROR; ++ ++ node = element; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ node_to_find = asn1_find_node (node, name_element); ++ ++ if (node_to_find == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ *start = node_to_find->start; ++ *end = node_to_find->end; ++ ++ if (*start == 0 && *end == 0) ++ { ++ if (ider == NULL || ider_len == 0) ++ return ASN1_GENERIC_ERROR; ++ ++ /* it seems asn1_der_decoding() wasn't called before. Do it now */ ++ result = asn1_der_decoding (&node, ider, ider_len, NULL); ++ if (result != ASN1_SUCCESS) ++ { ++ warn (); ++ return result; ++ } ++ ++ node_to_find = asn1_find_node (node, name_element); ++ if (node_to_find == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ *start = node_to_find->start; ++ *end = node_to_find->end; ++ } ++ ++ if (*end < *start) ++ return ASN1_GENERIC_ERROR; ++ ++ return ASN1_SUCCESS; ++} ++ ++/** ++ * asn1_expand_any_defined_by: ++ * @definitions: ASN1 definitions ++ * @element: pointer to an ASN1 structure ++ * ++ * Expands every "ANY DEFINED BY" element of a structure created from ++ * a DER decoding process (asn1_der_decoding function). The element ++ * ANY must be defined by an OBJECT IDENTIFIER. The type used to ++ * expand the element ANY is the first one following the definition of ++ * the actual value of the OBJECT IDENTIFIER. ++ * ++ * Returns: %ASN1_SUCCESS if Substitution OK, %ASN1_ERROR_TYPE_ANY if ++ * some "ANY DEFINED BY" element couldn't be expanded due to a ++ * problem in OBJECT_ID -> TYPE association, or other error codes ++ * depending on DER decoding. ++ **/ ++int ++asn1_expand_any_defined_by (asn1_node_const definitions, asn1_node * element) ++{ ++ char name[2 * ASN1_MAX_NAME_SIZE + 2], value[ASN1_MAX_NAME_SIZE]; ++ int retCode = ASN1_SUCCESS, result; ++ int len, len2, len3; ++ asn1_node_const p2; ++ asn1_node p, p3, aux = NULL; ++ char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; ++ const char *definitionsName; ++ ++ if ((definitions == NULL) || (*element == NULL)) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ definitionsName = definitions->name; ++ ++ p = *element; ++ while (p) ++ { ++ ++ switch (type_field (p->type)) ++ { ++ case ASN1_ETYPE_ANY: ++ if ((p->type & CONST_DEFINED_BY) && (p->value)) ++ { ++ /* search the "DEF_BY" element */ ++ p2 = p->down; ++ while ((p2) && (type_field (p2->type) != ASN1_ETYPE_CONSTANT)) ++ p2 = p2->right; ++ ++ if (!p2) ++ { ++ retCode = ASN1_ERROR_TYPE_ANY; ++ break; ++ } ++ ++ p3 = _asn1_find_up (p); ++ ++ if (!p3) ++ { ++ retCode = ASN1_ERROR_TYPE_ANY; ++ break; ++ } ++ ++ p3 = p3->down; ++ while (p3) ++ { ++ if (!(strcmp (p3->name, p2->name))) ++ break; ++ p3 = p3->right; ++ } ++ ++ if ((!p3) || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) || ++ (p3->value == NULL)) ++ { ++ ++ p3 = _asn1_find_up (p); ++ p3 = _asn1_find_up (p3); ++ ++ if (!p3) ++ { ++ retCode = ASN1_ERROR_TYPE_ANY; ++ break; ++ } ++ ++ p3 = p3->down; ++ ++ while (p3) ++ { ++ if (!(strcmp (p3->name, p2->name))) ++ break; ++ p3 = p3->right; ++ } ++ ++ if ((!p3) || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) ++ || (p3->value == NULL)) ++ { ++ retCode = ASN1_ERROR_TYPE_ANY; ++ break; ++ } ++ } ++ ++ /* search the OBJECT_ID into definitions */ ++ p2 = definitions->down; ++ while (p2) ++ { ++ if ((type_field (p2->type) == ASN1_ETYPE_OBJECT_ID) && ++ (p2->type & CONST_ASSIGN)) ++ { ++ snprintf (name, sizeof (name), "%s.%s", definitionsName, ++ p2->name); ++ ++ len = ASN1_MAX_NAME_SIZE; ++ result = ++ asn1_read_value (definitions, name, value, &len); ++ ++ if ((result == ASN1_SUCCESS) ++ && (!_asn1_strcmp (p3->value, value))) ++ { ++ p2 = p2->right; /* pointer to the structure to ++ use for expansion */ ++ while ((p2) && (p2->type & CONST_ASSIGN)) ++ p2 = p2->right; ++ ++ if (p2) ++ { ++ snprintf (name, sizeof (name), "%s.%s", ++ definitionsName, p2->name); ++ ++ result = ++ asn1_create_element (definitions, name, &aux); ++ if (result == ASN1_SUCCESS) ++ { ++ _asn1_cpy_name (aux, p); ++ len2 = ++ asn1_get_length_der (p->value, ++ p->value_len, &len3); ++ if (len2 < 0) ++ return ASN1_DER_ERROR; ++ ++ result = ++ asn1_der_decoding (&aux, p->value + len3, ++ len2, ++ errorDescription); ++ if (result == ASN1_SUCCESS) ++ { ++ ++ _asn1_set_right (aux, p->right); ++ _asn1_set_right (p, aux); ++ ++ result = asn1_delete_structure (&p); ++ if (result == ASN1_SUCCESS) ++ { ++ p = aux; ++ aux = NULL; ++ break; ++ } ++ else ++ { /* error with asn1_delete_structure */ ++ asn1_delete_structure (&aux); ++ retCode = result; ++ break; ++ } ++ } ++ else ++ { /* error with asn1_der_decoding */ ++ retCode = result; ++ break; ++ } ++ } ++ else ++ { /* error with asn1_create_element */ ++ retCode = result; ++ break; ++ } ++ } ++ else ++ { /* error with the pointer to the structure to exapand */ ++ retCode = ASN1_ERROR_TYPE_ANY; ++ break; ++ } ++ } ++ } ++ p2 = p2->right; ++ } /* end while */ ++ ++ if (!p2) ++ { ++ retCode = ASN1_ERROR_TYPE_ANY; ++ break; ++ } ++ ++ } ++ break; ++ default: ++ break; ++ } ++ ++ ++ if (p->down) ++ { ++ p = p->down; ++ } ++ else if (p == *element) ++ { ++ p = NULL; ++ break; ++ } ++ else if (p->right) ++ p = p->right; ++ else ++ { ++ while (1) ++ { ++ p = _asn1_find_up (p); ++ if (p == *element) ++ { ++ p = NULL; ++ break; ++ } ++ if (p->right) ++ { ++ p = p->right; ++ break; ++ } ++ } ++ } ++ } ++ ++ return retCode; ++} ++ ++/** ++ * asn1_expand_octet_string: ++ * @definitions: ASN1 definitions ++ * @element: pointer to an ASN1 structure ++ * @octetName: name of the OCTECT STRING field to expand. ++ * @objectName: name of the OBJECT IDENTIFIER field to use to define ++ * the type for expansion. ++ * ++ * Expands an "OCTET STRING" element of a structure created from a DER ++ * decoding process (the asn1_der_decoding() function). The type used ++ * for expansion is the first one following the definition of the ++ * actual value of the OBJECT IDENTIFIER indicated by OBJECTNAME. ++ * ++ * Returns: %ASN1_SUCCESS if substitution OK, %ASN1_ELEMENT_NOT_FOUND ++ * if @objectName or @octetName are not correct, ++ * %ASN1_VALUE_NOT_VALID if it wasn't possible to find the type to ++ * use for expansion, or other errors depending on DER decoding. ++ **/ ++int ++asn1_expand_octet_string (asn1_node_const definitions, asn1_node * element, ++ const char *octetName, const char *objectName) ++{ ++ char name[2 * ASN1_MAX_NAME_SIZE + 1], value[ASN1_MAX_NAME_SIZE]; ++ int retCode = ASN1_SUCCESS, result; ++ int len, len2, len3; ++ asn1_node_const p2; ++ asn1_node aux = NULL; ++ asn1_node octetNode = NULL, objectNode = NULL; ++ char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; ++ ++ if ((definitions == NULL) || (*element == NULL)) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ octetNode = asn1_find_node (*element, octetName); ++ if (octetNode == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ if (type_field (octetNode->type) != ASN1_ETYPE_OCTET_STRING) ++ return ASN1_ELEMENT_NOT_FOUND; ++ if (octetNode->value == NULL) ++ return ASN1_VALUE_NOT_FOUND; ++ ++ objectNode = asn1_find_node (*element, objectName); ++ if (objectNode == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ if (type_field (objectNode->type) != ASN1_ETYPE_OBJECT_ID) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ if (objectNode->value == NULL) ++ return ASN1_VALUE_NOT_FOUND; ++ ++ ++ /* search the OBJECT_ID into definitions */ ++ p2 = definitions->down; ++ while (p2) ++ { ++ if ((type_field (p2->type) == ASN1_ETYPE_OBJECT_ID) && ++ (p2->type & CONST_ASSIGN)) ++ { ++ strcpy (name, definitions->name); ++ strcat (name, "."); ++ strcat (name, p2->name); ++ ++ len = sizeof (value); ++ result = asn1_read_value (definitions, name, value, &len); ++ ++ if ((result == ASN1_SUCCESS) ++ && (!_asn1_strcmp (objectNode->value, value))) ++ { ++ ++ p2 = p2->right; /* pointer to the structure to ++ use for expansion */ ++ while ((p2) && (p2->type & CONST_ASSIGN)) ++ p2 = p2->right; ++ ++ if (p2) ++ { ++ strcpy (name, definitions->name); ++ strcat (name, "."); ++ strcat (name, p2->name); ++ ++ result = asn1_create_element (definitions, name, &aux); ++ if (result == ASN1_SUCCESS) ++ { ++ _asn1_cpy_name (aux, octetNode); ++ len2 = ++ asn1_get_length_der (octetNode->value, ++ octetNode->value_len, &len3); ++ if (len2 < 0) ++ return ASN1_DER_ERROR; ++ ++ result = ++ asn1_der_decoding (&aux, octetNode->value + len3, ++ len2, errorDescription); ++ if (result == ASN1_SUCCESS) ++ { ++ ++ _asn1_set_right (aux, octetNode->right); ++ _asn1_set_right (octetNode, aux); ++ ++ result = asn1_delete_structure (&octetNode); ++ if (result == ASN1_SUCCESS) ++ { ++ aux = NULL; ++ break; ++ } ++ else ++ { /* error with asn1_delete_structure */ ++ asn1_delete_structure (&aux); ++ retCode = result; ++ break; ++ } ++ } ++ else ++ { /* error with asn1_der_decoding */ ++ retCode = result; ++ break; ++ } ++ } ++ else ++ { /* error with asn1_create_element */ ++ retCode = result; ++ break; ++ } ++ } ++ else ++ { /* error with the pointer to the structure to exapand */ ++ retCode = ASN1_VALUE_NOT_VALID; ++ break; ++ } ++ } ++ } ++ ++ p2 = p2->right; ++ ++ } ++ ++ if (!p2) ++ retCode = ASN1_VALUE_NOT_VALID; ++ ++ return retCode; ++} ++ ++/*- ++ * _asn1_decode_simple_der: ++ * @etype: The type of the string to be encoded (ASN1_ETYPE_) ++ * @der: the encoded string ++ * @_der_len: the bytes of the encoded string ++ * @str: a pointer to the data ++ * @str_len: the length of the data ++ * @dflags: DECODE_FLAG_* ++ * ++ * Decodes a simple DER encoded type (e.g. a string, which is not constructed). ++ * The output is a pointer inside the @der. ++ * ++ * Returns: %ASN1_SUCCESS if successful or an error value. ++ -*/ ++static int ++_asn1_decode_simple_der (unsigned int etype, const unsigned char *der, ++ unsigned int _der_len, const unsigned char **str, ++ unsigned int *str_len, unsigned dflags) ++{ ++ int tag_len, len_len; ++ const unsigned char *p; ++ int der_len = _der_len; ++ unsigned char class; ++ unsigned long tag; ++ long ret; ++ ++ if (der == NULL || der_len == 0) ++ return ASN1_VALUE_NOT_VALID; ++ ++ if (ETYPE_OK (etype) == 0 || ETYPE_IS_STRING (etype) == 0) ++ return ASN1_VALUE_NOT_VALID; ++ ++ /* doesn't handle constructed classes */ ++ class = ETYPE_CLASS (etype); ++ if (class != ASN1_CLASS_UNIVERSAL) ++ return ASN1_VALUE_NOT_VALID; ++ ++ p = der; ++ ++ if (dflags & DECODE_FLAG_HAVE_TAG) ++ { ++ ret = asn1_get_tag_der (p, der_len, &class, &tag_len, &tag); ++ if (ret != ASN1_SUCCESS) ++ return ret; ++ ++ if (class != ETYPE_CLASS (etype) || tag != ETYPE_TAG (etype)) ++ { ++ warn (); ++ return ASN1_DER_ERROR; ++ } ++ ++ p += tag_len; ++ der_len -= tag_len; ++ if (der_len <= 0) ++ return ASN1_DER_ERROR; ++ } ++ ++ ret = asn1_get_length_der (p, der_len, &len_len); ++ if (ret < 0) ++ return ASN1_DER_ERROR; ++ ++ p += len_len; ++ der_len -= len_len; ++ if (der_len <= 0) ++ return ASN1_DER_ERROR; ++ ++ *str_len = ret; ++ *str = p; ++ ++ return ASN1_SUCCESS; ++} ++ ++/** ++ * asn1_decode_simple_der: ++ * @etype: The type of the string to be encoded (ASN1_ETYPE_) ++ * @der: the encoded string ++ * @_der_len: the bytes of the encoded string ++ * @str: a pointer to the data ++ * @str_len: the length of the data ++ * ++ * Decodes a simple DER encoded type (e.g. a string, which is not constructed). ++ * The output is a pointer inside the @der. ++ * ++ * Returns: %ASN1_SUCCESS if successful or an error value. ++ **/ ++int ++asn1_decode_simple_der (unsigned int etype, const unsigned char *der, ++ unsigned int _der_len, const unsigned char **str, ++ unsigned int *str_len) ++{ ++ return _asn1_decode_simple_der (etype, der, _der_len, str, str_len, ++ DECODE_FLAG_HAVE_TAG); ++} ++ ++static int ++append (uint8_t ** dst, unsigned *dst_size, const unsigned char *src, ++ unsigned src_size) ++{ ++ if (src_size == 0) ++ return ASN1_SUCCESS; ++ ++ *dst = _asn1_realloc (*dst, *dst_size + src_size); ++ if (*dst == NULL) ++ return ASN1_MEM_ALLOC_ERROR; ++ memcpy (*dst + *dst_size, src, src_size); ++ *dst_size += src_size; ++ return ASN1_SUCCESS; ++} ++ ++/*- ++ * _asn1_decode_simple_ber: ++ * @etype: The type of the string to be encoded (ASN1_ETYPE_) ++ * @der: the encoded string ++ * @_der_len: the bytes of the encoded string ++ * @str: a pointer to the data ++ * @str_len: the length of the data ++ * @ber_len: the total length occupied by BER (may be %NULL) ++ * @have_tag: whether a DER tag is included ++ * ++ * Decodes a BER encoded type. The output is an allocated value ++ * of the data. This decodes BER STRINGS only. Other types are ++ * decoded as DER. ++ * ++ * Returns: %ASN1_SUCCESS if successful or an error value. ++ -*/ ++static int ++_asn1_decode_simple_ber (unsigned int etype, const unsigned char *der, ++ unsigned int _der_len, unsigned char **str, ++ unsigned int *str_len, unsigned int *ber_len, ++ unsigned dflags) ++{ ++ int tag_len, len_len; ++ const unsigned char *p; ++ int der_len = _der_len; ++ uint8_t *total = NULL; ++ unsigned total_size = 0; ++ unsigned char class; ++ unsigned long tag; ++ unsigned char *out = NULL; ++ const unsigned char *cout = NULL; ++ unsigned out_len; ++ long result; ++ ++ if (ber_len) ++ *ber_len = 0; ++ ++ if (der == NULL || der_len == 0) ++ { ++ warn (); ++ return ASN1_VALUE_NOT_VALID; ++ } ++ ++ if (ETYPE_OK (etype) == 0) ++ { ++ warn (); ++ return ASN1_VALUE_NOT_VALID; ++ } ++ ++ /* doesn't handle constructed + definite classes */ ++ class = ETYPE_CLASS (etype); ++ if (class != ASN1_CLASS_UNIVERSAL) ++ { ++ warn (); ++ return ASN1_VALUE_NOT_VALID; ++ } ++ ++ p = der; ++ ++ if (dflags & DECODE_FLAG_HAVE_TAG) ++ { ++ result = asn1_get_tag_der (p, der_len, &class, &tag_len, &tag); ++ if (result != ASN1_SUCCESS) ++ { ++ warn (); ++ return result; ++ } ++ ++ if (tag != ETYPE_TAG (etype)) ++ { ++ warn (); ++ return ASN1_DER_ERROR; ++ } ++ ++ p += tag_len; ++ ++ DECR_LEN (der_len, tag_len); ++ ++ if (ber_len) ++ *ber_len += tag_len; ++ } ++ ++ /* indefinite constructed */ ++ if ((((dflags & DECODE_FLAG_CONSTRUCTED) || class == ASN1_CLASS_STRUCTURED) ++ && ETYPE_IS_STRING (etype)) && !(dflags & DECODE_FLAG_LEVEL3)) ++ { ++ if (der_len == 0) ++ { ++ warn (); ++ result = ASN1_DER_ERROR; ++ goto cleanup; ++ } ++ ++ if (der_len > 0 && p[0] == 0x80) /* indefinite */ ++ { ++ len_len = 1; ++ DECR_LEN (der_len, len_len); ++ p += len_len; ++ ++ if (ber_len) ++ *ber_len += len_len; ++ ++ /* decode the available octet strings */ ++ do ++ { ++ unsigned tmp_len; ++ unsigned flags = DECODE_FLAG_HAVE_TAG; ++ ++ if (dflags & DECODE_FLAG_LEVEL1) ++ flags |= DECODE_FLAG_LEVEL2; ++ else if (dflags & DECODE_FLAG_LEVEL2) ++ flags |= DECODE_FLAG_LEVEL3; ++ else ++ flags |= DECODE_FLAG_LEVEL1; ++ ++ result = ++ _asn1_decode_simple_ber (etype, p, der_len, &out, &out_len, ++ &tmp_len, flags); ++ if (result != ASN1_SUCCESS) ++ { ++ warn (); ++ goto cleanup; ++ } ++ ++ p += tmp_len; ++ DECR_LEN (der_len, tmp_len); ++ ++ if (ber_len) ++ *ber_len += tmp_len; ++ ++ DECR_LEN (der_len, 2); /* we need the EOC */ ++ ++ result = append (&total, &total_size, out, out_len); ++ if (result != ASN1_SUCCESS) ++ { ++ warn (); ++ goto cleanup; ++ } ++ ++ free (out); ++ out = NULL; ++ ++ if (p[0] == 0 && p[1] == 0) /* EOC */ ++ { ++ if (ber_len) ++ *ber_len += 2; ++ break; ++ } ++ ++ /* no EOC */ ++ der_len += 2; ++ ++ if (der_len == 2) ++ { ++ warn (); ++ result = ASN1_DER_ERROR; ++ goto cleanup; ++ } ++ } ++ while (1); ++ } ++ else /* constructed */ ++ { ++ long const_len; ++ ++ result = asn1_get_length_ber (p, der_len, &len_len); ++ if (result < 0) ++ { ++ warn (); ++ result = ASN1_DER_ERROR; ++ goto cleanup; ++ } ++ ++ DECR_LEN (der_len, len_len); ++ p += len_len; ++ ++ const_len = result; ++ ++ if (ber_len) ++ *ber_len += len_len; ++ ++ /* decode the available octet strings */ ++ while (const_len > 0) ++ { ++ unsigned tmp_len; ++ unsigned flags = DECODE_FLAG_HAVE_TAG; ++ ++ if (dflags & DECODE_FLAG_LEVEL1) ++ flags |= DECODE_FLAG_LEVEL2; ++ else if (dflags & DECODE_FLAG_LEVEL2) ++ flags |= DECODE_FLAG_LEVEL3; ++ else ++ flags |= DECODE_FLAG_LEVEL1; ++ ++ result = ++ _asn1_decode_simple_ber (etype, p, der_len, &out, &out_len, ++ &tmp_len, flags); ++ if (result != ASN1_SUCCESS) ++ { ++ warn (); ++ goto cleanup; ++ } ++ ++ p += tmp_len; ++ DECR_LEN (der_len, tmp_len); ++ DECR_LEN (const_len, tmp_len); ++ ++ if (ber_len) ++ *ber_len += tmp_len; ++ ++ result = append (&total, &total_size, out, out_len); ++ if (result != ASN1_SUCCESS) ++ { ++ warn (); ++ goto cleanup; ++ } ++ ++ free (out); ++ out = NULL; ++ } ++ } ++ } ++ else if (class == ETYPE_CLASS (etype)) ++ { ++ if (ber_len) ++ { ++ result = asn1_get_length_der (p, der_len, &len_len); ++ if (result < 0) ++ { ++ warn (); ++ result = ASN1_DER_ERROR; ++ goto cleanup; ++ } ++ *ber_len += result + len_len; ++ } ++ ++ /* non-string values are decoded as DER */ ++ result = ++ _asn1_decode_simple_der (etype, der, _der_len, &cout, &out_len, ++ dflags); ++ if (result != ASN1_SUCCESS) ++ { ++ warn (); ++ goto cleanup; ++ } ++ ++ result = append (&total, &total_size, cout, out_len); ++ if (result != ASN1_SUCCESS) ++ { ++ warn (); ++ goto cleanup; ++ } ++ } ++ else ++ { ++ warn (); ++ result = ASN1_DER_ERROR; ++ goto cleanup; ++ } ++ ++ *str = total; ++ *str_len = total_size; ++ ++ return ASN1_SUCCESS; ++cleanup: ++ free (out); ++ free (total); ++ return result; ++} ++ ++/** ++ * asn1_decode_simple_ber: ++ * @etype: The type of the string to be encoded (ASN1_ETYPE_) ++ * @der: the encoded string ++ * @_der_len: the bytes of the encoded string ++ * @str: a pointer to the data ++ * @str_len: the length of the data ++ * @ber_len: the total length occupied by BER (may be %NULL) ++ * ++ * Decodes a BER encoded type. The output is an allocated value ++ * of the data. This decodes BER STRINGS only. Other types are ++ * decoded as DER. ++ * ++ * Returns: %ASN1_SUCCESS if successful or an error value. ++ **/ ++int ++asn1_decode_simple_ber (unsigned int etype, const unsigned char *der, ++ unsigned int _der_len, unsigned char **str, ++ unsigned int *str_len, unsigned int *ber_len) ++{ ++ return _asn1_decode_simple_ber (etype, der, _der_len, str, str_len, ber_len, ++ DECODE_FLAG_HAVE_TAG); ++} +diff --git a/grub-core/lib/libtasn1/lib/element.c b/grub-core/lib/libtasn1/lib/element.c +new file mode 100644 +index 000000000..86e64f2cf +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/element.c +@@ -0,0 +1,1109 @@ ++/* ++ * Copyright (C) 2000-2021 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 library is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++/*****************************************************/ ++/* File: element.c */ ++/* Description: Functions with the read and write */ ++/* functions. */ ++/*****************************************************/ ++ ++ ++#include ++#include "parser_aux.h" ++#include ++#include "structure.h" ++#include "c-ctype.h" ++#include "element.h" ++ ++void ++_asn1_hierarchical_name (asn1_node_const node, char *name, int name_size) ++{ ++ asn1_node_const p; ++ char tmp_name[64]; ++ ++ p = node; ++ ++ name[0] = 0; ++ ++ while (p != NULL) ++ { ++ if (p->name[0] != 0) ++ { ++ _asn1_str_cpy (tmp_name, sizeof (tmp_name), name), ++ _asn1_str_cpy (name, name_size, p->name); ++ _asn1_str_cat (name, name_size, "."); ++ _asn1_str_cat (name, name_size, tmp_name); ++ } ++ p = _asn1_find_up (p); ++ } ++ ++ if (name[0] == 0) ++ _asn1_str_cpy (name, name_size, "ROOT"); ++} ++ ++ ++/******************************************************************/ ++/* Function : _asn1_convert_integer */ ++/* Description: converts an integer from a null terminated string */ ++/* to der decoding. The convertion from a null */ ++/* terminated string to an integer is made with */ ++/* the 'strtol' function. */ ++/* Parameters: */ ++/* value: null terminated string to convert. */ ++/* value_out: convertion result (memory must be already */ ++/* allocated). */ ++/* value_out_size: number of bytes of value_out. */ ++/* len: number of significant byte of value_out. */ ++/* Return: ASN1_MEM_ERROR or ASN1_SUCCESS */ ++/******************************************************************/ ++int ++_asn1_convert_integer (const unsigned char *value, unsigned char *value_out, ++ int value_out_size, int *len) ++{ ++ char negative; ++ unsigned char val[SIZEOF_UNSIGNED_LONG_INT]; ++ long valtmp; ++ int k, k2; ++ ++ valtmp = _asn1_strtol (value, NULL, 10); ++ ++ for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT; k++) ++ { ++ val[SIZEOF_UNSIGNED_LONG_INT - k - 1] = (valtmp >> (8 * k)) & 0xFF; ++ } ++ ++ if (val[0] & 0x80) ++ negative = 1; ++ else ++ negative = 0; ++ ++ for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT - 1; k++) ++ { ++ if (negative && (val[k] != 0xFF)) ++ break; ++ else if (!negative && val[k]) ++ break; ++ } ++ ++ if ((negative && !(val[k] & 0x80)) || (!negative && (val[k] & 0x80))) ++ k--; ++ ++ *len = SIZEOF_UNSIGNED_LONG_INT - k; ++ ++ if (SIZEOF_UNSIGNED_LONG_INT - k > value_out_size) ++ /* VALUE_OUT is too short to contain the value conversion */ ++ return ASN1_MEM_ERROR; ++ ++ if (value_out != NULL) ++ { ++ for (k2 = k; k2 < SIZEOF_UNSIGNED_LONG_INT; k2++) ++ value_out[k2 - k] = val[k2]; ++ } ++ ++#if 0 ++ printf ("_asn1_convert_integer: valueIn=%s, lenOut=%d", value, *len); ++ for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT; k++) ++ printf (", vOut[%d]=%d", k, value_out[k]); ++ printf ("\n"); ++#endif ++ ++ return ASN1_SUCCESS; ++} ++ ++/* Appends a new element into the sequence (or set) defined by this ++ * node. The new element will have a name of '?number', where number ++ * is a monotonically increased serial number. ++ * ++ * The last element in the list may be provided in @pcache, to avoid ++ * traversing the list, an expensive operation in long lists. ++ * ++ * On success it returns in @pcache the added element (which is the ++ * tail in the list of added elements). ++ */ ++int ++_asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcache) ++{ ++ asn1_node p, p2; ++ char temp[LTOSTR_MAX_SIZE + 1]; ++ long n; ++ ++ if (!node || !(node->down)) ++ return ASN1_GENERIC_ERROR; ++ ++ p = node->down; ++ while ((type_field (p->type) == ASN1_ETYPE_TAG) ++ || (type_field (p->type) == ASN1_ETYPE_SIZE)) ++ p = p->right; ++ ++ p2 = _asn1_copy_structure3 (p); ++ if (p2 == NULL) ++ return ASN1_GENERIC_ERROR; ++ ++ if (pcache == NULL || pcache->tail == NULL || pcache->head != node) ++ { ++ while (p->right) ++ { ++ p = p->right; ++ } ++ } ++ else ++ { ++ p = pcache->tail; ++ } ++ ++ _asn1_set_right (p, p2); ++ if (pcache) ++ { ++ pcache->head = node; ++ pcache->tail = p2; ++ } ++ ++ if (p->name[0] == 0) ++ _asn1_str_cpy (temp, sizeof (temp), "?1"); ++ else ++ { ++ n = strtol (p->name + 1, NULL, 0); ++ n++; ++ temp[0] = '?'; ++ _asn1_ltostr (n, temp + 1); ++ } ++ _asn1_set_name (p2, temp); ++ /* p2->type |= CONST_OPTION; */ ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++/** ++ * asn1_write_value: ++ * @node_root: pointer to a structure ++ * @name: the name of the element inside the structure that you want to set. ++ * @ivalue: vector used to specify the value to set. If len is >0, ++ * VALUE must be a two's complement form integer. if len=0 *VALUE ++ * must be a null terminated string with an integer value. ++ * @len: number of bytes of *value to use to set the value: ++ * value[0]..value[len-1] or 0 if value is a null terminated string ++ * ++ * Set the value of one element inside a structure. ++ * ++ * If an element is OPTIONAL and you want to delete it, you must use ++ * the value=NULL and len=0. Using "pkix.asn": ++ * ++ * result=asn1_write_value(cert, "tbsCertificate.issuerUniqueID", ++ * NULL, 0); ++ * ++ * Description for each type: ++ * ++ * INTEGER: VALUE must contain a two's complement form integer. ++ * ++ * value[0]=0xFF , len=1 -> integer=-1. ++ * value[0]=0xFF value[1]=0xFF , len=2 -> integer=-1. ++ * value[0]=0x01 , len=1 -> integer= 1. ++ * value[0]=0x00 value[1]=0x01 , len=2 -> integer= 1. ++ * value="123" , len=0 -> integer= 123. ++ * ++ * ENUMERATED: As INTEGER (but only with not negative numbers). ++ * ++ * BOOLEAN: VALUE must be the null terminated string "TRUE" or ++ * "FALSE" and LEN != 0. ++ * ++ * value="TRUE" , len=1 -> boolean=TRUE. ++ * value="FALSE" , len=1 -> boolean=FALSE. ++ * ++ * OBJECT IDENTIFIER: VALUE must be a null terminated string with ++ * each number separated by a dot (e.g. "1.2.3.543.1"). LEN != 0. ++ * ++ * value="1 2 840 10040 4 3" , len=1 -> OID=dsa-with-sha. ++ * ++ * UTCTime: VALUE must be a null terminated string in one of these ++ * formats: "YYMMDDhhmmssZ", "YYMMDDhhmmssZ", ++ * "YYMMDDhhmmss+hh'mm'", "YYMMDDhhmmss-hh'mm'", ++ * "YYMMDDhhmm+hh'mm'", or "YYMMDDhhmm-hh'mm'". LEN != 0. ++ * ++ * value="9801011200Z" , len=1 -> time=Jannuary 1st, 1998 ++ * at 12h 00m Greenwich Mean Time ++ * ++ * GeneralizedTime: VALUE must be in one of this format: ++ * "YYYYMMDDhhmmss.sZ", "YYYYMMDDhhmmss.sZ", ++ * "YYYYMMDDhhmmss.s+hh'mm'", "YYYYMMDDhhmmss.s-hh'mm'", ++ * "YYYYMMDDhhmm+hh'mm'", or "YYYYMMDDhhmm-hh'mm'" where ss.s ++ * indicates the seconds with any precision like "10.1" or "01.02". ++ * LEN != 0 ++ * ++ * value="2001010112001.12-0700" , len=1 -> time=Jannuary ++ * 1st, 2001 at 12h 00m 01.12s Pacific Daylight Time ++ * ++ * OCTET STRING: VALUE contains the octet string and LEN is the ++ * number of octets. ++ * ++ * value="$\backslash$x01$\backslash$x02$\backslash$x03" , ++ * len=3 -> three bytes octet string ++ * ++ * GeneralString: VALUE contains the generalstring and LEN is the ++ * number of octets. ++ * ++ * value="$\backslash$x01$\backslash$x02$\backslash$x03" , ++ * len=3 -> three bytes generalstring ++ * ++ * BIT STRING: VALUE contains the bit string organized by bytes and ++ * LEN is the number of bits. ++ * ++ * value="$\backslash$xCF" , len=6 -> bit string="110011" (six ++ * bits) ++ * ++ * CHOICE: if NAME indicates a choice type, VALUE must specify one of ++ * the alternatives with a null terminated string. LEN != 0. Using ++ * "pkix.asn"\: ++ * ++ * result=asn1_write_value(cert, ++ * "certificate1.tbsCertificate.subject", "rdnSequence", ++ * 1); ++ * ++ * ANY: VALUE indicates the der encoding of a structure. LEN != 0. ++ * ++ * SEQUENCE OF: VALUE must be the null terminated string "NEW" and ++ * LEN != 0. With this instruction another element is appended in ++ * the sequence. The name of this element will be "?1" if it's the ++ * first one, "?2" for the second and so on. ++ * ++ * Using "pkix.asn"\: ++ * ++ * result=asn1_write_value(cert, ++ * "certificate1.tbsCertificate.subject.rdnSequence", "NEW", 1); ++ * ++ * SET OF: the same as SEQUENCE OF. Using "pkix.asn": ++ * ++ * result=asn1_write_value(cert, ++ * "tbsCertificate.subject.rdnSequence.?LAST", "NEW", 1); ++ * ++ * Returns: %ASN1_SUCCESS if the value was set, ++ * %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element, and ++ * %ASN1_VALUE_NOT_VALID if @ivalue has a wrong format. ++ **/ ++int ++asn1_write_value (asn1_node node_root, const char *name, ++ const void *ivalue, int len) ++{ ++ asn1_node node, p, p2; ++ unsigned char *temp, *value_temp = NULL, *default_temp = NULL; ++ int len2, k, k2, negative; ++ size_t i; ++ const unsigned char *value = ivalue; ++ unsigned int type; ++ ++ node = asn1_find_node (node_root, name); ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ if ((node->type & CONST_OPTION) && (value == NULL) && (len == 0)) ++ { ++ asn1_delete_structure (&node); ++ return ASN1_SUCCESS; ++ } ++ ++ type = type_field (node->type); ++ ++ if ((type == ASN1_ETYPE_SEQUENCE_OF || type == ASN1_ETYPE_SET_OF) ++ && (value == NULL) && (len == 0)) ++ { ++ p = node->down; ++ while ((type_field (p->type) == ASN1_ETYPE_TAG) ++ || (type_field (p->type) == ASN1_ETYPE_SIZE)) ++ p = p->right; ++ ++ while (p->right) ++ asn1_delete_structure (&p->right); ++ ++ return ASN1_SUCCESS; ++ } ++ ++ /* Don't allow element deletion for other types */ ++ if (value == NULL) ++ { ++ return ASN1_VALUE_NOT_VALID; ++ } ++ ++ switch (type) ++ { ++ case ASN1_ETYPE_BOOLEAN: ++ if (!_asn1_strcmp (value, "TRUE")) ++ { ++ if (node->type & CONST_DEFAULT) ++ { ++ p = node->down; ++ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) ++ p = p->right; ++ if (p->type & CONST_TRUE) ++ _asn1_set_value (node, NULL, 0); ++ else ++ _asn1_set_value (node, "T", 1); ++ } ++ else ++ _asn1_set_value (node, "T", 1); ++ } ++ else if (!_asn1_strcmp (value, "FALSE")) ++ { ++ if (node->type & CONST_DEFAULT) ++ { ++ p = node->down; ++ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) ++ p = p->right; ++ if (p->type & CONST_FALSE) ++ _asn1_set_value (node, NULL, 0); ++ else ++ _asn1_set_value (node, "F", 1); ++ } ++ else ++ _asn1_set_value (node, "F", 1); ++ } ++ else ++ return ASN1_VALUE_NOT_VALID; ++ break; ++ case ASN1_ETYPE_INTEGER: ++ case ASN1_ETYPE_ENUMERATED: ++ if (len == 0) ++ { ++ if ((c_isdigit (value[0])) || (value[0] == '-')) ++ { ++ value_temp = malloc (SIZEOF_UNSIGNED_LONG_INT); ++ if (value_temp == NULL) ++ return ASN1_MEM_ALLOC_ERROR; ++ ++ _asn1_convert_integer (value, value_temp, ++ SIZEOF_UNSIGNED_LONG_INT, &len); ++ } ++ else ++ { /* is an identifier like v1 */ ++ if (!(node->type & CONST_LIST)) ++ return ASN1_VALUE_NOT_VALID; ++ p = node->down; ++ while (p) ++ { ++ if (type_field (p->type) == ASN1_ETYPE_CONSTANT) ++ { ++ if (!_asn1_strcmp (p->name, value)) ++ { ++ value_temp = malloc (SIZEOF_UNSIGNED_LONG_INT); ++ if (value_temp == NULL) ++ return ASN1_MEM_ALLOC_ERROR; ++ ++ _asn1_convert_integer (p->value, ++ value_temp, ++ SIZEOF_UNSIGNED_LONG_INT, ++ &len); ++ break; ++ } ++ } ++ p = p->right; ++ } ++ if (p == NULL) ++ return ASN1_VALUE_NOT_VALID; ++ } ++ } ++ else ++ { /* len != 0 */ ++ value_temp = malloc (len); ++ if (value_temp == NULL) ++ return ASN1_MEM_ALLOC_ERROR; ++ memcpy (value_temp, value, len); ++ } ++ ++ if (value_temp[0] & 0x80) ++ negative = 1; ++ else ++ negative = 0; ++ ++ if (negative && (type_field (node->type) == ASN1_ETYPE_ENUMERATED)) ++ { ++ free (value_temp); ++ return ASN1_VALUE_NOT_VALID; ++ } ++ ++ for (k = 0; k < len - 1; k++) ++ if (negative && (value_temp[k] != 0xFF)) ++ break; ++ else if (!negative && value_temp[k]) ++ break; ++ ++ if ((negative && !(value_temp[k] & 0x80)) || ++ (!negative && (value_temp[k] & 0x80))) ++ k--; ++ ++ _asn1_set_value_lv (node, value_temp + k, len - k); ++ ++ if (node->type & CONST_DEFAULT) ++ { ++ p = node->down; ++ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) ++ p = p->right; ++ if ((c_isdigit (p->value[0])) || (p->value[0] == '-')) ++ { ++ default_temp = malloc (SIZEOF_UNSIGNED_LONG_INT); ++ if (default_temp == NULL) ++ { ++ free (value_temp); ++ return ASN1_MEM_ALLOC_ERROR; ++ } ++ ++ _asn1_convert_integer (p->value, default_temp, ++ SIZEOF_UNSIGNED_LONG_INT, &len2); ++ } ++ else ++ { /* is an identifier like v1 */ ++ if (!(node->type & CONST_LIST)) ++ { ++ free (value_temp); ++ return ASN1_VALUE_NOT_VALID; ++ } ++ p2 = node->down; ++ while (p2) ++ { ++ if (type_field (p2->type) == ASN1_ETYPE_CONSTANT) ++ { ++ if (!_asn1_strcmp (p2->name, p->value)) ++ { ++ default_temp = malloc (SIZEOF_UNSIGNED_LONG_INT); ++ if (default_temp == NULL) ++ { ++ free (value_temp); ++ return ASN1_MEM_ALLOC_ERROR; ++ } ++ ++ _asn1_convert_integer (p2->value, ++ default_temp, ++ SIZEOF_UNSIGNED_LONG_INT, ++ &len2); ++ break; ++ } ++ } ++ p2 = p2->right; ++ } ++ if (p2 == NULL) ++ { ++ free (value_temp); ++ return ASN1_VALUE_NOT_VALID; ++ } ++ } ++ ++ ++ if ((len - k) == len2) ++ { ++ for (k2 = 0; k2 < len2; k2++) ++ if (value_temp[k + k2] != default_temp[k2]) ++ { ++ break; ++ } ++ if (k2 == len2) ++ _asn1_set_value (node, NULL, 0); ++ } ++ free (default_temp); ++ } ++ free (value_temp); ++ break; ++ case ASN1_ETYPE_OBJECT_ID: ++ for (i = 0; i < _asn1_strlen (value); i++) ++ if ((!c_isdigit (value[i])) && (value[i] != '.') && (value[i] != '+')) ++ return ASN1_VALUE_NOT_VALID; ++ if (node->type & CONST_DEFAULT) ++ { ++ p = node->down; ++ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) ++ p = p->right; ++ if (!_asn1_strcmp (value, p->value)) ++ { ++ _asn1_set_value (node, NULL, 0); ++ break; ++ } ++ } ++ _asn1_set_value (node, value, _asn1_strlen (value) + 1); ++ break; ++ case ASN1_ETYPE_UTC_TIME: ++ { ++ len = _asn1_strlen (value); ++ if (len < 11) ++ return ASN1_VALUE_NOT_VALID; ++ for (k = 0; k < 10; k++) ++ if (!c_isdigit (value[k])) ++ return ASN1_VALUE_NOT_VALID; ++ switch (len) ++ { ++ case 11: ++ if (value[10] != 'Z') ++ return ASN1_VALUE_NOT_VALID; ++ break; ++ case 13: ++ if ((!c_isdigit (value[10])) || (!c_isdigit (value[11])) || ++ (value[12] != 'Z')) ++ return ASN1_VALUE_NOT_VALID; ++ break; ++ case 15: ++ if ((value[10] != '+') && (value[10] != '-')) ++ return ASN1_VALUE_NOT_VALID; ++ for (k = 11; k < 15; k++) ++ if (!c_isdigit (value[k])) ++ return ASN1_VALUE_NOT_VALID; ++ break; ++ case 17: ++ if ((!c_isdigit (value[10])) || (!c_isdigit (value[11]))) ++ return ASN1_VALUE_NOT_VALID; ++ if ((value[12] != '+') && (value[12] != '-')) ++ return ASN1_VALUE_NOT_VALID; ++ for (k = 13; k < 17; k++) ++ if (!c_isdigit (value[k])) ++ return ASN1_VALUE_NOT_VALID; ++ break; ++ default: ++ return ASN1_VALUE_NOT_FOUND; ++ } ++ _asn1_set_value (node, value, len); ++ } ++ break; ++ case ASN1_ETYPE_GENERALIZED_TIME: ++ len = _asn1_strlen (value); ++ _asn1_set_value (node, value, len); ++ break; ++ case ASN1_ETYPE_OCTET_STRING: ++ case ASN1_ETYPE_GENERALSTRING: ++ case ASN1_ETYPE_NUMERIC_STRING: ++ case ASN1_ETYPE_IA5_STRING: ++ case ASN1_ETYPE_TELETEX_STRING: ++ case ASN1_ETYPE_PRINTABLE_STRING: ++ case ASN1_ETYPE_UNIVERSAL_STRING: ++ case ASN1_ETYPE_BMP_STRING: ++ case ASN1_ETYPE_UTF8_STRING: ++ case ASN1_ETYPE_VISIBLE_STRING: ++ if (len == 0) ++ len = _asn1_strlen (value); ++ _asn1_set_value_lv (node, value, len); ++ break; ++ case ASN1_ETYPE_BIT_STRING: ++ if (len == 0) ++ len = _asn1_strlen (value); ++ asn1_length_der ((len >> 3) + 2, NULL, &len2); ++ temp = malloc ((len >> 3) + 2 + len2); ++ if (temp == NULL) ++ return ASN1_MEM_ALLOC_ERROR; ++ ++ asn1_bit_der (value, len, temp, &len2); ++ _asn1_set_value_m (node, temp, len2); ++ temp = NULL; ++ break; ++ case ASN1_ETYPE_CHOICE: ++ p = node->down; ++ while (p) ++ { ++ if (!_asn1_strcmp (p->name, value)) ++ { ++ p2 = node->down; ++ while (p2) ++ { ++ if (p2 != p) ++ { ++ asn1_delete_structure (&p2); ++ p2 = node->down; ++ } ++ else ++ p2 = p2->right; ++ } ++ break; ++ } ++ p = p->right; ++ } ++ if (!p) ++ return ASN1_ELEMENT_NOT_FOUND; ++ break; ++ case ASN1_ETYPE_ANY: ++ _asn1_set_value_lv (node, value, len); ++ break; ++ case ASN1_ETYPE_SEQUENCE_OF: ++ case ASN1_ETYPE_SET_OF: ++ if (_asn1_strcmp (value, "NEW")) ++ return ASN1_VALUE_NOT_VALID; ++ _asn1_append_sequence_set (node, NULL); ++ break; ++ default: ++ return ASN1_ELEMENT_NOT_FOUND; ++ break; ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++#define PUT_VALUE( ptr, ptr_size, data, data_size) \ ++ *len = data_size; \ ++ if (ptr_size < data_size) { \ ++ return ASN1_MEM_ERROR; \ ++ } else { \ ++ if (ptr && data_size > 0) \ ++ memcpy (ptr, data, data_size); \ ++ } ++ ++#define PUT_STR_VALUE( ptr, ptr_size, data) \ ++ *len = _asn1_strlen (data) + 1; \ ++ if (ptr_size < *len) { \ ++ return ASN1_MEM_ERROR; \ ++ } else { \ ++ /* this strcpy is checked */ \ ++ if (ptr) { \ ++ _asn1_strcpy (ptr, data); \ ++ } \ ++ } ++ ++#define PUT_AS_STR_VALUE( ptr, ptr_size, data, data_size) \ ++ *len = data_size + 1; \ ++ if (ptr_size < *len) { \ ++ return ASN1_MEM_ERROR; \ ++ } else { \ ++ /* this strcpy is checked */ \ ++ if (ptr) { \ ++ if (data_size > 0) \ ++ memcpy (ptr, data, data_size); \ ++ ptr[data_size] = 0; \ ++ } \ ++ } ++ ++#define ADD_STR_VALUE( ptr, ptr_size, data) \ ++ *len += _asn1_strlen(data); \ ++ if (ptr_size < (int) *len) { \ ++ (*len)++; \ ++ return ASN1_MEM_ERROR; \ ++ } else { \ ++ /* this strcat is checked */ \ ++ if (ptr) _asn1_strcat (ptr, data); \ ++ } ++ ++/** ++ * asn1_read_value: ++ * @root: pointer to a structure. ++ * @name: the name of the element inside a structure that you want to read. ++ * @ivalue: vector that will contain the element's content, must be a ++ * pointer to memory cells already allocated (may be %NULL). ++ * @len: number of bytes of *value: value[0]..value[len-1]. Initialy ++ * holds the sizeof value. ++ * ++ * Returns the value of one element inside a structure. ++ * If an element is OPTIONAL and this returns ++ * %ASN1_ELEMENT_NOT_FOUND, it means that this element wasn't present ++ * in the der encoding that created the structure. The first element ++ * of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and ++ * so on. If the @root provided is a node to specific sequence element, ++ * then the keyword "?CURRENT" is also acceptable and indicates the ++ * current sequence element of this node. ++ * ++ * Note that there can be valid values with length zero. In these case ++ * this function will succeed and @len will be zero. ++ * ++ * INTEGER: VALUE will contain a two's complement form integer. ++ * ++ * integer=-1 -> value[0]=0xFF , len=1. ++ * integer=1 -> value[0]=0x01 , len=1. ++ * ++ * ENUMERATED: As INTEGER (but only with not negative numbers). ++ * ++ * BOOLEAN: VALUE will be the null terminated string "TRUE" or ++ * "FALSE" and LEN=5 or LEN=6. ++ * ++ * OBJECT IDENTIFIER: VALUE will be a null terminated string with ++ * each number separated by a dot (i.e. "1.2.3.543.1"). ++ * ++ * LEN = strlen(VALUE)+1 ++ * ++ * UTCTime: VALUE will be a null terminated string in one of these ++ * formats: "YYMMDDhhmmss+hh'mm'" or "YYMMDDhhmmss-hh'mm'". ++ * LEN=strlen(VALUE)+1. ++ * ++ * GeneralizedTime: VALUE will be a null terminated string in the ++ * same format used to set the value. ++ * ++ * OCTET STRING: VALUE will contain the octet string and LEN will be ++ * the number of octets. ++ * ++ * GeneralString: VALUE will contain the generalstring and LEN will ++ * be the number of octets. ++ * ++ * BIT STRING: VALUE will contain the bit string organized by bytes ++ * and LEN will be the number of bits. ++ * ++ * CHOICE: If NAME indicates a choice type, VALUE will specify the ++ * alternative selected. ++ * ++ * ANY: If NAME indicates an any type, VALUE will indicate the DER ++ * encoding of the structure actually used. ++ * ++ * Returns: %ASN1_SUCCESS if value is returned, ++ * %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element, ++ * %ASN1_VALUE_NOT_FOUND if there isn't any value for the element ++ * selected, and %ASN1_MEM_ERROR if The value vector isn't big enough ++ * to store the result, and in this case @len will contain the number of ++ * bytes needed. On the occasion that the stored data are of zero-length ++ * this function may return %ASN1_SUCCESS even if the provided @len is zero. ++ **/ ++int ++asn1_read_value (asn1_node_const root, const char *name, void *ivalue, ++ int *len) ++{ ++ return asn1_read_value_type (root, name, ivalue, len, NULL); ++} ++ ++/** ++ * asn1_read_value_type: ++ * @root: pointer to a structure. ++ * @name: the name of the element inside a structure that you want to read. ++ * @ivalue: vector that will contain the element's content, must be a ++ * pointer to memory cells already allocated (may be %NULL). ++ * @len: number of bytes of *value: value[0]..value[len-1]. Initialy ++ * holds the sizeof value. ++ * @etype: The type of the value read (ASN1_ETYPE) ++ * ++ * Returns the type and value of one element inside a structure. ++ * If an element is OPTIONAL and this returns ++ * %ASN1_ELEMENT_NOT_FOUND, it means that this element wasn't present ++ * in the der encoding that created the structure. The first element ++ * of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and ++ * so on. If the @root provided is a node to specific sequence element, ++ * then the keyword "?CURRENT" is also acceptable and indicates the ++ * current sequence element of this node. ++ * ++ * Note that there can be valid values with length zero. In these case ++ * this function will succeed and @len will be zero. ++ * ++ * ++ * INTEGER: VALUE will contain a two's complement form integer. ++ * ++ * integer=-1 -> value[0]=0xFF , len=1. ++ * integer=1 -> value[0]=0x01 , len=1. ++ * ++ * ENUMERATED: As INTEGER (but only with not negative numbers). ++ * ++ * BOOLEAN: VALUE will be the null terminated string "TRUE" or ++ * "FALSE" and LEN=5 or LEN=6. ++ * ++ * OBJECT IDENTIFIER: VALUE will be a null terminated string with ++ * each number separated by a dot (i.e. "1.2.3.543.1"). ++ * ++ * LEN = strlen(VALUE)+1 ++ * ++ * UTCTime: VALUE will be a null terminated string in one of these ++ * formats: "YYMMDDhhmmss+hh'mm'" or "YYMMDDhhmmss-hh'mm'". ++ * LEN=strlen(VALUE)+1. ++ * ++ * GeneralizedTime: VALUE will be a null terminated string in the ++ * same format used to set the value. ++ * ++ * OCTET STRING: VALUE will contain the octet string and LEN will be ++ * the number of octets. ++ * ++ * GeneralString: VALUE will contain the generalstring and LEN will ++ * be the number of octets. ++ * ++ * BIT STRING: VALUE will contain the bit string organized by bytes ++ * and LEN will be the number of bits. ++ * ++ * CHOICE: If NAME indicates a choice type, VALUE will specify the ++ * alternative selected. ++ * ++ * ANY: If NAME indicates an any type, VALUE will indicate the DER ++ * encoding of the structure actually used. ++ * ++ * Returns: %ASN1_SUCCESS if value is returned, ++ * %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element, ++ * %ASN1_VALUE_NOT_FOUND if there isn't any value for the element ++ * selected, and %ASN1_MEM_ERROR if The value vector isn't big enough ++ * to store the result, and in this case @len will contain the number of ++ * bytes needed. On the occasion that the stored data are of zero-length ++ * this function may return %ASN1_SUCCESS even if the provided @len is zero. ++ **/ ++int ++asn1_read_value_type (asn1_node_const root, const char *name, void *ivalue, ++ int *len, unsigned int *etype) ++{ ++ asn1_node_const node, p, p2; ++ int len2, len3, result; ++ int value_size = *len; ++ unsigned char *value = ivalue; ++ unsigned type; ++ ++ node = asn1_find_node (root, name); ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ type = type_field (node->type); ++ ++ if ((type != ASN1_ETYPE_NULL) && ++ (type != ASN1_ETYPE_CHOICE) && ++ !(node->type & CONST_DEFAULT) && !(node->type & CONST_ASSIGN) && ++ (node->value == NULL)) ++ return ASN1_VALUE_NOT_FOUND; ++ ++ if (etype) ++ *etype = type; ++ switch (type) ++ { ++ case ASN1_ETYPE_NULL: ++ PUT_STR_VALUE (value, value_size, "NULL"); ++ break; ++ case ASN1_ETYPE_BOOLEAN: ++ if ((node->type & CONST_DEFAULT) && (node->value == NULL)) ++ { ++ p = node->down; ++ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) ++ p = p->right; ++ if (p->type & CONST_TRUE) ++ { ++ PUT_STR_VALUE (value, value_size, "TRUE"); ++ } ++ else ++ { ++ PUT_STR_VALUE (value, value_size, "FALSE"); ++ } ++ } ++ else if (node->value[0] == 'T') ++ { ++ PUT_STR_VALUE (value, value_size, "TRUE"); ++ } ++ else ++ { ++ PUT_STR_VALUE (value, value_size, "FALSE"); ++ } ++ break; ++ case ASN1_ETYPE_INTEGER: ++ case ASN1_ETYPE_ENUMERATED: ++ if ((node->type & CONST_DEFAULT) && (node->value == NULL)) ++ { ++ p = node->down; ++ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) ++ p = p->right; ++ if ((c_isdigit (p->value[0])) || (p->value[0] == '-') ++ || (p->value[0] == '+')) ++ { ++ result = _asn1_convert_integer ++ (p->value, value, value_size, len); ++ if (result != ASN1_SUCCESS) ++ return result; ++ } ++ else ++ { /* is an identifier like v1 */ ++ p2 = node->down; ++ while (p2) ++ { ++ if (type_field (p2->type) == ASN1_ETYPE_CONSTANT) ++ { ++ if (!_asn1_strcmp (p2->name, p->value)) ++ { ++ result = _asn1_convert_integer ++ (p2->value, value, value_size, len); ++ if (result != ASN1_SUCCESS) ++ return result; ++ break; ++ } ++ } ++ p2 = p2->right; ++ } ++ } ++ } ++ else ++ { ++ len2 = -1; ++ result = asn1_get_octet_der ++ (node->value, node->value_len, &len2, value, value_size, len); ++ if (result != ASN1_SUCCESS) ++ return result; ++ } ++ break; ++ case ASN1_ETYPE_OBJECT_ID: ++ if (node->type & CONST_ASSIGN) ++ { ++ *len = 0; ++ if (value) ++ value[0] = 0; ++ p = node->down; ++ while (p) ++ { ++ if (type_field (p->type) == ASN1_ETYPE_CONSTANT) ++ { ++ ADD_STR_VALUE (value, value_size, p->value); ++ if (p->right) ++ { ++ ADD_STR_VALUE (value, value_size, "."); ++ } ++ } ++ p = p->right; ++ } ++ (*len)++; ++ } ++ else if ((node->type & CONST_DEFAULT) && (node->value == NULL)) ++ { ++ p = node->down; ++ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) ++ p = p->right; ++ PUT_STR_VALUE (value, value_size, p->value); ++ } ++ else ++ { ++ PUT_STR_VALUE (value, value_size, node->value); ++ } ++ break; ++ case ASN1_ETYPE_GENERALIZED_TIME: ++ case ASN1_ETYPE_UTC_TIME: ++ PUT_AS_STR_VALUE (value, value_size, node->value, node->value_len); ++ break; ++ case ASN1_ETYPE_OCTET_STRING: ++ case ASN1_ETYPE_GENERALSTRING: ++ case ASN1_ETYPE_NUMERIC_STRING: ++ case ASN1_ETYPE_IA5_STRING: ++ case ASN1_ETYPE_TELETEX_STRING: ++ case ASN1_ETYPE_PRINTABLE_STRING: ++ case ASN1_ETYPE_UNIVERSAL_STRING: ++ case ASN1_ETYPE_BMP_STRING: ++ case ASN1_ETYPE_UTF8_STRING: ++ case ASN1_ETYPE_VISIBLE_STRING: ++ len2 = -1; ++ result = asn1_get_octet_der ++ (node->value, node->value_len, &len2, value, value_size, len); ++ if (result != ASN1_SUCCESS) ++ return result; ++ break; ++ case ASN1_ETYPE_BIT_STRING: ++ len2 = -1; ++ result = asn1_get_bit_der ++ (node->value, node->value_len, &len2, value, value_size, len); ++ if (result != ASN1_SUCCESS) ++ return result; ++ break; ++ case ASN1_ETYPE_CHOICE: ++ PUT_STR_VALUE (value, value_size, node->down->name); ++ break; ++ case ASN1_ETYPE_ANY: ++ len3 = -1; ++ len2 = asn1_get_length_der (node->value, node->value_len, &len3); ++ if (len2 < 0) ++ return ASN1_DER_ERROR; ++ PUT_VALUE (value, value_size, node->value + len3, len2); ++ break; ++ default: ++ return ASN1_ELEMENT_NOT_FOUND; ++ break; ++ } ++ return ASN1_SUCCESS; ++} ++ ++ ++/** ++ * asn1_read_tag: ++ * @root: pointer to a structure ++ * @name: the name of the element inside a structure. ++ * @tagValue: variable that will contain the TAG value. ++ * @classValue: variable that will specify the TAG type. ++ * ++ * Returns the TAG and the CLASS of one element inside a structure. ++ * CLASS can have one of these constants: %ASN1_CLASS_APPLICATION, ++ * %ASN1_CLASS_UNIVERSAL, %ASN1_CLASS_PRIVATE or ++ * %ASN1_CLASS_CONTEXT_SPECIFIC. ++ * ++ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if ++ * @name is not a valid element. ++ **/ ++int ++asn1_read_tag (asn1_node_const root, const char *name, int *tagValue, ++ int *classValue) ++{ ++ asn1_node node, p, pTag; ++ ++ node = asn1_find_node (root, name); ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = node->down; ++ ++ /* pTag will points to the IMPLICIT TAG */ ++ pTag = NULL; ++ if (node->type & CONST_TAG) ++ { ++ while (p) ++ { ++ if (type_field (p->type) == ASN1_ETYPE_TAG) ++ { ++ if ((p->type & CONST_IMPLICIT) && (pTag == NULL)) ++ pTag = p; ++ else if (p->type & CONST_EXPLICIT) ++ pTag = NULL; ++ } ++ p = p->right; ++ } ++ } ++ ++ if (pTag) ++ { ++ *tagValue = _asn1_strtoul (pTag->value, NULL, 10); ++ ++ if (pTag->type & CONST_APPLICATION) ++ *classValue = ASN1_CLASS_APPLICATION; ++ else if (pTag->type & CONST_UNIVERSAL) ++ *classValue = ASN1_CLASS_UNIVERSAL; ++ else if (pTag->type & CONST_PRIVATE) ++ *classValue = ASN1_CLASS_PRIVATE; ++ else ++ *classValue = ASN1_CLASS_CONTEXT_SPECIFIC; ++ } ++ else ++ { ++ unsigned type = type_field (node->type); ++ *classValue = ASN1_CLASS_UNIVERSAL; ++ ++ switch (type) ++ { ++ CASE_HANDLED_ETYPES: ++ *tagValue = _asn1_tags[type].tag; ++ break; ++ case ASN1_ETYPE_TAG: ++ case ASN1_ETYPE_CHOICE: ++ case ASN1_ETYPE_ANY: ++ *tagValue = -1; ++ break; ++ default: ++ break; ++ } ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++/** ++ * asn1_read_node_value: ++ * @node: pointer to a node. ++ * @data: a point to a asn1_data_node_st ++ * ++ * Returns the value a data node inside a asn1_node structure. ++ * The data returned should be handled as constant values. ++ * ++ * Returns: %ASN1_SUCCESS if the node exists. ++ **/ ++int ++asn1_read_node_value (asn1_node_const node, asn1_data_node_st * data) ++{ ++ data->name = node->name; ++ data->value = node->value; ++ data->value_len = node->value_len; ++ data->type = type_field (node->type); ++ ++ return ASN1_SUCCESS; ++} +diff --git a/grub-core/lib/libtasn1/lib/element.h b/grub-core/lib/libtasn1/lib/element.h +new file mode 100644 +index 000000000..4c9a901d1 +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/element.h +@@ -0,0 +1,42 @@ ++/* ++ * Copyright (C) 2000-2021 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 library is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++#ifndef _ELEMENT_H ++# define _ELEMENT_H ++ ++ ++struct node_tail_cache_st ++{ ++ asn1_node head; /* the first element of the sequence */ ++ asn1_node tail; ++}; ++ ++int _asn1_append_sequence_set (asn1_node node, ++ struct node_tail_cache_st *pcached); ++ ++int _asn1_convert_integer (const unsigned char *value, ++ unsigned char *value_out, ++ int value_out_size, int *len); ++ ++void _asn1_hierarchical_name (asn1_node_const node, char *name, ++ int name_size); ++ ++#endif +diff --git a/grub-core/lib/libtasn1/lib/errors.c b/grub-core/lib/libtasn1/lib/errors.c +new file mode 100644 +index 000000000..4dadbd96d +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/errors.c +@@ -0,0 +1,100 @@ ++/* ++ * Copyright (C) 2002-2021 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 library is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++#include ++#ifdef STDC_HEADERS ++# include ++#endif ++ ++#define LIBTASN1_ERROR_ENTRY(name) { #name, name } ++ ++struct libtasn1_error_entry ++{ ++ const char *name; ++ int number; ++}; ++typedef struct libtasn1_error_entry libtasn1_error_entry; ++ ++static const libtasn1_error_entry error_algorithms[] = { ++ LIBTASN1_ERROR_ENTRY (ASN1_SUCCESS), ++ LIBTASN1_ERROR_ENTRY (ASN1_FILE_NOT_FOUND), ++ LIBTASN1_ERROR_ENTRY (ASN1_ELEMENT_NOT_FOUND), ++ LIBTASN1_ERROR_ENTRY (ASN1_IDENTIFIER_NOT_FOUND), ++ LIBTASN1_ERROR_ENTRY (ASN1_DER_ERROR), ++ LIBTASN1_ERROR_ENTRY (ASN1_VALUE_NOT_FOUND), ++ LIBTASN1_ERROR_ENTRY (ASN1_GENERIC_ERROR), ++ LIBTASN1_ERROR_ENTRY (ASN1_VALUE_NOT_VALID), ++ LIBTASN1_ERROR_ENTRY (ASN1_TAG_ERROR), ++ LIBTASN1_ERROR_ENTRY (ASN1_TAG_IMPLICIT), ++ LIBTASN1_ERROR_ENTRY (ASN1_ERROR_TYPE_ANY), ++ LIBTASN1_ERROR_ENTRY (ASN1_SYNTAX_ERROR), ++ LIBTASN1_ERROR_ENTRY (ASN1_MEM_ERROR), ++ LIBTASN1_ERROR_ENTRY (ASN1_MEM_ALLOC_ERROR), ++ LIBTASN1_ERROR_ENTRY (ASN1_DER_OVERFLOW), ++ LIBTASN1_ERROR_ENTRY (ASN1_NAME_TOO_LONG), ++ LIBTASN1_ERROR_ENTRY (ASN1_ARRAY_ERROR), ++ LIBTASN1_ERROR_ENTRY (ASN1_ELEMENT_NOT_EMPTY), ++ LIBTASN1_ERROR_ENTRY (ASN1_TIME_ENCODING_ERROR), ++ LIBTASN1_ERROR_ENTRY (ASN1_RECURSION), ++ {0, 0} ++}; ++ ++/** ++ * asn1_perror: ++ * @error: is an error returned by a libtasn1 function. ++ * ++ * Prints a string to stderr with a description of an error. This ++ * function is like perror(). The only difference is that it accepts ++ * an error returned by a libtasn1 function. ++ * ++ * Since: 1.6 ++ **/ ++void ++asn1_perror (int error) ++{ ++ const char *str = asn1_strerror (error); ++ fprintf (stderr, "LIBTASN1 ERROR: %s\n", str ? str : "(null)"); ++} ++ ++/** ++ * asn1_strerror: ++ * @error: is an error returned by a libtasn1 function. ++ * ++ * Returns a string with a description of an error. This function is ++ * similar to strerror. The only difference is that it accepts an ++ * error (number) returned by a libtasn1 function. ++ * ++ * Returns: Pointer to static zero-terminated string describing error ++ * code. ++ * ++ * Since: 1.6 ++ **/ ++const char * ++asn1_strerror (int error) ++{ ++ const libtasn1_error_entry *p; ++ ++ for (p = error_algorithms; p->name != NULL; p++) ++ if (p->number == error) ++ return p->name + sizeof ("ASN1_") - 1; ++ ++ return NULL; ++} +diff --git a/grub-core/lib/libtasn1/lib/gstr.c b/grub-core/lib/libtasn1/lib/gstr.c +new file mode 100644 +index 000000000..1475ed51b +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/gstr.c +@@ -0,0 +1,74 @@ ++/* ++ * Copyright (C) 2002-2021 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 library is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++#include ++#include "gstr.h" ++ ++/* These function are like strcat, strcpy. They only ++ * do bounds checking (they shouldn't cause buffer overruns), ++ * and they always produce null terminated strings. ++ * ++ * They should be used only with null terminated strings. ++ */ ++void ++_asn1_str_cat (char *dest, size_t dest_tot_size, const char *src) ++{ ++ size_t str_size = strlen (src); ++ size_t dest_size = strlen (dest); ++ ++ if (dest_tot_size - dest_size > str_size) ++ { ++ strcat (dest, src); ++ } ++ else ++ { ++ if (dest_tot_size > dest_size) ++ { ++ strncat (dest, src, (dest_tot_size - dest_size) - 1); ++ dest[dest_tot_size - 1] = 0; ++ } ++ } ++} ++ ++/* Returns the bytes copied (not including the null terminator) */ ++unsigned int ++_asn1_str_cpy (char *dest, size_t dest_tot_size, const char *src) ++{ ++ size_t str_size = strlen (src); ++ ++ if (dest_tot_size > str_size) ++ { ++ strcpy (dest, src); ++ return str_size; ++ } ++ else ++ { ++ if (dest_tot_size > 0) ++ { ++ str_size = dest_tot_size - 1; ++ memcpy (dest, src, str_size); ++ dest[str_size] = 0; ++ return str_size; ++ } ++ else ++ return 0; ++ } ++} +diff --git a/grub-core/lib/libtasn1/lib/gstr.h b/grub-core/lib/libtasn1/lib/gstr.h +new file mode 100644 +index 000000000..cd47d145c +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/gstr.h +@@ -0,0 +1,50 @@ ++/* ++ * Copyright (C) 2002-2021 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 library is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++#ifndef GSTR_H ++# define GSTR_H ++ ++unsigned int _asn1_str_cpy (char *dest, size_t dest_tot_size, ++ const char *src); ++void _asn1_str_cat (char *dest, size_t dest_tot_size, const char *src); ++ ++# define Estrcpy(x,y) _asn1_str_cpy(x,ASN1_MAX_ERROR_DESCRIPTION_SIZE,y) ++# define Estrcat(x,y) _asn1_str_cat(x,ASN1_MAX_ERROR_DESCRIPTION_SIZE,y) ++ ++inline static void ++safe_memset (void *data, int c, size_t size) ++{ ++ volatile unsigned volatile_zero = 0; ++ volatile char *vdata = (volatile char *) data; ++ ++ /* This is based on a nice trick for safe memset, ++ * sent by David Jacobson in the openssl-dev mailing list. ++ */ ++ ++ if (size > 0) ++ do ++ { ++ memset (data, c, size); ++ } ++ while (vdata[volatile_zero] != c); ++} ++ ++#endif /* GSTR_H */ +diff --git a/grub-core/lib/libtasn1/lib/int.h b/grub-core/lib/libtasn1/lib/int.h +new file mode 100644 +index 000000000..404cd1562 +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/int.h +@@ -0,0 +1,221 @@ ++/* ++ * Copyright (C) 2002-2021 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 library is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++#ifndef INT_H ++# define INT_H ++ ++# ifdef HAVE_CONFIG_H ++# include ++# endif ++ ++# include ++# include ++# include ++# include ++ ++# ifdef HAVE_SYS_TYPES_H ++# include ++# endif ++ ++# include ++ ++# define ASN1_SMALL_VALUE_SIZE 16 ++ ++/* This structure is also in libtasn1.h, but then contains less ++ fields. You cannot make any modifications to these first fields ++ without breaking ABI. */ ++struct asn1_node_st ++{ ++ /* public fields: */ ++ char name[ASN1_MAX_NAME_SIZE + 1]; /* Node name */ ++ unsigned int name_hash; ++ unsigned int type; /* Node type */ ++ unsigned char *value; /* Node value */ ++ int value_len; ++ asn1_node down; /* Pointer to the son node */ ++ asn1_node right; /* Pointer to the brother node */ ++ asn1_node left; /* Pointer to the next list element */ ++ /* private fields: */ ++ unsigned char small_value[ASN1_SMALL_VALUE_SIZE]; /* For small values */ ++ ++ /* values used during decoding/coding */ ++ int tmp_ival; ++ unsigned start; /* the start of the DER sequence - if decoded */ ++ unsigned end; /* the end of the DER sequence - if decoded */ ++}; ++ ++typedef struct tag_and_class_st ++{ ++ unsigned tag; ++ unsigned class; ++ const char *desc; ++} tag_and_class_st; ++ ++/* the types that are handled in _asn1_tags */ ++# define CASE_HANDLED_ETYPES \ ++ case ASN1_ETYPE_NULL: \ ++ case ASN1_ETYPE_BOOLEAN: \ ++ case ASN1_ETYPE_INTEGER: \ ++ case ASN1_ETYPE_ENUMERATED: \ ++ case ASN1_ETYPE_OBJECT_ID: \ ++ case ASN1_ETYPE_OCTET_STRING: \ ++ case ASN1_ETYPE_GENERALSTRING: \ ++ case ASN1_ETYPE_NUMERIC_STRING: \ ++ case ASN1_ETYPE_IA5_STRING: \ ++ case ASN1_ETYPE_TELETEX_STRING: \ ++ case ASN1_ETYPE_PRINTABLE_STRING: \ ++ case ASN1_ETYPE_UNIVERSAL_STRING: \ ++ case ASN1_ETYPE_BMP_STRING: \ ++ case ASN1_ETYPE_UTF8_STRING: \ ++ case ASN1_ETYPE_VISIBLE_STRING: \ ++ case ASN1_ETYPE_BIT_STRING: \ ++ case ASN1_ETYPE_SEQUENCE: \ ++ case ASN1_ETYPE_SEQUENCE_OF: \ ++ case ASN1_ETYPE_SET: \ ++ case ASN1_ETYPE_UTC_TIME: \ ++ case ASN1_ETYPE_GENERALIZED_TIME: \ ++ case ASN1_ETYPE_SET_OF ++ ++# define ETYPE_TAG(etype) (_asn1_tags[etype].tag) ++# define ETYPE_CLASS(etype) (_asn1_tags[etype].class) ++# define ETYPE_OK(etype) (((etype) != ASN1_ETYPE_INVALID && \ ++ (etype) <= _asn1_tags_size && \ ++ _asn1_tags[(etype)].desc != NULL)?1:0) ++ ++# define ETYPE_IS_STRING(etype) ((etype == ASN1_ETYPE_GENERALSTRING || \ ++ etype == ASN1_ETYPE_NUMERIC_STRING || etype == ASN1_ETYPE_IA5_STRING || \ ++ etype == ASN1_ETYPE_TELETEX_STRING || etype == ASN1_ETYPE_PRINTABLE_STRING || \ ++ etype == ASN1_ETYPE_UNIVERSAL_STRING || etype == ASN1_ETYPE_BMP_STRING || \ ++ etype == ASN1_ETYPE_UTF8_STRING || etype == ASN1_ETYPE_VISIBLE_STRING || \ ++ etype == ASN1_ETYPE_OCTET_STRING)?1:0) ++ ++extern unsigned int _asn1_tags_size; ++extern const tag_and_class_st _asn1_tags[]; ++ ++# define _asn1_strlen(s) strlen((const char *) s) ++# define _asn1_strtol(n,e,b) strtol((const char *) n, e, b) ++# define _asn1_strtoul(n,e,b) strtoul((const char *) n, e, b) ++# define _asn1_strcmp(a,b) strcmp((const char *)a, (const char *)b) ++# define _asn1_strcpy(a,b) strcpy((char *)a, (const char *)b) ++# define _asn1_strcat(a,b) strcat((char *)a, (const char *)b) ++ ++# if SIZEOF_UNSIGNED_LONG_INT == 8 ++# define _asn1_strtou64(n,e,b) strtoul((const char *) n, e, b) ++# else ++# define _asn1_strtou64(n,e,b) strtoull((const char *) n, e, b) ++# endif ++ ++# define MAX_LOG_SIZE 1024 /* maximum number of characters of a log message */ ++ ++/* Define used for visiting trees. */ ++# define UP 1 ++# define RIGHT 2 ++# define DOWN 3 ++ ++/***********************************************************************/ ++/* List of constants to better specify the type of typedef asn1_node_st. */ ++/***********************************************************************/ ++/* Used with TYPE_TAG */ ++# define CONST_UNIVERSAL (1U<<8) ++# define CONST_PRIVATE (1U<<9) ++# define CONST_APPLICATION (1U<<10) ++# define CONST_EXPLICIT (1U<<11) ++# define CONST_IMPLICIT (1U<<12) ++ ++# define CONST_TAG (1U<<13) /* Used in ASN.1 assignement */ ++# define CONST_OPTION (1U<<14) ++# define CONST_DEFAULT (1U<<15) ++# define CONST_TRUE (1U<<16) ++# define CONST_FALSE (1U<<17) ++ ++# define CONST_LIST (1U<<18) /* Used with TYPE_INTEGER and TYPE_BIT_STRING */ ++# define CONST_MIN_MAX (1U<<19) ++ ++# define CONST_1_PARAM (1U<<20) ++ ++# define CONST_SIZE (1U<<21) ++ ++# define CONST_DEFINED_BY (1U<<22) ++ ++/* Those two are deprecated and used for backwards compatibility */ ++# define CONST_GENERALIZED (1U<<23) ++# define CONST_UTC (1U<<24) ++ ++/* #define CONST_IMPORTS (1U<<25) */ ++ ++# define CONST_NOT_USED (1U<<26) ++# define CONST_SET (1U<<27) ++# define CONST_ASSIGN (1U<<28) ++ ++# define CONST_DOWN (1U<<29) ++# define CONST_RIGHT (1U<<30) ++ ++ ++# define ASN1_ETYPE_TIME 17 ++/****************************************/ ++/* Returns the first 8 bits. */ ++/* Used with the field type of asn1_node_st */ ++/****************************************/ ++inline static unsigned int ++type_field (unsigned int ntype) ++{ ++ return (ntype & 0xff); ++} ++ ++/* To convert old types from a static structure */ ++inline static unsigned int ++convert_old_type (unsigned int ntype) ++{ ++ unsigned int type = ntype & 0xff; ++ if (type == ASN1_ETYPE_TIME) ++ { ++ if (ntype & CONST_UTC) ++ type = ASN1_ETYPE_UTC_TIME; ++ else ++ type = ASN1_ETYPE_GENERALIZED_TIME; ++ ++ ntype &= ~(CONST_UTC | CONST_GENERALIZED); ++ ntype &= 0xffffff00; ++ ntype |= type; ++ ++ return ntype; ++ } ++ else ++ return ntype; ++} ++ ++static inline void * ++_asn1_realloc (void *ptr, size_t size) ++{ ++ void *ret; ++ ++ if (size == 0) ++ return ptr; ++ ++ ret = realloc (ptr, size); ++ if (ret == NULL) ++ { ++ free (ptr); ++ } ++ return ret; ++} ++ ++#endif /* INT_H */ +diff --git a/grub-core/lib/libtasn1/lib/parser_aux.c b/grub-core/lib/libtasn1/lib/parser_aux.c +new file mode 100644 +index 000000000..c99c5a4cb +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/parser_aux.c +@@ -0,0 +1,1178 @@ ++/* ++ * Copyright (C) 2000-2021 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 library is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++#include // WORD_BIT ++ ++#include "int.h" ++#include "parser_aux.h" ++#include "gstr.h" ++#include "structure.h" ++#include "element.h" ++#include "c-ctype.h" ++ ++char _asn1_identifierMissing[ASN1_MAX_NAME_SIZE + 1]; /* identifier name not found */ ++ ++/* Return a hash of the N bytes of X using the method described by ++ Bruno Haible in https://www.haible.de/bruno/hashfunc.html. ++ Note that while many hash functions reduce their result via modulo ++ to a 0..table_size-1 range, this function does not do that. ++ ++ This implementation has been changed from size_t -> unsigned int. */ ++ ++#ifdef __clang__ ++__attribute__((no_sanitize ("integer"))) ++#endif ++ _GL_ATTRIBUTE_PURE static unsigned int _asn1_hash_name (const char *x) ++{ ++ const unsigned char *s = (unsigned char *) x; ++ unsigned h = 0; ++ ++ while (*s) ++ h = (*s++) + ((h << 9) | (h >> (WORD_BIT - 9))); ++ ++ return h; ++} ++ ++/******************************************************/ ++/* Function : _asn1_add_static_node */ ++/* Description: creates a new NODE_ASN element and */ ++/* puts it in the list pointed by e_list. */ ++/* Parameters: */ ++/* e_list: of type list_type; must be NULL initially */ ++/* type: type of the new element (see ASN1_ETYPE_ */ ++/* and CONST_ constants). */ ++/* Return: pointer to the new element. */ ++/******************************************************/ ++asn1_node ++_asn1_add_static_node (list_type ** e_list, unsigned int type) ++{ ++ list_type *p; ++ asn1_node punt; ++ ++ punt = calloc (1, sizeof (struct asn1_node_st)); ++ if (punt == NULL) ++ return NULL; ++ ++ p = malloc (sizeof (list_type)); ++ if (p == NULL) ++ { ++ free (punt); ++ return NULL; ++ } ++ ++ p->node = punt; ++ p->next = *e_list; ++ *e_list = p; ++ ++ punt->type = type; ++ ++ return punt; ++} ++ ++static int ++_asn1_add_static_node2 (list_type ** e_list, asn1_node node) ++{ ++ list_type *p; ++ ++ p = malloc (sizeof (list_type)); ++ if (p == NULL) ++ { ++ return -1; ++ } ++ ++ p->node = node; ++ p->next = *e_list; ++ *e_list = p; ++ ++ return 0; ++} ++ ++/** ++ * asn1_find_node: ++ * @pointer: NODE_ASN element pointer. ++ * @name: null terminated string with the element's name to find. ++ * ++ * Searches for an element called @name starting from @pointer. The ++ * name is composed by different identifiers separated by dots. When ++ * *@pointer has a name, the first identifier must be the name of ++ * *@pointer, otherwise it must be the name of one child of *@pointer. ++ * ++ * Returns: the search result, or %NULL if not found. ++ **/ ++asn1_node ++asn1_find_node (asn1_node_const pointer, const char *name) ++{ ++ asn1_node_const p; ++ char *n_end, n[ASN1_MAX_NAME_SIZE + 1]; ++ const char *n_start; ++ unsigned int nsize; ++ unsigned int nhash; ++ ++ if (pointer == NULL) ++ return NULL; ++ ++ if (name == NULL) ++ return NULL; ++ ++ p = pointer; ++ n_start = name; ++ ++ if (name[0] == '?' && name[1] == 'C' && p->name[0] == '?') ++ { /* ?CURRENT */ ++ n_start = strchr (n_start, '.'); ++ if (n_start) ++ n_start++; ++ } ++ else if (p->name[0] != 0) ++ { /* has *pointer got a name ? */ ++ n_end = strchr (n_start, '.'); /* search the first dot */ ++ if (n_end) ++ { ++ nsize = n_end - n_start; ++ if (nsize >= sizeof (n)) ++ return NULL; ++ ++ memcpy (n, n_start, nsize); ++ n[nsize] = 0; ++ n_start = n_end; ++ n_start++; ++ ++ nhash = _asn1_hash_name (n); ++ } ++ else ++ { ++ _asn1_str_cpy (n, sizeof (n), n_start); ++ nhash = _asn1_hash_name (n); ++ ++ n_start = NULL; ++ } ++ ++ while (p) ++ { ++ if (nhash == p->name_hash && (!strcmp (p->name, n))) ++ break; ++ else ++ p = p->right; ++ } /* while */ ++ ++ if (p == NULL) ++ return NULL; ++ } ++ else ++ { /* *pointer doesn't have a name */ ++ if (n_start[0] == 0) ++ return (asn1_node) p; ++ } ++ ++ while (n_start) ++ { /* Has the end of NAME been reached? */ ++ n_end = strchr (n_start, '.'); /* search the next dot */ ++ if (n_end) ++ { ++ nsize = n_end - n_start; ++ if (nsize >= sizeof (n)) ++ return NULL; ++ ++ memcpy (n, n_start, nsize); ++ n[nsize] = 0; ++ n_start = n_end; ++ n_start++; ++ ++ nhash = _asn1_hash_name (n); ++ } ++ else ++ { ++ _asn1_str_cpy (n, sizeof (n), n_start); ++ nhash = _asn1_hash_name (n); ++ n_start = NULL; ++ } ++ ++ if (p->down == NULL) ++ return NULL; ++ ++ p = p->down; ++ if (p == NULL) ++ return NULL; ++ ++ /* The identifier "?LAST" indicates the last element ++ in the right chain. */ ++ if (n[0] == '?' && n[1] == 'L') /* ?LAST */ ++ { ++ while (p->right) ++ p = p->right; ++ } ++ else ++ { /* no "?LAST" */ ++ while (p) ++ { ++ if (p->name_hash == nhash && !strcmp (p->name, n)) ++ break; ++ else ++ p = p->right; ++ } ++ } ++ if (p == NULL) ++ return NULL; ++ } /* while */ ++ ++ return (asn1_node) p; ++} ++ ++ ++/******************************************************************/ ++/* Function : _asn1_set_value */ ++/* Description: sets the field VALUE in a NODE_ASN element. The */ ++/* previous value (if exist) will be lost */ ++/* Parameters: */ ++/* node: element pointer. */ ++/* value: pointer to the value that you want to set. */ ++/* len: character number of value. */ ++/* Return: pointer to the NODE_ASN element. */ ++/******************************************************************/ ++asn1_node ++_asn1_set_value (asn1_node node, const void *value, unsigned int len) ++{ ++ if (node == NULL) ++ return node; ++ if (node->value) ++ { ++ if (node->value != node->small_value) ++ free (node->value); ++ node->value = NULL; ++ node->value_len = 0; ++ } ++ ++ if (!len) ++ return node; ++ ++ if (len < sizeof (node->small_value)) ++ { ++ node->value = node->small_value; ++ } ++ else ++ { ++ node->value = malloc (len); ++ if (node->value == NULL) ++ return NULL; ++ } ++ node->value_len = len; ++ ++ memcpy (node->value, value, len); ++ return node; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_set_value_lv */ ++/* Description: sets the field VALUE in a NODE_ASN element. The */ ++/* previous value (if exist) will be lost. The value */ ++/* given is stored as an length-value format (LV */ ++/* Parameters: */ ++/* node: element pointer. */ ++/* value: pointer to the value that you want to set. */ ++/* len: character number of value. */ ++/* Return: pointer to the NODE_ASN element. */ ++/******************************************************************/ ++asn1_node ++_asn1_set_value_lv (asn1_node node, const void *value, unsigned int len) ++{ ++ int len2; ++ void *temp; ++ ++ if (node == NULL) ++ return node; ++ ++ asn1_length_der (len, NULL, &len2); ++ temp = malloc (len + len2); ++ if (temp == NULL) ++ return NULL; ++ ++ asn1_octet_der (value, len, temp, &len2); ++ return _asn1_set_value_m (node, temp, len2); ++} ++ ++/* the same as _asn1_set_value except that it sets an already malloc'ed ++ * value. ++ */ ++asn1_node ++_asn1_set_value_m (asn1_node node, void *value, unsigned int len) ++{ ++ if (node == NULL) ++ return node; ++ ++ if (node->value) ++ { ++ if (node->value != node->small_value) ++ free (node->value); ++ node->value = NULL; ++ node->value_len = 0; ++ } ++ ++ if (!len) ++ return node; ++ ++ node->value = value; ++ node->value_len = len; ++ ++ return node; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_append_value */ ++/* Description: appends to the field VALUE in a NODE_ASN element. */ ++/* */ ++/* Parameters: */ ++/* node: element pointer. */ ++/* value: pointer to the value that you want to be appended. */ ++/* len: character number of value. */ ++/* Return: pointer to the NODE_ASN element. */ ++/******************************************************************/ ++asn1_node ++_asn1_append_value (asn1_node node, const void *value, unsigned int len) ++{ ++ if (node == NULL) ++ return node; ++ ++ if (node->value == NULL) ++ return _asn1_set_value (node, value, len); ++ ++ if (len == 0) ++ return node; ++ ++ if (node->value == node->small_value) ++ { ++ /* value is in node */ ++ int prev_len = node->value_len; ++ node->value_len += len; ++ node->value = malloc (node->value_len); ++ if (node->value == NULL) ++ { ++ node->value_len = 0; ++ return NULL; ++ } ++ ++ if (prev_len > 0) ++ memcpy (node->value, node->small_value, prev_len); ++ ++ memcpy (&node->value[prev_len], value, len); ++ ++ return node; ++ } ++ else /* if (node->value != NULL && node->value != node->small_value) */ ++ { ++ /* value is allocated */ ++ int prev_len = node->value_len; ++ node->value_len += len; ++ ++ node->value = _asn1_realloc (node->value, node->value_len); ++ if (node->value == NULL) ++ { ++ node->value_len = 0; ++ return NULL; ++ } ++ ++ memcpy (&node->value[prev_len], value, len); ++ ++ return node; ++ } ++} ++ ++/******************************************************************/ ++/* Function : _asn1_set_name */ ++/* Description: sets the field NAME in a NODE_ASN element. The */ ++/* previous value (if exist) will be lost */ ++/* Parameters: */ ++/* node: element pointer. */ ++/* name: a null terminated string with the name that you want */ ++/* to set. */ ++/* Return: pointer to the NODE_ASN element. */ ++/******************************************************************/ ++asn1_node ++_asn1_set_name (asn1_node node, const char *name) ++{ ++ if (node == NULL) ++ return node; ++ ++ _asn1_str_cpy (node->name, sizeof (node->name), name ? name : ""); ++ node->name_hash = _asn1_hash_name (node->name); ++ ++ return node; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_cpy_name */ ++/* Description: copies the field NAME in a NODE_ASN element. */ ++/* Parameters: */ ++/* dst: a dest element pointer. */ ++/* src: a source element pointer. */ ++/* Return: pointer to the NODE_ASN element. */ ++/******************************************************************/ ++asn1_node ++_asn1_cpy_name (asn1_node dst, asn1_node_const src) ++{ ++ if (dst == NULL) ++ return dst; ++ ++ if (src == NULL) ++ { ++ dst->name[0] = 0; ++ dst->name_hash = _asn1_hash_name (dst->name); ++ return dst; ++ } ++ ++ _asn1_str_cpy (dst->name, sizeof (dst->name), src->name); ++ dst->name_hash = src->name_hash; ++ ++ return dst; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_set_right */ ++/* Description: sets the field RIGHT in a NODE_ASN element. */ ++/* Parameters: */ ++/* node: element pointer. */ ++/* right: pointer to a NODE_ASN element that you want be pointed*/ ++/* by NODE. */ ++/* Return: pointer to *NODE. */ ++/******************************************************************/ ++asn1_node ++_asn1_set_right (asn1_node node, asn1_node right) ++{ ++ if (node == NULL) ++ return node; ++ node->right = right; ++ if (right) ++ right->left = node; ++ return node; ++} ++ ++ ++/******************************************************************/ ++/* Function : _asn1_get_last_right */ ++/* Description: return the last element along the right chain. */ ++/* Parameters: */ ++/* node: starting element pointer. */ ++/* Return: pointer to the last element along the right chain. */ ++/******************************************************************/ ++asn1_node ++_asn1_get_last_right (asn1_node_const node) ++{ ++ asn1_node_const p; ++ ++ if (node == NULL) ++ return NULL; ++ p = node; ++ while (p->right) ++ p = p->right; ++ return (asn1_node) p; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_remove_node */ ++/* Description: gets free the memory allocated for an NODE_ASN */ ++/* element (not the elements pointed by it). */ ++/* Parameters: */ ++/* node: NODE_ASN element pointer. */ ++/* flags: ASN1_DELETE_FLAG_* */ ++/******************************************************************/ ++void ++_asn1_remove_node (asn1_node node, unsigned int flags) ++{ ++ if (node == NULL) ++ return; ++ ++ if (node->value != NULL) ++ { ++ if (flags & ASN1_DELETE_FLAG_ZEROIZE) ++ { ++ safe_memset (node->value, 0, node->value_len); ++ } ++ ++ if (node->value != node->small_value) ++ free (node->value); ++ } ++ free (node); ++} ++ ++/******************************************************************/ ++/* Function : _asn1_find_up */ ++/* Description: return the father of the NODE_ASN element. */ ++/* Parameters: */ ++/* node: NODE_ASN element pointer. */ ++/* Return: Null if not found. */ ++/******************************************************************/ ++asn1_node ++_asn1_find_up (asn1_node_const node) ++{ ++ asn1_node_const p; ++ ++ if (node == NULL) ++ return NULL; ++ ++ p = node; ++ ++ while ((p->left != NULL) && (p->left->right == p)) ++ p = p->left; ++ ++ return p->left; ++} ++ ++static unsigned ++_asn1_is_up (asn1_node_const up_cand, asn1_node_const down) ++{ ++ asn1_node_const d, u; ++ ++ if (up_cand == NULL || down == NULL) ++ return 0; ++ ++ d = down; ++ ++ while ((u = _asn1_find_up (d)) != NULL && u != d) ++ { ++ if (u == up_cand) ++ return 1; ++ d = u; ++ } ++ ++ return 0; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_delete_node_from_list */ ++/* Description: deletes the list element given */ ++/******************************************************************/ ++void ++_asn1_delete_node_from_list (list_type * list, asn1_node node) ++{ ++ list_type *p = list; ++ ++ while (p) ++ { ++ if (p->node == node) ++ p->node = NULL; ++ p = p->next; ++ } ++} ++ ++/******************************************************************/ ++/* Function : _asn1_delete_list */ ++/* Description: deletes the list elements (not the elements */ ++/* pointed by them). */ ++/******************************************************************/ ++void ++_asn1_delete_list (list_type * e_list) ++{ ++ list_type *p; ++ ++ while (e_list) ++ { ++ p = e_list; ++ e_list = e_list->next; ++ free (p); ++ } ++} ++ ++/******************************************************************/ ++/* Function : _asn1_delete_list_and nodes */ ++/* Description: deletes the list elements and the elements */ ++/* pointed by them. */ ++/******************************************************************/ ++void ++_asn1_delete_list_and_nodes (list_type * e_list) ++{ ++ list_type *p; ++ ++ while (e_list) ++ { ++ p = e_list; ++ e_list = e_list->next; ++ _asn1_remove_node (p->node, 0); ++ free (p); ++ } ++} ++ ++ ++char * ++_asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE]) ++{ ++ uint64_t d, r; ++ char temp[LTOSTR_MAX_SIZE]; ++ int count, k, start; ++ uint64_t val; ++ ++ if (v < 0) ++ { ++ str[0] = '-'; ++ start = 1; ++ val = -((uint64_t) v); ++ } ++ else ++ { ++ val = v; ++ start = 0; ++ } ++ ++ count = 0; ++ do ++ { ++ d = val / 10; ++ r = val - d * 10; ++ temp[start + count] = '0' + (char) r; ++ count++; ++ val = d; ++ } ++ while (val && ((start + count) < LTOSTR_MAX_SIZE - 1)); ++ ++ for (k = 0; k < count; k++) ++ str[k + start] = temp[start + count - k - 1]; ++ str[count + start] = 0; ++ return str; ++} ++ ++ ++/******************************************************************/ ++/* Function : _asn1_change_integer_value */ ++/* Description: converts into DER coding the value assign to an */ ++/* INTEGER constant. */ ++/* Parameters: */ ++/* node: root of an ASN1element. */ ++/* Return: */ ++/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */ ++/* otherwise ASN1_SUCCESS */ ++/******************************************************************/ ++int ++_asn1_change_integer_value (asn1_node node) ++{ ++ asn1_node p; ++ unsigned char val[SIZEOF_UNSIGNED_LONG_INT]; ++ unsigned char val2[SIZEOF_UNSIGNED_LONG_INT + 1]; ++ int len; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = node; ++ while (p) ++ { ++ if ((type_field (p->type) == ASN1_ETYPE_INTEGER) ++ && (p->type & CONST_ASSIGN)) ++ { ++ if (p->value) ++ { ++ _asn1_convert_integer (p->value, val, sizeof (val), &len); ++ asn1_octet_der (val, len, val2, &len); ++ _asn1_set_value (p, val2, len); ++ } ++ } ++ ++ if (p->down) ++ { ++ p = p->down; ++ } ++ else ++ { ++ if (p == node) ++ p = NULL; ++ else if (p->right) ++ p = p->right; ++ else ++ { ++ while (1) ++ { ++ p = _asn1_find_up (p); ++ if (p == node) ++ { ++ p = NULL; ++ break; ++ } ++ if (p && p->right) ++ { ++ p = p->right; ++ break; ++ } ++ } ++ } ++ } ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++#define MAX_CONSTANTS 1024 ++/******************************************************************/ ++/* Function : _asn1_expand_object_id */ ++/* Description: expand the IDs of an OBJECT IDENTIFIER constant. */ ++/* Parameters: */ ++/* list: root of an object list */ ++/* node: root of an ASN1 element. */ ++/* Return: */ ++/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */ ++/* otherwise ASN1_SUCCESS */ ++/******************************************************************/ ++int ++_asn1_expand_object_id (list_type ** list, asn1_node node) ++{ ++ asn1_node p, p2, p3, p4, p5; ++ char name_root[ASN1_MAX_NAME_SIZE], name2[2 * ASN1_MAX_NAME_SIZE + 1]; ++ int move, tlen, tries; ++ unsigned max_constants; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ _asn1_str_cpy (name_root, sizeof (name_root), node->name); ++ ++ p = node; ++ move = DOWN; ++ tries = 0; ++ ++ while (!((p == node) && (move == UP))) ++ { ++ if (move != UP) ++ { ++ if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) ++ && (p->type & CONST_ASSIGN)) ++ { ++ p2 = p->down; ++ if (p2 && (type_field (p2->type) == ASN1_ETYPE_CONSTANT)) ++ { ++ if (p2->value && !c_isdigit (p2->value[0])) ++ { ++ _asn1_str_cpy (name2, sizeof (name2), name_root); ++ _asn1_str_cat (name2, sizeof (name2), "."); ++ _asn1_str_cat (name2, sizeof (name2), ++ (char *) p2->value); ++ p3 = asn1_find_node (node, name2); ++ if (!p3 || _asn1_is_up (p2, p3) || ++ (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) || ++ !(p3->type & CONST_ASSIGN)) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ _asn1_set_down (p, p2->right); ++ if (p2->down) ++ _asn1_delete_structure (*list, &p2->down, 0); ++ _asn1_delete_node_from_list (*list, p2); ++ _asn1_remove_node (p2, 0); ++ p2 = p; ++ p4 = p3->down; ++ max_constants = 0; ++ while (p4) ++ { ++ if (type_field (p4->type) == ASN1_ETYPE_CONSTANT) ++ { ++ max_constants++; ++ if (max_constants == MAX_CONSTANTS) ++ return ASN1_RECURSION; ++ ++ p5 = ++ _asn1_add_single_node (ASN1_ETYPE_CONSTANT); ++ _asn1_set_name (p5, p4->name); ++ if (p4->value) ++ { ++ tlen = _asn1_strlen (p4->value); ++ if (tlen > 0) ++ _asn1_set_value (p5, p4->value, tlen + 1); ++ } ++ _asn1_add_static_node2 (list, p5); ++ ++ if (p2 == p) ++ { ++ _asn1_set_right (p5, p->down); ++ _asn1_set_down (p, p5); ++ } ++ else ++ { ++ _asn1_set_right (p5, p2->right); ++ _asn1_set_right (p2, p5); ++ } ++ p2 = p5; ++ } ++ p4 = p4->right; ++ } ++ move = DOWN; ++ ++ tries++; ++ if (tries >= EXPAND_OBJECT_ID_MAX_RECURSION) ++ return ASN1_RECURSION; ++ ++ continue; ++ } ++ } ++ } ++ move = DOWN; ++ } ++ else ++ move = RIGHT; ++ ++ tries = 0; ++ if (move == DOWN) ++ { ++ if (p->down) ++ p = p->down; ++ else ++ move = RIGHT; ++ } ++ ++ if (p == node) ++ { ++ move = UP; ++ continue; ++ } ++ ++ if (move == RIGHT) ++ { ++ if (p && p->right) ++ p = p->right; ++ else ++ move = UP; ++ } ++ if (move == UP) ++ p = _asn1_find_up (p); ++ } ++ ++ /*******************************/ ++ /* expand DEFAULT */ ++ /*******************************/ ++ p = node; ++ move = DOWN; ++ ++ while (!((p == node) && (move == UP))) ++ { ++ if (move != UP) ++ { ++ if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) && ++ (p->type & CONST_DEFAULT)) ++ { ++ p2 = p->down; ++ if (p2 && (type_field (p2->type) == ASN1_ETYPE_DEFAULT)) ++ { ++ _asn1_str_cpy (name2, sizeof (name2), name_root); ++ _asn1_str_cat (name2, sizeof (name2), "."); ++ if (p2->value) ++ _asn1_str_cat (name2, sizeof (name2), (char *) p2->value); ++ p3 = asn1_find_node (node, name2); ++ if (!p3 || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) ++ || !(p3->type & CONST_ASSIGN)) ++ return ASN1_ELEMENT_NOT_FOUND; ++ p4 = p3->down; ++ name2[0] = 0; ++ while (p4) ++ { ++ if (type_field (p4->type) == ASN1_ETYPE_CONSTANT) ++ { ++ if (p4->value == NULL) ++ return ASN1_VALUE_NOT_FOUND; ++ ++ if (name2[0]) ++ _asn1_str_cat (name2, sizeof (name2), "."); ++ _asn1_str_cat (name2, sizeof (name2), ++ (char *) p4->value); ++ } ++ p4 = p4->right; ++ } ++ tlen = strlen (name2); ++ if (tlen > 0) ++ _asn1_set_value (p2, name2, tlen + 1); ++ } ++ } ++ move = DOWN; ++ } ++ else ++ move = RIGHT; ++ ++ if (move == DOWN) ++ { ++ if (p->down) ++ p = p->down; ++ else ++ move = RIGHT; ++ } ++ ++ if (p == node) ++ { ++ move = UP; ++ continue; ++ } ++ ++ if (move == RIGHT) ++ { ++ if (p && p->right) ++ p = p->right; ++ else ++ move = UP; ++ } ++ if (move == UP) ++ p = _asn1_find_up (p); ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++/******************************************************************/ ++/* Function : _asn1_type_set_config */ ++/* Description: sets the CONST_SET and CONST_NOT_USED properties */ ++/* in the fields of the SET elements. */ ++/* Parameters: */ ++/* node: root of an ASN1 element. */ ++/* Return: */ ++/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */ ++/* otherwise ASN1_SUCCESS */ ++/******************************************************************/ ++int ++_asn1_type_set_config (asn1_node node) ++{ ++ asn1_node p, p2; ++ int move; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = node; ++ move = DOWN; ++ ++ while (!((p == node) && (move == UP))) ++ { ++ if (move != UP) ++ { ++ if (type_field (p->type) == ASN1_ETYPE_SET) ++ { ++ p2 = p->down; ++ while (p2) ++ { ++ if (type_field (p2->type) != ASN1_ETYPE_TAG) ++ p2->type |= CONST_SET | CONST_NOT_USED; ++ p2 = p2->right; ++ } ++ } ++ move = DOWN; ++ } ++ else ++ move = RIGHT; ++ ++ if (move == DOWN) ++ { ++ if (p->down) ++ p = p->down; ++ else ++ move = RIGHT; ++ } ++ ++ if (p == node) ++ { ++ move = UP; ++ continue; ++ } ++ ++ if (move == RIGHT) ++ { ++ if (p && p->right) ++ p = p->right; ++ else ++ move = UP; ++ } ++ if (move == UP) ++ p = _asn1_find_up (p); ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++/******************************************************************/ ++/* Function : _asn1_check_identifier */ ++/* Description: checks the definitions of all the identifiers */ ++/* and the first element of an OBJECT_ID (e.g. {pkix 0 4}). */ ++/* The _asn1_identifierMissing global variable is filled if */ ++/* necessary. */ ++/* Parameters: */ ++/* node: root of an ASN1 element. */ ++/* Return: */ ++/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */ ++/* ASN1_IDENTIFIER_NOT_FOUND if an identifier is not defined, */ ++/* otherwise ASN1_SUCCESS */ ++/******************************************************************/ ++int ++_asn1_check_identifier (asn1_node_const node) ++{ ++ asn1_node_const p, p2; ++ char name2[ASN1_MAX_NAME_SIZE * 2 + 2]; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = node; ++ while (p) ++ { ++ if (p->value && type_field (p->type) == ASN1_ETYPE_IDENTIFIER) ++ { ++ _asn1_str_cpy (name2, sizeof (name2), node->name); ++ _asn1_str_cat (name2, sizeof (name2), "."); ++ _asn1_str_cat (name2, sizeof (name2), (char *) p->value); ++ p2 = asn1_find_node (node, name2); ++ if (p2 == NULL) ++ { ++ if (p->value) ++ _asn1_str_cpy (_asn1_identifierMissing, ++ sizeof (_asn1_identifierMissing), ++ (char *) p->value); ++ else ++ _asn1_strcpy (_asn1_identifierMissing, "(null)"); ++ return ASN1_IDENTIFIER_NOT_FOUND; ++ } ++ } ++ else if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) && ++ (p->type & CONST_DEFAULT)) ++ { ++ p2 = p->down; ++ if (p2 && (type_field (p2->type) == ASN1_ETYPE_DEFAULT)) ++ { ++ _asn1_str_cpy (name2, sizeof (name2), node->name); ++ if (p2->value) ++ { ++ _asn1_str_cat (name2, sizeof (name2), "."); ++ _asn1_str_cat (name2, sizeof (name2), (char *) p2->value); ++ _asn1_str_cpy (_asn1_identifierMissing, ++ sizeof (_asn1_identifierMissing), ++ (char *) p2->value); ++ } ++ else ++ _asn1_strcpy (_asn1_identifierMissing, "(null)"); ++ ++ p2 = asn1_find_node (node, name2); ++ if (!p2 || (type_field (p2->type) != ASN1_ETYPE_OBJECT_ID) || ++ !(p2->type & CONST_ASSIGN)) ++ return ASN1_IDENTIFIER_NOT_FOUND; ++ else ++ _asn1_identifierMissing[0] = 0; ++ } ++ } ++ else if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) && ++ (p->type & CONST_ASSIGN)) ++ { ++ p2 = p->down; ++ if (p2 && (type_field (p2->type) == ASN1_ETYPE_CONSTANT)) ++ { ++ if (p2->value && !c_isdigit (p2->value[0])) ++ { ++ _asn1_str_cpy (name2, sizeof (name2), node->name); ++ _asn1_str_cat (name2, sizeof (name2), "."); ++ _asn1_str_cat (name2, sizeof (name2), (char *) p2->value); ++ _asn1_str_cpy (_asn1_identifierMissing, ++ sizeof (_asn1_identifierMissing), ++ (char *) p2->value); ++ ++ p2 = asn1_find_node (node, name2); ++ if (!p2 || (type_field (p2->type) != ASN1_ETYPE_OBJECT_ID) ++ || !(p2->type & CONST_ASSIGN)) ++ return ASN1_IDENTIFIER_NOT_FOUND; ++ else ++ _asn1_identifierMissing[0] = 0; ++ } ++ } ++ } ++ ++ if (p->down) ++ { ++ p = p->down; ++ } ++ else if (p->right) ++ p = p->right; ++ else ++ { ++ while (p) ++ { ++ p = _asn1_find_up (p); ++ if (p == node) ++ { ++ p = NULL; ++ break; ++ } ++ if (p && p->right) ++ { ++ p = p->right; ++ break; ++ } ++ } ++ } ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++/******************************************************************/ ++/* Function : _asn1_set_default_tag */ ++/* Description: sets the default IMPLICIT or EXPLICIT property in */ ++/* the tagged elements that don't have this declaration. */ ++/* Parameters: */ ++/* node: pointer to a DEFINITIONS element. */ ++/* Return: */ ++/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL or not a pointer to */ ++/* a DEFINITIONS element, */ ++/* otherwise ASN1_SUCCESS */ ++/******************************************************************/ ++int ++_asn1_set_default_tag (asn1_node node) ++{ ++ asn1_node p; ++ ++ if ((node == NULL) || (type_field (node->type) != ASN1_ETYPE_DEFINITIONS)) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = node; ++ while (p) ++ { ++ if ((type_field (p->type) == ASN1_ETYPE_TAG) && ++ !(p->type & CONST_EXPLICIT) && !(p->type & CONST_IMPLICIT)) ++ { ++ if (node->type & CONST_EXPLICIT) ++ p->type |= CONST_EXPLICIT; ++ else ++ p->type |= CONST_IMPLICIT; ++ } ++ ++ if (p->down) ++ { ++ p = p->down; ++ } ++ else if (p->right) ++ p = p->right; ++ else ++ { ++ while (1) ++ { ++ p = _asn1_find_up (p); ++ if (p == node) ++ { ++ p = NULL; ++ break; ++ } ++ if (p && p->right) ++ { ++ p = p->right; ++ break; ++ } ++ } ++ } ++ } ++ ++ return ASN1_SUCCESS; ++} +diff --git a/grub-core/lib/libtasn1/lib/parser_aux.h b/grub-core/lib/libtasn1/lib/parser_aux.h +new file mode 100644 +index 000000000..b21235eb1 +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/parser_aux.h +@@ -0,0 +1,172 @@ ++/* ++ * Copyright (C) 2000-2021 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 library is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++#ifndef _PARSER_AUX_H ++# define _PARSER_AUX_H ++ ++/***********************************************/ ++/* Type: list_type */ ++/* Description: type used in the list during */ ++/* the structure creation. */ ++/***********************************************/ ++typedef struct list_struct ++{ ++ asn1_node node; ++ struct list_struct *next; ++} list_type; ++ ++/***************************************/ ++/* Functions used by ASN.1 parser */ ++/***************************************/ ++asn1_node _asn1_add_static_node (list_type ** e_list, unsigned int type); ++ ++void _asn1_delete_list (list_type * e_list); ++ ++void _asn1_delete_list_and_nodes (list_type * e_list); ++ ++void _asn1_delete_node_from_list (list_type * list, asn1_node node); ++ ++asn1_node ++_asn1_set_value (asn1_node node, const void *value, unsigned int len); ++ ++asn1_node _asn1_set_value_m (asn1_node node, void *value, unsigned int len); ++ ++asn1_node ++_asn1_set_value_lv (asn1_node node, const void *value, unsigned int len); ++ ++asn1_node ++_asn1_append_value (asn1_node node, const void *value, unsigned int len); ++ ++asn1_node _asn1_set_name (asn1_node node, const char *name); ++ ++asn1_node _asn1_cpy_name (asn1_node dst, asn1_node_const src); ++ ++asn1_node _asn1_set_right (asn1_node node, asn1_node right); ++ ++asn1_node _asn1_get_last_right (asn1_node_const node); ++ ++void _asn1_remove_node (asn1_node node, unsigned int flags); ++ ++/* Max 64-bit integer length is 20 chars + 1 for sign + 1 for null termination */ ++# define LTOSTR_MAX_SIZE 22 ++char *_asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE]); ++ ++asn1_node _asn1_find_up (asn1_node_const node); ++ ++int _asn1_change_integer_value (asn1_node node); ++ ++# define EXPAND_OBJECT_ID_MAX_RECURSION 16 ++int _asn1_expand_object_id (list_type ** list, asn1_node node); ++ ++int _asn1_type_set_config (asn1_node node); ++ ++int _asn1_check_identifier (asn1_node_const node); ++ ++int _asn1_set_default_tag (asn1_node node); ++ ++/******************************************************************/ ++/* Function : _asn1_get_right */ ++/* Description: returns the element pointed by the RIGHT field of */ ++/* a NODE_ASN element. */ ++/* Parameters: */ ++/* node: NODE_ASN element pointer. */ ++/* Return: field RIGHT of NODE. */ ++/******************************************************************/ ++inline static asn1_node ++_asn1_get_right (asn1_node_const node) ++{ ++ if (node == NULL) ++ return NULL; ++ return node->right; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_set_down */ ++/* Description: sets the field DOWN in a NODE_ASN element. */ ++/* Parameters: */ ++/* node: element pointer. */ ++/* down: pointer to a NODE_ASN element that you want be pointed */ ++/* by NODE. */ ++/* Return: pointer to *NODE. */ ++/******************************************************************/ ++inline static asn1_node ++_asn1_set_down (asn1_node node, asn1_node down) ++{ ++ if (node == NULL) ++ return node; ++ node->down = down; ++ if (down) ++ down->left = node; ++ return node; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_get_down */ ++/* Description: returns the element pointed by the DOWN field of */ ++/* a NODE_ASN element. */ ++/* Parameters: */ ++/* node: NODE_ASN element pointer. */ ++/* Return: field DOWN of NODE. */ ++/******************************************************************/ ++inline static asn1_node ++_asn1_get_down (asn1_node_const node) ++{ ++ if (node == NULL) ++ return NULL; ++ return node->down; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_get_name */ ++/* Description: returns the name of a NODE_ASN element. */ ++/* Parameters: */ ++/* node: NODE_ASN element pointer. */ ++/* Return: a null terminated string. */ ++/******************************************************************/ ++inline static char * ++_asn1_get_name (asn1_node_const node) ++{ ++ if (node == NULL) ++ return NULL; ++ return (char *) node->name; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_mod_type */ ++/* Description: change the field TYPE of an NODE_ASN element. */ ++/* The new value is the old one | (bitwise or) the */ ++/* paramener VALUE. */ ++/* Parameters: */ ++/* node: NODE_ASN element pointer. */ ++/* value: the integer value that must be or-ed with the current */ ++/* value of field TYPE. */ ++/* Return: NODE pointer. */ ++/******************************************************************/ ++inline static asn1_node ++_asn1_mod_type (asn1_node node, unsigned int value) ++{ ++ if (node == NULL) ++ return node; ++ node->type |= value; ++ return node; ++} ++ ++#endif +diff --git a/grub-core/lib/libtasn1/lib/structure.c b/grub-core/lib/libtasn1/lib/structure.c +new file mode 100644 +index 000000000..c0802202e +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/structure.c +@@ -0,0 +1,1225 @@ ++/* ++ * Copyright (C) 2002-2021 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 library is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++ ++/*****************************************************/ ++/* File: structure.c */ ++/* Description: Functions to create and delete an */ ++/* ASN1 tree. */ ++/*****************************************************/ ++ ++ ++#include ++#include ++#include "parser_aux.h" ++#include ++ ++ ++extern char _asn1_identifierMissing[]; ++ ++ ++/******************************************************/ ++/* Function : _asn1_add_single_node */ ++/* Description: creates a new NODE_ASN element. */ ++/* Parameters: */ ++/* type: type of the new element (see ASN1_ETYPE_ */ ++/* and CONST_ constants). */ ++/* Return: pointer to the new element. */ ++/******************************************************/ ++asn1_node ++_asn1_add_single_node (unsigned int type) ++{ ++ asn1_node punt; ++ ++ punt = calloc (1, sizeof (struct asn1_node_st)); ++ if (punt == NULL) ++ return NULL; ++ ++ punt->type = type; ++ ++ return punt; ++} ++ ++ ++/******************************************************************/ ++/* Function : _asn1_find_left */ ++/* Description: returns the NODE_ASN element with RIGHT field that*/ ++/* points the element NODE. */ ++/* Parameters: */ ++/* node: NODE_ASN element pointer. */ ++/* Return: NULL if not found. */ ++/******************************************************************/ ++asn1_node ++_asn1_find_left (asn1_node_const node) ++{ ++ if ((node == NULL) || (node->left == NULL) || (node->left->down == node)) ++ return NULL; ++ ++ return node->left; ++} ++ ++ ++int ++_asn1_create_static_structure (asn1_node_const pointer, ++ char *output_file_name, char *vector_name) ++{ ++ FILE *file; ++ asn1_node_const p; ++ unsigned long t; ++ ++ file = fopen (output_file_name, "w"); ++ ++ if (file == NULL) ++ return ASN1_FILE_NOT_FOUND; ++ ++ fprintf (file, "#if HAVE_CONFIG_H\n"); ++ fprintf (file, "# include \"config.h\"\n"); ++ fprintf (file, "#endif\n\n"); ++ ++ fprintf (file, "#include \n\n"); ++ ++ fprintf (file, "const asn1_static_node %s[] = {\n", vector_name); ++ ++ p = pointer; ++ ++ while (p) ++ { ++ fprintf (file, " { "); ++ ++ if (p->name[0] != 0) ++ fprintf (file, "\"%s\", ", p->name); ++ else ++ fprintf (file, "NULL, "); ++ ++ t = p->type; ++ if (p->down) ++ t |= CONST_DOWN; ++ if (p->right) ++ t |= CONST_RIGHT; ++ ++ fprintf (file, "%lu, ", t); ++ ++ if (p->value) ++ fprintf (file, "\"%s\"},\n", p->value); ++ else ++ fprintf (file, "NULL },\n"); ++ ++ if (p->down) ++ { ++ p = p->down; ++ } ++ else if (p->right) ++ { ++ p = p->right; ++ } ++ else ++ { ++ while (1) ++ { ++ p = _asn1_find_up (p); ++ if (p == pointer) ++ { ++ p = NULL; ++ break; ++ } ++ if (p->right) ++ { ++ p = p->right; ++ break; ++ } ++ } ++ } ++ } ++ ++ fprintf (file, " { NULL, 0, NULL }\n};\n"); ++ ++ fclose (file); ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++/** ++ * asn1_array2tree: ++ * @array: specify the array that contains ASN.1 declarations ++ * @definitions: return the pointer to the structure created by ++ * *ARRAY ASN.1 declarations ++ * @errorDescription: return the error description. ++ * ++ * Creates the structures needed to manage the ASN.1 definitions. ++ * @array is a vector created by asn1_parser2array(). ++ * ++ * Returns: %ASN1_SUCCESS if structure was created correctly, ++ * %ASN1_ELEMENT_NOT_EMPTY if *@definitions not NULL, ++ * %ASN1_IDENTIFIER_NOT_FOUND if in the file there is an identifier ++ * that is not defined (see @errorDescription for more information), ++ * %ASN1_ARRAY_ERROR if the array pointed by @array is wrong. ++ **/ ++int ++asn1_array2tree (const asn1_static_node * array, asn1_node * definitions, ++ char *errorDescription) ++{ ++ asn1_node p, p_last = NULL; ++ unsigned long k; ++ int move; ++ int result; ++ unsigned int type; ++ list_type *e_list = NULL; ++ ++ if (errorDescription) ++ errorDescription[0] = 0; ++ ++ if (*definitions != NULL) ++ return ASN1_ELEMENT_NOT_EMPTY; ++ ++ move = UP; ++ ++ for (k = 0; array[k].value || array[k].type || array[k].name; k++) ++ { ++ type = convert_old_type (array[k].type); ++ ++ p = _asn1_add_static_node (&e_list, type & (~CONST_DOWN)); ++ if (array[k].name) ++ _asn1_set_name (p, array[k].name); ++ if (array[k].value) ++ _asn1_set_value (p, array[k].value, strlen (array[k].value) + 1); ++ ++ if (*definitions == NULL) ++ *definitions = p; ++ ++ if (move == DOWN) ++ { ++ if (p_last && p_last->down) ++ _asn1_delete_structure (e_list, &p_last->down, 0); ++ _asn1_set_down (p_last, p); ++ } ++ else if (move == RIGHT) ++ { ++ if (p_last && p_last->right) ++ _asn1_delete_structure (e_list, &p_last->right, 0); ++ _asn1_set_right (p_last, p); ++ } ++ ++ p_last = p; ++ ++ if (type & CONST_DOWN) ++ move = DOWN; ++ else if (type & CONST_RIGHT) ++ move = RIGHT; ++ else ++ { ++ while (p_last != *definitions) ++ { ++ p_last = _asn1_find_up (p_last); ++ ++ if (p_last == NULL) ++ break; ++ ++ if (p_last->type & CONST_RIGHT) ++ { ++ p_last->type &= ~CONST_RIGHT; ++ move = RIGHT; ++ break; ++ } ++ } /* while */ ++ } ++ } /* while */ ++ ++ if (p_last == *definitions) ++ { ++ result = _asn1_check_identifier (*definitions); ++ if (result == ASN1_SUCCESS) ++ { ++ _asn1_change_integer_value (*definitions); ++ result = _asn1_expand_object_id (&e_list, *definitions); ++ } ++ } ++ else ++ { ++ result = ASN1_ARRAY_ERROR; ++ } ++ ++ if (errorDescription != NULL) ++ { ++ if (result == ASN1_IDENTIFIER_NOT_FOUND) ++ { ++ Estrcpy (errorDescription, ":: identifier '"); ++ Estrcat (errorDescription, _asn1_identifierMissing); ++ Estrcat (errorDescription, "' not found"); ++ } ++ else ++ errorDescription[0] = 0; ++ } ++ ++ if (result != ASN1_SUCCESS) ++ { ++ _asn1_delete_list_and_nodes (e_list); ++ *definitions = NULL; ++ } ++ else ++ _asn1_delete_list (e_list); ++ ++ return result; ++} ++ ++/** ++ * asn1_delete_structure: ++ * @structure: pointer to the structure that you want to delete. ++ * ++ * Deletes the structure *@structure. At the end, *@structure is set ++ * to NULL. ++ * ++ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if ++ * *@structure was NULL. ++ **/ ++int ++asn1_delete_structure (asn1_node * structure) ++{ ++ return _asn1_delete_structure (NULL, structure, 0); ++} ++ ++/** ++ * asn1_delete_structure2: ++ * @structure: pointer to the structure that you want to delete. ++ * @flags: additional flags (see %ASN1_DELETE_FLAG_ZEROIZE) ++ * ++ * Deletes the structure *@structure. At the end, *@structure is set ++ * to NULL. ++ * ++ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if ++ * *@structure was NULL. ++ **/ ++int ++asn1_delete_structure2 (asn1_node * structure, unsigned int flags) ++{ ++ return _asn1_delete_structure (NULL, structure, flags); ++} ++ ++int ++_asn1_delete_structure (list_type * e_list, asn1_node * structure, ++ unsigned int flags) ++{ ++ asn1_node p, p2, p3; ++ ++ if (*structure == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = *structure; ++ while (p) ++ { ++ if (p->down) ++ { ++ p = p->down; ++ } ++ else ++ { /* no down */ ++ p2 = p->right; ++ if (p != *structure) ++ { ++ p3 = _asn1_find_up (p); ++ _asn1_set_down (p3, p2); ++ if (e_list) ++ _asn1_delete_node_from_list (e_list, p); ++ _asn1_remove_node (p, flags); ++ p = p3; ++ } ++ else ++ { /* p==root */ ++ p3 = _asn1_find_left (p); ++ if (!p3) ++ { ++ p3 = _asn1_find_up (p); ++ if (p3) ++ _asn1_set_down (p3, p2); ++ else ++ { ++ if (p->right) ++ p->right->left = NULL; ++ } ++ } ++ else ++ _asn1_set_right (p3, p2); ++ if (e_list) ++ _asn1_delete_node_from_list (e_list, p); ++ _asn1_remove_node (p, flags); ++ p = NULL; ++ } ++ } ++ } ++ ++ *structure = NULL; ++ return ASN1_SUCCESS; ++} ++ ++ ++/** ++ * asn1_delete_element: ++ * @structure: pointer to the structure that contains the element you ++ * want to delete. ++ * @element_name: element's name you want to delete. ++ * ++ * Deletes the element named *@element_name inside *@structure. ++ * ++ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if ++ * the @element_name was not found. ++ **/ ++int ++asn1_delete_element (asn1_node structure, const char *element_name) ++{ ++ asn1_node p2, p3, source_node; ++ ++ source_node = asn1_find_node (structure, element_name); ++ ++ if (source_node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p2 = source_node->right; ++ p3 = _asn1_find_left (source_node); ++ if (!p3) ++ { ++ p3 = _asn1_find_up (source_node); ++ if (p3) ++ _asn1_set_down (p3, p2); ++ else if (source_node->right) ++ source_node->right->left = NULL; ++ } ++ else ++ _asn1_set_right (p3, p2); ++ ++ return asn1_delete_structure (&source_node); ++} ++ ++#ifndef __clang_analyzer__ ++asn1_node ++_asn1_copy_structure3 (asn1_node_const source_node) ++{ ++ asn1_node_const p_s; ++ asn1_node dest_node, p_d, p_d_prev; ++ int move; ++ ++ if (source_node == NULL) ++ return NULL; ++ ++ dest_node = _asn1_add_single_node (source_node->type); ++ if (dest_node == NULL) ++ return dest_node; ++ ++ p_s = source_node; ++ p_d = dest_node; ++ ++ move = DOWN; ++ ++ do ++ { ++ if (move != UP) ++ { ++ if (p_s->name[0] != 0) ++ _asn1_cpy_name (p_d, p_s); ++ if (p_s->value) ++ _asn1_set_value (p_d, p_s->value, p_s->value_len); ++ if (p_s->down) ++ { ++ p_s = p_s->down; ++ p_d_prev = p_d; ++ p_d = _asn1_add_single_node (p_s->type); ++ _asn1_set_down (p_d_prev, p_d); ++ continue; ++ } ++ p_d->start = p_s->start; ++ p_d->end = p_s->end; ++ } ++ ++ if (p_s == source_node) ++ break; ++ ++ if (p_s->right) ++ { ++ move = RIGHT; ++ p_s = p_s->right; ++ p_d_prev = p_d; ++ p_d = _asn1_add_single_node (p_s->type); ++ _asn1_set_right (p_d_prev, p_d); ++ } ++ else ++ { ++ move = UP; ++ p_s = _asn1_find_up (p_s); ++ p_d = _asn1_find_up (p_d); ++ } ++ } ++ while (p_s != source_node); ++ return dest_node; ++} ++#else ++ ++/* Non-production code */ ++asn1_node ++_asn1_copy_structure3 (asn1_node_const source_node) ++{ ++ return NULL; ++} ++#endif /* __clang_analyzer__ */ ++ ++ ++static asn1_node ++_asn1_copy_structure2 (asn1_node_const root, const char *source_name) ++{ ++ asn1_node source_node; ++ ++ source_node = asn1_find_node (root, source_name); ++ ++ return _asn1_copy_structure3 (source_node); ++ ++} ++ ++ ++static int ++_asn1_type_choice_config (asn1_node node) ++{ ++ asn1_node p, p2, p3, p4; ++ int move, tlen; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = node; ++ move = DOWN; ++ ++ while (!((p == node) && (move == UP))) ++ { ++ if (move != UP) ++ { ++ if ((type_field (p->type) == ASN1_ETYPE_CHOICE) ++ && (p->type & CONST_TAG)) ++ { ++ p2 = p->down; ++ while (p2) ++ { ++ if (type_field (p2->type) != ASN1_ETYPE_TAG) ++ { ++ p2->type |= CONST_TAG; ++ p3 = _asn1_find_left (p2); ++ while (p3) ++ { ++ if (type_field (p3->type) == ASN1_ETYPE_TAG) ++ { ++ p4 = _asn1_add_single_node (p3->type); ++ tlen = _asn1_strlen (p3->value); ++ if (tlen > 0) ++ _asn1_set_value (p4, p3->value, tlen + 1); ++ _asn1_set_right (p4, p2->down); ++ _asn1_set_down (p2, p4); ++ } ++ p3 = _asn1_find_left (p3); ++ } ++ } ++ p2 = p2->right; ++ } ++ p->type &= ~(CONST_TAG); ++ p2 = p->down; ++ while (p2) ++ { ++ p3 = p2->right; ++ if (type_field (p2->type) == ASN1_ETYPE_TAG) ++ asn1_delete_structure (&p2); ++ p2 = p3; ++ } ++ } ++ move = DOWN; ++ } ++ else ++ move = RIGHT; ++ ++ if (move == DOWN) ++ { ++ if (p->down) ++ p = p->down; ++ else ++ move = RIGHT; ++ } ++ ++ if (p == node) ++ { ++ move = UP; ++ continue; ++ } ++ ++ if (move == RIGHT) ++ { ++ if (p->right) ++ p = p->right; ++ else ++ move = UP; ++ } ++ if (move == UP) ++ p = _asn1_find_up (p); ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++static int ++_asn1_expand_identifier (asn1_node * node, asn1_node_const root) ++{ ++ asn1_node p, p2, p3; ++ char name2[ASN1_MAX_NAME_SIZE + 2]; ++ int move; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = *node; ++ move = DOWN; ++ ++ while (!((p == *node) && (move == UP))) ++ { ++ if (move != UP) ++ { ++ if (type_field (p->type) == ASN1_ETYPE_IDENTIFIER) ++ { ++ snprintf (name2, sizeof (name2), "%s.%s", root->name, p->value); ++ p2 = _asn1_copy_structure2 (root, name2); ++ if (p2 == NULL) ++ { ++ return ASN1_IDENTIFIER_NOT_FOUND; ++ } ++ _asn1_cpy_name (p2, p); ++ p2->right = p->right; ++ p2->left = p->left; ++ if (p->right) ++ p->right->left = p2; ++ p3 = p->down; ++ if (p3) ++ { ++ while (p3->right) ++ p3 = p3->right; ++ _asn1_set_right (p3, p2->down); ++ _asn1_set_down (p2, p->down); ++ } ++ ++ p3 = _asn1_find_left (p); ++ if (p3) ++ _asn1_set_right (p3, p2); ++ else ++ { ++ p3 = _asn1_find_up (p); ++ if (p3) ++ _asn1_set_down (p3, p2); ++ else ++ { ++ p2->left = NULL; ++ } ++ } ++ ++ if (p->type & CONST_SIZE) ++ p2->type |= CONST_SIZE; ++ if (p->type & CONST_TAG) ++ p2->type |= CONST_TAG; ++ if (p->type & CONST_OPTION) ++ p2->type |= CONST_OPTION; ++ if (p->type & CONST_DEFAULT) ++ p2->type |= CONST_DEFAULT; ++ if (p->type & CONST_SET) ++ p2->type |= CONST_SET; ++ if (p->type & CONST_NOT_USED) ++ p2->type |= CONST_NOT_USED; ++ ++ if (p == *node) ++ *node = p2; ++ _asn1_remove_node (p, 0); ++ p = p2; ++ move = DOWN; ++ continue; ++ } ++ move = DOWN; ++ } ++ else ++ move = RIGHT; ++ ++ if (move == DOWN) ++ { ++ if (p->down) ++ p = p->down; ++ else ++ move = RIGHT; ++ } ++ ++ if (p == *node) ++ { ++ move = UP; ++ continue; ++ } ++ ++ if (move == RIGHT) ++ { ++ if (p->right) ++ p = p->right; ++ else ++ move = UP; ++ } ++ if (move == UP) ++ p = _asn1_find_up (p); ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++/** ++ * asn1_create_element: ++ * @definitions: pointer to the structure returned by "parser_asn1" function ++ * @source_name: the name of the type of the new structure (must be ++ * inside p_structure). ++ * @element: pointer to the structure created. ++ * ++ * Creates a structure of type @source_name. Example using ++ * "pkix.asn": ++ * ++ * rc = asn1_create_element(cert_def, "PKIX1.Certificate", certptr); ++ * ++ * Returns: %ASN1_SUCCESS if creation OK, %ASN1_ELEMENT_NOT_FOUND if ++ * @source_name is not known. ++ **/ ++int ++asn1_create_element (asn1_node_const definitions, const char *source_name, ++ asn1_node * element) ++{ ++ asn1_node dest_node; ++ int res; ++ ++ dest_node = _asn1_copy_structure2 (definitions, source_name); ++ ++ if (dest_node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ _asn1_set_name (dest_node, ""); ++ ++ res = _asn1_expand_identifier (&dest_node, definitions); ++ _asn1_type_choice_config (dest_node); ++ ++ *element = dest_node; ++ ++ return res; ++} ++ ++ ++/** ++ * asn1_print_structure: ++ * @out: pointer to the output file (e.g. stdout). ++ * @structure: pointer to the structure that you want to visit. ++ * @name: an element of the structure ++ * @mode: specify how much of the structure to print, can be ++ * %ASN1_PRINT_NAME, %ASN1_PRINT_NAME_TYPE, ++ * %ASN1_PRINT_NAME_TYPE_VALUE, or %ASN1_PRINT_ALL. ++ * ++ * Prints on the @out file descriptor the structure's tree starting ++ * from the @name element inside the structure @structure. ++ **/ ++void ++asn1_print_structure (FILE * out, asn1_node_const structure, const char *name, ++ int mode) ++{ ++ asn1_node_const p, root; ++ int k, indent = 0, len, len2, len3; ++ ++ if (out == NULL) ++ return; ++ ++ root = asn1_find_node (structure, name); ++ ++ if (root == NULL) ++ return; ++ ++ p = root; ++ while (p) ++ { ++ if (mode == ASN1_PRINT_ALL) ++ { ++ for (k = 0; k < indent; k++) ++ fprintf (out, " "); ++ fprintf (out, "name:"); ++ if (p->name[0] != 0) ++ fprintf (out, "%s ", p->name); ++ else ++ fprintf (out, "NULL "); ++ } ++ else ++ { ++ switch (type_field (p->type)) ++ { ++ case ASN1_ETYPE_CONSTANT: ++ case ASN1_ETYPE_TAG: ++ case ASN1_ETYPE_SIZE: ++ break; ++ default: ++ for (k = 0; k < indent; k++) ++ fprintf (out, " "); ++ fprintf (out, "name:"); ++ if (p->name[0] != 0) ++ fprintf (out, "%s ", p->name); ++ else ++ fprintf (out, "NULL "); ++ } ++ } ++ ++ if (mode != ASN1_PRINT_NAME) ++ { ++ unsigned type = type_field (p->type); ++ switch (type) ++ { ++ case ASN1_ETYPE_CONSTANT: ++ if (mode == ASN1_PRINT_ALL) ++ fprintf (out, "type:CONST"); ++ break; ++ case ASN1_ETYPE_TAG: ++ if (mode == ASN1_PRINT_ALL) ++ fprintf (out, "type:TAG"); ++ break; ++ case ASN1_ETYPE_SIZE: ++ if (mode == ASN1_PRINT_ALL) ++ fprintf (out, "type:SIZE"); ++ break; ++ case ASN1_ETYPE_DEFAULT: ++ fprintf (out, "type:DEFAULT"); ++ break; ++ case ASN1_ETYPE_IDENTIFIER: ++ fprintf (out, "type:IDENTIFIER"); ++ break; ++ case ASN1_ETYPE_ANY: ++ fprintf (out, "type:ANY"); ++ break; ++ case ASN1_ETYPE_CHOICE: ++ fprintf (out, "type:CHOICE"); ++ break; ++ case ASN1_ETYPE_DEFINITIONS: ++ fprintf (out, "type:DEFINITIONS"); ++ break; ++ CASE_HANDLED_ETYPES: ++ fprintf (out, "%s", _asn1_tags[type].desc); ++ break; ++ default: ++ break; ++ } ++ } ++ ++ if ((mode == ASN1_PRINT_NAME_TYPE_VALUE) || (mode == ASN1_PRINT_ALL)) ++ { ++ switch (type_field (p->type)) ++ { ++ case ASN1_ETYPE_CONSTANT: ++ if (mode == ASN1_PRINT_ALL) ++ if (p->value) ++ fprintf (out, " value:%s", p->value); ++ break; ++ case ASN1_ETYPE_TAG: ++ if (mode == ASN1_PRINT_ALL) ++ if (p->value) ++ fprintf (out, " value:%s", p->value); ++ break; ++ case ASN1_ETYPE_SIZE: ++ if (mode == ASN1_PRINT_ALL) ++ if (p->value) ++ fprintf (out, " value:%s", p->value); ++ break; ++ case ASN1_ETYPE_DEFAULT: ++ if (p->value) ++ fprintf (out, " value:%s", p->value); ++ else if (p->type & CONST_TRUE) ++ fprintf (out, " value:TRUE"); ++ else if (p->type & CONST_FALSE) ++ fprintf (out, " value:FALSE"); ++ break; ++ case ASN1_ETYPE_IDENTIFIER: ++ if (p->value) ++ fprintf (out, " value:%s", p->value); ++ break; ++ case ASN1_ETYPE_INTEGER: ++ if (p->value) ++ { ++ len2 = -1; ++ len = asn1_get_length_der (p->value, p->value_len, &len2); ++ fprintf (out, " value:0x"); ++ if (len > 0) ++ for (k = 0; k < len; k++) ++ fprintf (out, "%02x", (unsigned) (p->value)[k + len2]); ++ } ++ break; ++ case ASN1_ETYPE_ENUMERATED: ++ if (p->value) ++ { ++ len2 = -1; ++ len = asn1_get_length_der (p->value, p->value_len, &len2); ++ fprintf (out, " value:0x"); ++ if (len > 0) ++ for (k = 0; k < len; k++) ++ fprintf (out, "%02x", (unsigned) (p->value)[k + len2]); ++ } ++ break; ++ case ASN1_ETYPE_BOOLEAN: ++ if (p->value) ++ { ++ if (p->value[0] == 'T') ++ fprintf (out, " value:TRUE"); ++ else if (p->value[0] == 'F') ++ fprintf (out, " value:FALSE"); ++ } ++ break; ++ case ASN1_ETYPE_BIT_STRING: ++ if (p->value) ++ { ++ len2 = -1; ++ len = asn1_get_length_der (p->value, p->value_len, &len2); ++ if (len > 0) ++ { ++ fprintf (out, " value(%i):", ++ (len - 1) * 8 - (p->value[len2])); ++ for (k = 1; k < len; k++) ++ fprintf (out, "%02x", ++ (unsigned) (p->value)[k + len2]); ++ } ++ } ++ break; ++ case ASN1_ETYPE_GENERALIZED_TIME: ++ case ASN1_ETYPE_UTC_TIME: ++ if (p->value) ++ { ++ fprintf (out, " value:"); ++ for (k = 0; k < p->value_len; k++) ++ fprintf (out, "%c", (p->value)[k]); ++ } ++ break; ++ case ASN1_ETYPE_GENERALSTRING: ++ case ASN1_ETYPE_NUMERIC_STRING: ++ case ASN1_ETYPE_IA5_STRING: ++ case ASN1_ETYPE_TELETEX_STRING: ++ case ASN1_ETYPE_PRINTABLE_STRING: ++ case ASN1_ETYPE_UNIVERSAL_STRING: ++ case ASN1_ETYPE_UTF8_STRING: ++ case ASN1_ETYPE_VISIBLE_STRING: ++ if (p->value) ++ { ++ len2 = -1; ++ len = asn1_get_length_der (p->value, p->value_len, &len2); ++ fprintf (out, " value:"); ++ if (len > 0) ++ for (k = 0; k < len; k++) ++ fprintf (out, "%c", (p->value)[k + len2]); ++ } ++ break; ++ case ASN1_ETYPE_BMP_STRING: ++ case ASN1_ETYPE_OCTET_STRING: ++ if (p->value) ++ { ++ len2 = -1; ++ len = asn1_get_length_der (p->value, p->value_len, &len2); ++ fprintf (out, " value:"); ++ if (len > 0) ++ for (k = 0; k < len; k++) ++ fprintf (out, "%02x", (unsigned) (p->value)[k + len2]); ++ } ++ break; ++ case ASN1_ETYPE_OBJECT_ID: ++ if (p->value) ++ fprintf (out, " value:%s", p->value); ++ break; ++ case ASN1_ETYPE_ANY: ++ if (p->value) ++ { ++ len3 = -1; ++ len2 = asn1_get_length_der (p->value, p->value_len, &len3); ++ fprintf (out, " value:"); ++ if (len2 > 0) ++ for (k = 0; k < len2; k++) ++ fprintf (out, "%02x", (unsigned) (p->value)[k + len3]); ++ } ++ break; ++ case ASN1_ETYPE_SET: ++ case ASN1_ETYPE_SET_OF: ++ case ASN1_ETYPE_CHOICE: ++ case ASN1_ETYPE_DEFINITIONS: ++ case ASN1_ETYPE_SEQUENCE_OF: ++ case ASN1_ETYPE_SEQUENCE: ++ case ASN1_ETYPE_NULL: ++ break; ++ default: ++ break; ++ } ++ } ++ ++ if (mode == ASN1_PRINT_ALL) ++ { ++ if (p->type & 0x1FFFFF00) ++ { ++ fprintf (out, " attr:"); ++ if (p->type & CONST_UNIVERSAL) ++ fprintf (out, "UNIVERSAL,"); ++ if (p->type & CONST_PRIVATE) ++ fprintf (out, "PRIVATE,"); ++ if (p->type & CONST_APPLICATION) ++ fprintf (out, "APPLICATION,"); ++ if (p->type & CONST_EXPLICIT) ++ fprintf (out, "EXPLICIT,"); ++ if (p->type & CONST_IMPLICIT) ++ fprintf (out, "IMPLICIT,"); ++ if (p->type & CONST_TAG) ++ fprintf (out, "TAG,"); ++ if (p->type & CONST_DEFAULT) ++ fprintf (out, "DEFAULT,"); ++ if (p->type & CONST_TRUE) ++ fprintf (out, "TRUE,"); ++ if (p->type & CONST_FALSE) ++ fprintf (out, "FALSE,"); ++ if (p->type & CONST_LIST) ++ fprintf (out, "LIST,"); ++ if (p->type & CONST_MIN_MAX) ++ fprintf (out, "MIN_MAX,"); ++ if (p->type & CONST_OPTION) ++ fprintf (out, "OPTION,"); ++ if (p->type & CONST_1_PARAM) ++ fprintf (out, "1_PARAM,"); ++ if (p->type & CONST_SIZE) ++ fprintf (out, "SIZE,"); ++ if (p->type & CONST_DEFINED_BY) ++ fprintf (out, "DEF_BY,"); ++ if (p->type & CONST_GENERALIZED) ++ fprintf (out, "GENERALIZED,"); ++ if (p->type & CONST_UTC) ++ fprintf (out, "UTC,"); ++ if (p->type & CONST_SET) ++ fprintf (out, "SET,"); ++ if (p->type & CONST_NOT_USED) ++ fprintf (out, "NOT_USED,"); ++ if (p->type & CONST_ASSIGN) ++ fprintf (out, "ASSIGNMENT,"); ++ } ++ } ++ ++ if (mode == ASN1_PRINT_ALL) ++ { ++ fprintf (out, "\n"); ++ } ++ else ++ { ++ switch (type_field (p->type)) ++ { ++ case ASN1_ETYPE_CONSTANT: ++ case ASN1_ETYPE_TAG: ++ case ASN1_ETYPE_SIZE: ++ break; ++ default: ++ fprintf (out, "\n"); ++ } ++ } ++ ++ if (p->down) ++ { ++ p = p->down; ++ indent += 2; ++ } ++ else if (p == root) ++ { ++ p = NULL; ++ break; ++ } ++ else if (p->right) ++ p = p->right; ++ else ++ { ++ while (1) ++ { ++ p = _asn1_find_up (p); ++ if (p == root) ++ { ++ p = NULL; ++ break; ++ } ++ indent -= 2; ++ if (p->right) ++ { ++ p = p->right; ++ break; ++ } ++ } ++ } ++ } ++} ++ ++ ++ ++/** ++ * asn1_number_of_elements: ++ * @element: pointer to the root of an ASN1 structure. ++ * @name: the name of a sub-structure of ROOT. ++ * @num: pointer to an integer where the result will be stored ++ * ++ * Counts the number of elements of a sub-structure called NAME with ++ * names equal to "?1","?2", ... ++ * ++ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if ++ * @name is not known, %ASN1_GENERIC_ERROR if pointer @num is %NULL. ++ **/ ++int ++asn1_number_of_elements (asn1_node_const element, const char *name, int *num) ++{ ++ asn1_node_const node, p; ++ ++ if (num == NULL) ++ return ASN1_GENERIC_ERROR; ++ ++ *num = 0; ++ ++ node = asn1_find_node (element, name); ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = node->down; ++ ++ while (p) ++ { ++ if (p->name[0] == '?') ++ (*num)++; ++ p = p->right; ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++/** ++ * asn1_find_structure_from_oid: ++ * @definitions: ASN1 definitions ++ * @oidValue: value of the OID to search (e.g. "1.2.3.4"). ++ * ++ * Search the structure that is defined just after an OID definition. ++ * ++ * Returns: %NULL when @oidValue not found, otherwise the pointer to a ++ * constant string that contains the element name defined just after ++ * the OID. ++ **/ ++const char * ++asn1_find_structure_from_oid (asn1_node_const definitions, ++ const char *oidValue) ++{ ++ char name[2 * ASN1_MAX_NAME_SIZE + 2]; ++ char value[ASN1_MAX_NAME_SIZE]; ++ asn1_node p; ++ int len; ++ int result; ++ const char *definitionsName; ++ ++ if ((definitions == NULL) || (oidValue == NULL)) ++ return NULL; /* ASN1_ELEMENT_NOT_FOUND; */ ++ ++ definitionsName = definitions->name; ++ ++ /* search the OBJECT_ID into definitions */ ++ p = definitions->down; ++ while (p) ++ { ++ if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) && ++ (p->type & CONST_ASSIGN)) ++ { ++ snprintf (name, sizeof (name), "%s.%s", definitionsName, p->name); ++ ++ len = ASN1_MAX_NAME_SIZE; ++ result = asn1_read_value (definitions, name, value, &len); ++ ++ if ((result == ASN1_SUCCESS) && (!strcmp (oidValue, value))) ++ { ++ p = p->right; ++ if (p == NULL) /* reach the end of ASN1 definitions */ ++ return NULL; /* ASN1_ELEMENT_NOT_FOUND; */ ++ ++ return p->name; ++ } ++ } ++ p = p->right; ++ } ++ ++ return NULL; /* ASN1_ELEMENT_NOT_FOUND; */ ++} ++ ++/** ++ * asn1_copy_node: ++ * @dst: Destination asn1 node. ++ * @dst_name: Field name in destination node. ++ * @src: Source asn1 node. ++ * @src_name: Field name in source node. ++ * ++ * Create a deep copy of a asn1_node variable. That ++ * function requires @dst to be expanded using asn1_create_element(). ++ * ++ * Returns: Return %ASN1_SUCCESS on success. ++ **/ ++int ++asn1_copy_node (asn1_node dst, const char *dst_name, ++ asn1_node_const src, const char *src_name) ++{ ++ int result; ++ asn1_node dst_node; ++ void *data = NULL; ++ int size = 0; ++ ++ result = asn1_der_coding (src, src_name, NULL, &size, NULL); ++ if (result != ASN1_MEM_ERROR) ++ return result; ++ ++ data = malloc (size); ++ if (data == NULL) ++ return ASN1_MEM_ERROR; ++ ++ result = asn1_der_coding (src, src_name, data, &size, NULL); ++ if (result != ASN1_SUCCESS) ++ { ++ free (data); ++ return result; ++ } ++ ++ dst_node = asn1_find_node (dst, dst_name); ++ if (dst_node == NULL) ++ { ++ free (data); ++ return ASN1_ELEMENT_NOT_FOUND; ++ } ++ ++ result = asn1_der_decoding (&dst_node, data, size, NULL); ++ ++ free (data); ++ ++ return result; ++} ++ ++/** ++ * asn1_dup_node: ++ * @src: Source asn1 node. ++ * @src_name: Field name in source node. ++ * ++ * Create a deep copy of a asn1_node variable. This function ++ * will return an exact copy of the provided structure. ++ * ++ * Returns: Return %NULL on failure. ++ **/ ++asn1_node ++asn1_dup_node (asn1_node_const src, const char *src_name) ++{ ++ return _asn1_copy_structure2 (src, src_name); ++} +diff --git a/grub-core/lib/libtasn1/lib/structure.h b/grub-core/lib/libtasn1/lib/structure.h +new file mode 100644 +index 000000000..da70ae53f +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/structure.h +@@ -0,0 +1,46 @@ ++/* ++ * Copyright (C) 2002-2021 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 library is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++/*************************************************/ ++/* File: structure.h */ ++/* Description: list of exported object by */ ++/* "structure.c" */ ++/*************************************************/ ++ ++#ifndef _STRUCTURE_H ++# define _STRUCTURE_H ++ ++# include "parser_aux.h" // list_type ++ ++int _asn1_create_static_structure (asn1_node_const pointer, ++ char *output_file_name, char *vector_name); ++ ++asn1_node _asn1_copy_structure3 (asn1_node_const source_node); ++ ++asn1_node _asn1_add_single_node (unsigned int type); ++ ++asn1_node _asn1_find_left (asn1_node_const node); ++ ++int ++_asn1_delete_structure (list_type * e_list, asn1_node * structure, ++ unsigned int flags); ++ ++#endif +diff --git a/include/grub/libtasn1.h b/include/grub/libtasn1.h +new file mode 100644 +index 000000000..fc695a28a +--- /dev/null ++++ b/include/grub/libtasn1.h +@@ -0,0 +1,639 @@ ++/* ++ * Copyright (C) 2002-2021 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * LIBTASN1 is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU Lesser General Public License as ++ * published by the Free Software Foundation; either version 2.1 of ++ * the License, or (at your option) any later version. ++ * ++ * LIBTASN1 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with LIBTASN1; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ * ++ */ ++ ++/** ++ * SECTION:libtasn1 ++ * @short_description: GNU ASN.1 library ++ * ++ * The Libtasn1 library provides Abstract Syntax Notation One (ASN.1, as ++ * specified by the X.680 ITU-T recommendation) parsing and structures ++ * management, and Distinguished Encoding Rules (DER, as per X.690) ++ * encoding and decoding functions. ++ */ ++ ++ ++#ifndef LIBTASN1_H ++# define LIBTASN1_H ++ ++# ifndef ASN1_API ++# if defined ASN1_BUILDING && defined HAVE_VISIBILITY && HAVE_VISIBILITY ++# define ASN1_API __attribute__((__visibility__("default"))) ++# elif defined ASN1_BUILDING && defined _MSC_VER && ! defined ASN1_STATIC ++# define ASN1_API __declspec(dllexport) ++# elif defined _MSC_VER && ! defined ASN1_STATIC ++# define ASN1_API __declspec(dllimport) ++# else ++# define ASN1_API ++# endif ++# endif ++ ++# ifdef __GNUC__ ++# define __LIBTASN1_CONST__ __attribute__((const)) ++# define __LIBTASN1_PURE__ __attribute__((pure)) ++# else ++# define __LIBTASN1_CONST__ ++# define __LIBTASN1_PURE__ ++# endif ++ ++# include ++# include ++# include /* for FILE* */ ++ ++# ifdef __cplusplus ++extern "C" ++{ ++# endif ++ ++/** ++ * ASN1_VERSION: ++ * ++ * Version of the library as a string. ++ */ ++# define ASN1_VERSION "4.18.0" ++ ++/** ++ * ASN1_VERSION_MAJOR: ++ * ++ * Major version number of the library. ++ */ ++# define ASN1_VERSION_MAJOR 4 ++ ++/** ++ * ASN1_VERSION_MINOR: ++ * ++ * Minor version number of the library. ++ */ ++# define ASN1_VERSION_MINOR 18 ++ ++/** ++ * ASN1_VERSION_PATCH: ++ * ++ * Patch version number of the library. ++ */ ++# define ASN1_VERSION_PATCH 0 ++ ++/** ++ * ASN1_VERSION_NUMBER: ++ * ++ * Version number of the library as a number. ++ */ ++# define ASN1_VERSION_NUMBER 0x041200 ++ ++ ++# if defined __GNUC__ && !defined ASN1_INTERNAL_BUILD ++# define _ASN1_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) ++# if _ASN1_GCC_VERSION >= 30100 ++# define _ASN1_GCC_ATTR_DEPRECATED __attribute__ ((__deprecated__)) ++# endif ++# endif ++ ++# ifndef _ASN1_GCC_ATTR_DEPRECATED ++# define _ASN1_GCC_ATTR_DEPRECATED ++# endif ++ ++/*****************************************/ ++/* Errors returned by libtasn1 functions */ ++/*****************************************/ ++# define ASN1_SUCCESS 0 ++# define ASN1_FILE_NOT_FOUND 1 ++# define ASN1_ELEMENT_NOT_FOUND 2 ++# define ASN1_IDENTIFIER_NOT_FOUND 3 ++# define ASN1_DER_ERROR 4 ++# define ASN1_VALUE_NOT_FOUND 5 ++# define ASN1_GENERIC_ERROR 6 ++# define ASN1_VALUE_NOT_VALID 7 ++# define ASN1_TAG_ERROR 8 ++# define ASN1_TAG_IMPLICIT 9 ++# define ASN1_ERROR_TYPE_ANY 10 ++# define ASN1_SYNTAX_ERROR 11 ++# define ASN1_MEM_ERROR 12 ++# define ASN1_MEM_ALLOC_ERROR 13 ++# define ASN1_DER_OVERFLOW 14 ++# define ASN1_NAME_TOO_LONG 15 ++# define ASN1_ARRAY_ERROR 16 ++# define ASN1_ELEMENT_NOT_EMPTY 17 ++# define ASN1_TIME_ENCODING_ERROR 18 ++# define ASN1_RECURSION 19 ++ ++/*************************************/ ++/* Constants used in asn1_visit_tree */ ++/*************************************/ ++# define ASN1_PRINT_NAME 1 ++# define ASN1_PRINT_NAME_TYPE 2 ++# define ASN1_PRINT_NAME_TYPE_VALUE 3 ++# define ASN1_PRINT_ALL 4 ++ ++/*****************************************/ ++/* Constants returned by asn1_read_tag */ ++/*****************************************/ ++# define ASN1_CLASS_UNIVERSAL 0x00 /* old: 1 */ ++# define ASN1_CLASS_APPLICATION 0x40 /* old: 2 */ ++# define ASN1_CLASS_CONTEXT_SPECIFIC 0x80 /* old: 3 */ ++# define ASN1_CLASS_PRIVATE 0xC0 /* old: 4 */ ++# define ASN1_CLASS_STRUCTURED 0x20 ++ ++/*****************************************/ ++/* Constants returned by asn1_read_tag */ ++/*****************************************/ ++# define ASN1_TAG_BOOLEAN 0x01 ++# define ASN1_TAG_INTEGER 0x02 ++# define ASN1_TAG_SEQUENCE 0x10 ++# define ASN1_TAG_SET 0x11 ++# define ASN1_TAG_OCTET_STRING 0x04 ++# define ASN1_TAG_BIT_STRING 0x03 ++# define ASN1_TAG_UTCTime 0x17 ++# define ASN1_TAG_GENERALIZEDTime 0x18 ++# define ASN1_TAG_OBJECT_ID 0x06 ++# define ASN1_TAG_ENUMERATED 0x0A ++# define ASN1_TAG_NULL 0x05 ++# define ASN1_TAG_GENERALSTRING 0x1B ++# define ASN1_TAG_NUMERIC_STRING 0x12 ++# define ASN1_TAG_IA5_STRING 0x16 ++# define ASN1_TAG_TELETEX_STRING 0x14 ++# define ASN1_TAG_PRINTABLE_STRING 0x13 ++# define ASN1_TAG_UNIVERSAL_STRING 0x1C ++# define ASN1_TAG_BMP_STRING 0x1E ++# define ASN1_TAG_UTF8_STRING 0x0C ++# define ASN1_TAG_VISIBLE_STRING 0x1A ++ ++/** ++ * asn1_node: ++ * ++ * Structure definition used for the node of the tree ++ * that represents an ASN.1 DEFINITION. ++ */ ++ typedef struct asn1_node_st asn1_node_st; ++ ++ typedef asn1_node_st *asn1_node; ++ typedef const asn1_node_st *asn1_node_const; ++ ++/** ++ * ASN1_MAX_NAME_SIZE: ++ * ++ * Maximum number of characters of a name ++ * inside a file with ASN1 definitions. ++ */ ++# define ASN1_MAX_NAME_SIZE 64 ++ ++ ++/** ++ * asn1_static_node: ++ * @name: Node name ++ * @type: Node typ ++ * @value: Node value ++ * ++ * For the on-disk format of ASN.1 trees, created by asn1_parser2array(). ++ */ ++ typedef struct asn1_static_node_st ++ { ++ const char *name; /* Node name */ ++ unsigned int type; /* Node type */ ++ const void *value; /* Node value */ ++ } asn1_static_node; ++ ++/* List of constants for field type of asn1_static_node */ ++# define ASN1_ETYPE_INVALID 0 ++# define ASN1_ETYPE_CONSTANT 1 ++# define ASN1_ETYPE_IDENTIFIER 2 ++# define ASN1_ETYPE_INTEGER 3 ++# define ASN1_ETYPE_BOOLEAN 4 ++# define ASN1_ETYPE_SEQUENCE 5 ++# define ASN1_ETYPE_BIT_STRING 6 ++# define ASN1_ETYPE_OCTET_STRING 7 ++# define ASN1_ETYPE_TAG 8 ++# define ASN1_ETYPE_DEFAULT 9 ++# define ASN1_ETYPE_SIZE 10 ++# define ASN1_ETYPE_SEQUENCE_OF 11 ++# define ASN1_ETYPE_OBJECT_ID 12 ++# define ASN1_ETYPE_ANY 13 ++# define ASN1_ETYPE_SET 14 ++# define ASN1_ETYPE_SET_OF 15 ++# define ASN1_ETYPE_DEFINITIONS 16 ++# define ASN1_ETYPE_CHOICE 18 ++# define ASN1_ETYPE_IMPORTS 19 ++# define ASN1_ETYPE_NULL 20 ++# define ASN1_ETYPE_ENUMERATED 21 ++# define ASN1_ETYPE_GENERALSTRING 27 ++# define ASN1_ETYPE_NUMERIC_STRING 28 ++# define ASN1_ETYPE_IA5_STRING 29 ++# define ASN1_ETYPE_TELETEX_STRING 30 ++# define ASN1_ETYPE_PRINTABLE_STRING 31 ++# define ASN1_ETYPE_UNIVERSAL_STRING 32 ++# define ASN1_ETYPE_BMP_STRING 33 ++# define ASN1_ETYPE_UTF8_STRING 34 ++# define ASN1_ETYPE_VISIBLE_STRING 35 ++# define ASN1_ETYPE_UTC_TIME 36 ++# define ASN1_ETYPE_GENERALIZED_TIME 37 ++ ++/** ++ * ASN1_DELETE_FLAG_ZEROIZE: ++ * ++ * Used by: asn1_delete_structure2() ++ * ++ * Zeroize values prior to deinitialization. ++ */ ++# define ASN1_DELETE_FLAG_ZEROIZE 1 ++ ++/** ++ * ASN1_DECODE_FLAG_ALLOW_PADDING: ++ * ++ * Used by: asn1_der_decoding2() ++ * ++ * This flag would allow arbitrary data past the DER data. ++ */ ++# define ASN1_DECODE_FLAG_ALLOW_PADDING 1 ++/** ++ * ASN1_DECODE_FLAG_STRICT_DER: ++ * ++ * Used by: asn1_der_decoding2() ++ * ++ * This flag would ensure that no BER decoding takes place. ++ */ ++# define ASN1_DECODE_FLAG_STRICT_DER (1<<1) ++/** ++ * ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME: ++ * ++ * Used by: asn1_der_decoding2() ++ * ++ * This flag will tolerate Time encoding errors when in strict DER. ++ */ ++# define ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME (1<<2) ++ ++ ++/** ++ * asn1_data_node_st: ++ * @name: Node name ++ * @value: Node value ++ * @value_len: Node value size ++ * @type: Node value type (ASN1_ETYPE_*) ++ * ++ * Data node inside a #asn1_node structure. ++ */ ++ struct asn1_data_node_st ++ { ++ const char *name; /* Node name */ ++ const void *value; /* Node value */ ++ unsigned int value_len; /* Node value size */ ++ unsigned int type; /* Node value type (ASN1_ETYPE_*) */ ++ }; ++ typedef struct asn1_data_node_st asn1_data_node_st; ++ ++/***********************************/ ++/* Fixed constants */ ++/***********************************/ ++ ++/** ++ * ASN1_MAX_ERROR_DESCRIPTION_SIZE: ++ * ++ * Maximum number of characters ++ * of a description message ++ * (null character included). ++ */ ++# define ASN1_MAX_ERROR_DESCRIPTION_SIZE 128 ++ ++/***********************************/ ++/* Functions definitions */ ++/***********************************/ ++ ++ extern ASN1_API int ++ asn1_parser2tree (const char *file, ++ asn1_node * definitions, char *error_desc); ++ ++ extern ASN1_API int ++ asn1_parser2array (const char *inputFileName, ++ const char *outputFileName, ++ const char *vectorName, char *error_desc); ++ ++ extern ASN1_API int ++ asn1_array2tree (const asn1_static_node * array, ++ asn1_node * definitions, char *errorDescription); ++ ++ extern ASN1_API void ++ asn1_print_structure (FILE * out, asn1_node_const structure, ++ const char *name, int mode); ++ ++ extern ASN1_API int ++ asn1_create_element (asn1_node_const definitions, ++ const char *source_name, asn1_node * element); ++ ++ extern ASN1_API int asn1_delete_structure (asn1_node * structure); ++ ++ extern ASN1_API int asn1_delete_structure2 (asn1_node * structure, ++ unsigned int flags); ++ ++ extern ASN1_API int ++ asn1_delete_element (asn1_node structure, const char *element_name); ++ ++ extern ASN1_API int ++ asn1_write_value (asn1_node node_root, const char *name, ++ const void *ivalue, int len); ++ ++ extern ASN1_API int ++ asn1_read_value (asn1_node_const root, const char *name, ++ void *ivalue, int *len); ++ ++ extern ASN1_API int ++ asn1_read_value_type (asn1_node_const root, const char *name, ++ void *ivalue, int *len, unsigned int *etype); ++ ++ extern ASN1_API int ++ asn1_read_node_value (asn1_node_const node, asn1_data_node_st * data); ++ ++ extern ASN1_API int ++ asn1_number_of_elements (asn1_node_const element, const char *name, ++ int *num); ++ ++ extern ASN1_API int ++ asn1_der_coding (asn1_node_const element, const char *name, ++ void *ider, int *len, char *ErrorDescription); ++ ++ extern ASN1_API int ++ asn1_der_decoding2 (asn1_node * element, const void *ider, ++ int *max_ider_len, unsigned int flags, ++ char *errorDescription); ++ ++ extern ASN1_API int ++ asn1_der_decoding (asn1_node * element, const void *ider, ++ int ider_len, char *errorDescription); ++ ++/* Do not use. Use asn1_der_decoding() instead. */ ++ extern ASN1_API int ++ asn1_der_decoding_element (asn1_node * structure, ++ const char *elementName, ++ const void *ider, int len, ++ char *errorDescription) ++ _ASN1_GCC_ATTR_DEPRECATED; ++ ++ extern ASN1_API int ++ asn1_der_decoding_startEnd (asn1_node element, ++ const void *ider, int ider_len, ++ const char *name_element, ++ int *start, int *end); ++ ++ extern ASN1_API int ++ asn1_expand_any_defined_by (asn1_node_const definitions, ++ asn1_node * element); ++ ++ extern ASN1_API int ++ asn1_expand_octet_string (asn1_node_const definitions, ++ asn1_node * element, ++ const char *octetName, const char *objectName); ++ ++ extern ASN1_API int ++ asn1_read_tag (asn1_node_const root, const char *name, ++ int *tagValue, int *classValue); ++ ++ extern ASN1_API const char *asn1_find_structure_from_oid (asn1_node_const ++ definitions, ++ const char ++ *oidValue); ++ ++ __LIBTASN1_PURE__ ++ extern ASN1_API const char *asn1_check_version (const char *req_version); ++ ++ __LIBTASN1_PURE__ extern ASN1_API const char *asn1_strerror (int error); ++ ++ extern ASN1_API void asn1_perror (int error); ++ ++# define ASN1_MAX_TAG_SIZE 4 ++# define ASN1_MAX_LENGTH_SIZE 9 ++# define ASN1_MAX_TL_SIZE (ASN1_MAX_TAG_SIZE+ASN1_MAX_LENGTH_SIZE) ++ extern ASN1_API long ++ asn1_get_length_der (const unsigned char *der, int der_len, int *len); ++ ++ extern ASN1_API long ++ asn1_get_length_ber (const unsigned char *ber, int ber_len, int *len); ++ ++ extern ASN1_API void ++ asn1_length_der (unsigned long int len, unsigned char *der, int *der_len); ++ ++/* Other utility functions. */ ++ ++ extern ASN1_API ++ int asn1_decode_simple_der (unsigned int etype, const unsigned char *der, ++ unsigned int _der_len, ++ const unsigned char **str, ++ unsigned int *str_len); ++ ++ extern ASN1_API ++ int asn1_decode_simple_ber (unsigned int etype, const unsigned char *der, ++ unsigned int _der_len, ++ unsigned char **str, ++ unsigned int *str_len, unsigned int *ber_len); ++ ++ extern ASN1_API int ++ asn1_encode_simple_der (unsigned int etype, const unsigned char *str, ++ unsigned int str_len, unsigned char *tl, ++ unsigned int *tl_len); ++ ++ extern ASN1_API asn1_node ++ asn1_find_node (asn1_node_const pointer, const char *name); ++ ++ extern ASN1_API int ++ asn1_copy_node (asn1_node dst, const char *dst_name, ++ asn1_node_const src, const char *src_name); ++ extern ASN1_API asn1_node ++ asn1_dup_node (asn1_node_const src, const char *src_name); ++ ++/* Internal and low-level DER utility functions. */ ++ ++ extern ASN1_API int ++ asn1_get_tag_der (const unsigned char *der, int der_len, ++ unsigned char *cls, int *len, unsigned long *tag); ++ ++ extern ASN1_API void ++ asn1_octet_der (const unsigned char *str, int str_len, ++ unsigned char *der, int *der_len); ++ ++ extern ASN1_API int ++ asn1_get_octet_der (const unsigned char *der, int der_len, ++ int *ret_len, unsigned char *str, ++ int str_size, int *str_len); ++ ++ extern ASN1_API void asn1_bit_der (const unsigned char *str, int bit_len, ++ unsigned char *der, int *der_len); ++ ++ extern ASN1_API int ++ asn1_get_bit_der (const unsigned char *der, int der_len, ++ int *ret_len, unsigned char *str, ++ int str_size, int *bit_len); ++ ++ extern ASN1_API int ++ asn1_get_object_id_der (const unsigned char *der, ++ int der_len, int *ret_len, ++ char *str, int str_size); ++ ++ extern ASN1_API int ++ asn1_object_id_der (const char *str, unsigned char *der, int *der_len, ++ unsigned flags); ++ ++/* Compatibility types */ ++ ++/** ++ * asn1_retCode: ++ * ++ * Type formerly returned by libtasn1 functions. ++ * ++ * Deprecated: 3.0: Use int instead. ++ */ ++ typedef int asn1_retCode _ASN1_GCC_ATTR_DEPRECATED; ++ ++/** ++ * node_asn_struct: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_node instead. ++ */ ++# ifndef ASN1_DISABLE_DEPRECATED ++# if _ASN1_GCC_VERSION >= 30100 ++# define node_asn_struct _Pragma ("GCC warning \"'node_asn_struct' macro is deprecated, use 'asn1_node' instead.\"") asn1_node_st ++# else ++# define node_asn_struct asn1_node_st ++# endif ++# endif /* !ASN1_DISABLE_DEPRECATED */ ++ ++/** ++ * node_asn: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_node instead. ++ */ ++# ifndef ASN1_DISABLE_DEPRECATED ++# if _ASN1_GCC_VERSION >= 30100 ++# define node_asn _Pragma ("GCC warning \"'node_asn' macro is deprecated, use 'asn1_node' instead.\"") asn1_node_st ++# else ++# define node_asn asn1_node_st ++# endif ++# endif /* !ASN1_DISABLE_DEPRECATED */ ++ ++/** ++ * ASN1_TYPE: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_node instead. ++ */ ++# ifndef ASN1_DISABLE_DEPRECATED ++# if _ASN1_GCC_VERSION >= 30100 ++# define ASN1_TYPE _Pragma ("GCC warning \"'ASN1_TYPE' macro is deprecated, use 'asn1_node' instead.\"") asn1_node ++# else ++# define ASN1_TYPE asn1_node ++# endif ++# endif /* !ASN1_DISABLE_DEPRECATED */ ++ ++/** ++ * ASN1_TYPE_EMPTY: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use NULL instead. ++ */ ++# ifndef ASN1_DISABLE_DEPRECATED ++# if _ASN1_GCC_VERSION >= 30100 ++# define ASN1_TYPE_EMPTY _Pragma ("GCC warning \"'ASN1_TYPE_EMPTY' macro is deprecated, use 'NULL' instead.\"") NULL ++# else ++# define ASN1_TYPE_EMPTY NULL ++# endif ++# endif /* !ASN1_DISABLE_DEPRECATED */ ++ ++/** ++ * static_struct_asn: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_static_node instead. ++ */ ++# ifndef ASN1_DISABLE_DEPRECATED ++# if _ASN1_GCC_VERSION >= 30100 ++# define static_struct_asn _Pragma ("GCC warning \"'static_struct_asn' macro is deprecated, use 'asn1_static_node_st' instead.\"") asn1_static_node_st ++# else ++# define static_struct_asn asn1_static_node_st ++# endif ++# endif /* !ASN1_DISABLE_DEPRECATED */ ++ ++/** ++ * ASN1_ARRAY_TYPE: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_static_node instead. ++ */ ++# ifndef ASN1_DISABLE_DEPRECATED ++# if _ASN1_GCC_VERSION >= 30100 ++# define ASN1_ARRAY_TYPE _Pragma ("GCC warning \"'ASN1_ARRAY_TYPE' macro is deprecated, use 'asn1_static_node' instead.\"") asn1_static_node ++# else ++# define ASN1_ARRAY_TYPE asn1_static_node ++# endif ++# endif /* !ASN1_DISABLE_DEPRECATED */ ++ ++/** ++ * asn1_static_node_t: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_static_node instead. ++ */ ++# ifndef ASN1_DISABLE_DEPRECATED ++# if _ASN1_GCC_VERSION >= 30100 ++# define asn1_static_node_t _Pragma ("GCC warning \"'asn1_static_node_t' macro is deprecated, use 'asn1_static_node' instead.\"") asn1_static_node ++# else ++# define asn1_static_node_t asn1_static_node ++# endif ++# endif /* !ASN1_DISABLE_DEPRECATED */ ++ ++/** ++ * node_data_struct: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_data_node_st instead. ++ */ ++# ifndef ASN1_DISABLE_DEPRECATED ++# if _ASN1_GCC_VERSION >= 30100 ++# define node_data_struct _Pragma ("GCC warning \"'node_data_struct' macro is deprecated, use 'asn1_data_node_st' instead.\"") asn1_data_node_st ++# else ++# define node_data_struct asn1_data_node_st ++# endif ++# endif /* !ASN1_DISABLE_DEPRECATED */ ++ ++/** ++ * ASN1_DATA_NODE: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_data_node_st instead. ++ */ ++# ifndef ASN1_DISABLE_DEPRECATED ++# if _ASN1_GCC_VERSION >= 30100 ++# define ASN1_DATA_NODE _Pragma ("GCC warning \"'asn1_static_node_t' macro is deprecated, use 'asn1_static_node' instead.\"") asn1_data_node_st ++# else ++# define ASN1_DATA_NODE asn1_data_node_st ++# endif ++# endif /* !ASN1_DISABLE_DEPRECATED */ ++ ++# ifdef __cplusplus ++} ++# endif ++ ++#endif /* LIBTASN1_H */ +-- +2.31.1 + diff --git a/0011-tpm2-Add-TPM-Software-Stack-TSS.patch b/0011-tpm2-Add-TPM-Software-Stack-TSS.patch new file mode 100644 index 0000000..c8bd8ed --- /dev/null +++ b/0011-tpm2-Add-TPM-Software-Stack-TSS.patch @@ -0,0 +1,3523 @@ +From 65f937752d51b81fb830d4c6177975d395be9346 Mon Sep 17 00:00:00 2001 +From: Hernan Gatta +Date: Tue, 1 Feb 2022 05:02:54 -0800 +Subject: [PATCH 11/14] tpm2: Add TPM Software Stack (TSS) + +A Trusted Platform Module (TPM) Software Stack (TSS) provides logic to compose, +submit, and parse TPM commands and responses. + +A limited number of TPM commands may be accessed via the EFI TCG2 protocol. This +protocol exposes functionality that is primarily geared toward TPM usage within +the context of Secure Boot. For all other TPM commands, however, such as sealing +and unsealing, this protocol does not provide any help, with the exception of +passthrough command submission. + +The SubmitCommand method allows a caller to send raw commands to the system's +TPM and to receive the corresponding response. These command/response pairs are +formatted using the TPM wire protocol. To construct commands in this way, and to +parse the TPM's response, it is necessary to, first, possess knowledge of the +various TPM structures, and, two, of the TPM wire protocol itself. + +As such, this patch includes a set of header files that define the necessary TPM +structures and TSS functions, implementations of various TPM2_* functions +(inventoried below), and logic to write and read command and response buffers, +respectively, using the TPM wire protocol. + +Functions: TPM2_Create, TPM2_CreatePrimary, TPM2_EvictControl, +TPM2_FlushContext, TPM2_Load, TPM2_PCR_Read, TPM2_PolicyGetDigest, +TPM2_PolicyPCR, TPM2_ReadPublic, TPM2_StartAuthSession, TPM2_Unseal. + +Signed-off-by: Hernan Gatta +--- + grub-core/tpm2/buffer.c | 145 +++++ + grub-core/tpm2/mu.c | 807 +++++++++++++++++++++++++ + grub-core/tpm2/tcg2.c | 143 +++++ + grub-core/tpm2/tpm2.c | 711 ++++++++++++++++++++++ + include/grub/tpm2/buffer.h | 65 ++ + include/grub/tpm2/internal/functions.h | 117 ++++ + include/grub/tpm2/internal/structs.h | 675 +++++++++++++++++++++ + include/grub/tpm2/internal/types.h | 372 ++++++++++++ + include/grub/tpm2/mu.h | 292 +++++++++ + include/grub/tpm2/tcg2.h | 34 ++ + include/grub/tpm2/tpm2.h | 38 ++ + 11 files changed, 3399 insertions(+) + create mode 100644 grub-core/tpm2/buffer.c + create mode 100644 grub-core/tpm2/mu.c + create mode 100644 grub-core/tpm2/tcg2.c + create mode 100644 grub-core/tpm2/tpm2.c + create mode 100644 include/grub/tpm2/buffer.h + create mode 100644 include/grub/tpm2/internal/functions.h + create mode 100644 include/grub/tpm2/internal/structs.h + create mode 100644 include/grub/tpm2/internal/types.h + create mode 100644 include/grub/tpm2/mu.h + create mode 100644 include/grub/tpm2/tcg2.h + create mode 100644 include/grub/tpm2/tpm2.h + +diff --git a/grub-core/tpm2/buffer.c b/grub-core/tpm2/buffer.c +new file mode 100644 +index 0000000000..fee42d5a9e +--- /dev/null ++++ b/grub-core/tpm2/buffer.c +@@ -0,0 +1,145 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * 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 . ++ */ ++ ++#include ++#include ++ ++void grub_tpm2_buffer_init (grub_tpm2_buffer_t buffer) ++{ ++ grub_memset (buffer->data, 0xDD, sizeof (buffer->data)); ++ buffer->size = 0; ++ buffer->offset = 0; ++ buffer->cap = sizeof (buffer->data); ++ buffer->error = 0; ++} ++ ++void ++grub_tpm2_buffer_pack (grub_tpm2_buffer_t buffer, const void* data, ++ grub_size_t size) ++{ ++ grub_uint32_t r = buffer->cap - buffer->size; ++ ++ if (buffer->error) ++ return; ++ ++ if (size > r) ++ { ++ buffer->error = 1; ++ return; ++ } ++ ++ grub_memcpy (&buffer->data[buffer->size], (void*) data, size); ++ buffer->size += size; ++} ++ ++void ++grub_tpm2_buffer_pack_u8 (grub_tpm2_buffer_t buffer, grub_uint8_t value) ++{ ++ grub_tpm2_buffer_pack (buffer, (const char*) &value, sizeof (value)); ++} ++ ++void ++grub_tpm2_buffer_pack_u16 (grub_tpm2_buffer_t buffer, grub_uint16_t value) ++{ ++ grub_uint16_t tmp = grub_swap_bytes16 (value); ++ grub_tpm2_buffer_pack (buffer, (const char*) &tmp, sizeof (tmp)); ++} ++ ++void ++grub_tpm2_buffer_pack_u32 (grub_tpm2_buffer_t buffer, grub_uint32_t value) ++{ ++ grub_uint32_t tmp = grub_swap_bytes32 (value); ++ grub_tpm2_buffer_pack (buffer, (const char*) &tmp, sizeof (tmp)); ++} ++ ++void ++grub_tpm2_buffer_unpack (grub_tpm2_buffer_t buffer, void* data, ++ grub_size_t size) ++{ ++ grub_uint32_t r = buffer->size - buffer->offset; ++ ++ if (buffer->error) ++ return; ++ ++ if (size > r) ++ { ++ buffer->error = 1; ++ return; ++ } ++ ++ grub_memcpy (data, &buffer->data[buffer->offset], size); ++ buffer->offset += size; ++} ++ ++void ++grub_tpm2_buffer_unpack_u8 (grub_tpm2_buffer_t buffer, grub_uint8_t* value) ++{ ++ grub_uint32_t r = buffer->size - buffer->offset; ++ ++ if (buffer->error) ++ return; ++ ++ if (sizeof (*value) > r) ++ { ++ buffer->error = 1; ++ return; ++ } ++ ++ grub_memcpy (value, &buffer->data[buffer->offset], sizeof (*value)); ++ buffer->offset += sizeof (*value); ++} ++ ++void ++grub_tpm2_buffer_unpack_u16 (grub_tpm2_buffer_t buffer, grub_uint16_t* value) ++{ ++ grub_uint16_t tmp; ++ grub_uint32_t r = buffer->size - buffer->offset; ++ ++ if (buffer->error) ++ return; ++ ++ if (sizeof (tmp) > r) ++ { ++ buffer->error = 1; ++ return; ++ } ++ ++ grub_memcpy (&tmp, &buffer->data[buffer->offset], sizeof (tmp)); ++ buffer->offset += sizeof (tmp); ++ *value = grub_swap_bytes16 (tmp); ++} ++ ++void ++grub_tpm2_buffer_unpack_u32 (grub_tpm2_buffer_t buffer, grub_uint32_t* value) ++{ ++ grub_uint32_t tmp; ++ grub_uint32_t r = buffer->size - buffer->offset; ++ ++ if (buffer->error) ++ return; ++ ++ if (sizeof (tmp) > r) ++ { ++ buffer->error = 1; ++ return; ++ } ++ ++ grub_memcpy (&tmp, &buffer->data[buffer->offset], sizeof (tmp)); ++ buffer->offset += sizeof (tmp); ++ *value = grub_swap_bytes32 (tmp); ++} +diff --git a/grub-core/tpm2/mu.c b/grub-core/tpm2/mu.c +new file mode 100644 +index 0000000000..c5f5c7b5f8 +--- /dev/null ++++ b/grub-core/tpm2/mu.c +@@ -0,0 +1,807 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * 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 . ++ */ ++ ++#include ++#include ++ ++void ++grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (grub_tpm2_buffer_t buffer, ++ const TPMS_AUTH_COMMAND* authCommand) ++{ ++ grub_uint32_t start; ++ grub_uint32_t tmp; ++ ++ grub_tpm2_buffer_pack_u32 (buffer, 0); ++ start = buffer->size; ++ ++ grub_tpm2_buffer_pack_u32 (buffer, authCommand->sessionHandle); ++ ++ grub_tpm2_buffer_pack_u16 (buffer, authCommand->nonce.size); ++ grub_tpm2_buffer_pack (buffer, authCommand->nonce.buffer, ++ authCommand->nonce.size); ++ ++ grub_tpm2_buffer_pack_u8 (buffer, ++ *((const grub_uint8_t*) &authCommand->sessionAttributes)); ++ ++ grub_tpm2_buffer_pack_u16 (buffer, authCommand->hmac.size); ++ grub_tpm2_buffer_pack (buffer, authCommand->hmac.buffer, ++ authCommand->hmac.size); ++ ++ tmp = grub_swap_bytes32 (buffer->size - start); ++ grub_memcpy (&buffer->data[start - sizeof (grub_uint32_t)], &tmp, ++ sizeof (tmp)); ++} ++ ++void ++grub_tpm2_mu_TPM2B_Marshal (grub_tpm2_buffer_t buffer, ++ grub_uint16_t size, ++ const grub_uint8_t* b) ++{ ++ grub_tpm2_buffer_pack_u16 (buffer, size); ++ ++ for (grub_uint16_t i = 0; i < size; i++) ++ grub_tpm2_buffer_pack_u8 (buffer, b[i]); ++} ++ ++void ++grub_tpm2_mu_TPMU_SYM_KEY_BITS_Marshal (grub_tpm2_buffer_t buffer, ++ TPMI_ALG_SYM_OBJECT algorithm, ++ TPMU_SYM_KEY_BITS *p) ++{ ++ switch (algorithm) ++ { ++ case TPM_ALG_AES: ++ case TPM_ALG_SM4: ++ case TPM_ALG_CAMELLIA: ++ case TPM_ALG_XOR: ++ grub_tpm2_buffer_pack_u16 (buffer, *((const grub_uint16_t*) p)); ++ break; ++ case TPM_ALG_NULL: ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMU_SYM_MODE_Marshal (grub_tpm2_buffer_t buffer, ++ TPMI_ALG_SYM_OBJECT algorithm, ++ TPMU_SYM_MODE *p) ++{ ++ switch (algorithm) ++ { ++ case TPM_ALG_AES: ++ case TPM_ALG_SM4: ++ case TPM_ALG_CAMELLIA: ++ grub_tpm2_buffer_pack_u16 (buffer, *((const grub_uint16_t*) p)); ++ break; ++ case TPM_ALG_XOR: ++ case TPM_ALG_NULL: ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMT_SYM_DEF_Marshal (grub_tpm2_buffer_t buffer, ++ TPMT_SYM_DEF *p) ++{ ++ grub_tpm2_buffer_pack_u16 (buffer, p->algorithm); ++ grub_tpm2_mu_TPMU_SYM_KEY_BITS_Marshal (buffer, p->algorithm, &p->keyBits); ++ grub_tpm2_mu_TPMU_SYM_MODE_Marshal (buffer, p->algorithm, &p->mode); ++} ++ ++void ++grub_tpm2_mu_TPMS_PCR_SELECTION_Marshal (grub_tpm2_buffer_t buffer, ++ const TPMS_PCR_SELECTION* pcrSelection) ++{ ++ grub_tpm2_buffer_pack_u16 (buffer, pcrSelection->hash); ++ grub_tpm2_buffer_pack_u8 (buffer, pcrSelection->sizeOfSelect); ++ ++ for (grub_uint32_t i = 0; i < pcrSelection->sizeOfSelect; i++) ++ grub_tpm2_buffer_pack_u8 (buffer, pcrSelection->pcrSelect[i]); ++} ++ ++void ++grub_tpm2_mu_TPML_PCR_SELECTION_Marshal (grub_tpm2_buffer_t buffer, ++ const TPML_PCR_SELECTION* pcrSelection) ++{ ++ grub_tpm2_buffer_pack_u32 (buffer, pcrSelection->count); ++ ++ for (grub_uint32_t i = 0; i < pcrSelection->count; i++) ++ grub_tpm2_mu_TPMS_PCR_SELECTION_Marshal (buffer, ++ &pcrSelection->pcrSelections[i]); ++} ++ ++void ++grub_tpm2_mu_TPMA_OBJECT_Marshal (grub_tpm2_buffer_t buffer, ++ const TPMA_OBJECT *p) ++{ ++ grub_tpm2_buffer_pack_u32 (buffer, *((const grub_uint32_t*) p)); ++} ++ ++void ++grub_tpm2_mu_TPMS_SCHEME_XOR_Marshal (grub_tpm2_buffer_t buffer, ++ TPMS_SCHEME_XOR *p) ++{ ++ grub_tpm2_buffer_pack_u16 (buffer, p->hashAlg); ++ grub_tpm2_buffer_pack_u16 (buffer, p->kdf); ++} ++ ++void ++grub_tpm2_mu_TPMS_SCHEME_HMAC_Marshal (grub_tpm2_buffer_t buffer, ++ TPMS_SCHEME_HMAC *p) ++{ ++ grub_tpm2_buffer_pack_u16 (buffer, p->hashAlg); ++} ++ ++void ++grub_tpm2_mu_TPMU_SCHEME_KEYEDHASH_Marshal (grub_tpm2_buffer_t buffer, ++ TPMI_ALG_KEYEDHASH_SCHEME scheme, ++ TPMU_SCHEME_KEYEDHASH *p) ++{ ++ switch (scheme) ++ { ++ case TPM_ALG_HMAC: ++ grub_tpm2_mu_TPMS_SCHEME_HMAC_Marshal (buffer, &p->hmac); ++ break; ++ case TPM_ALG_XOR: ++ grub_tpm2_mu_TPMS_SCHEME_XOR_Marshal (buffer, &p->exclusiveOr); ++ break; ++ case TPM_ALG_NULL: ++ break; ++ default: ++ buffer->error = 1; ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMT_KEYEDHASH_SCHEME_Marshal (grub_tpm2_buffer_t buffer, ++ TPMT_KEYEDHASH_SCHEME *p) ++{ ++ grub_tpm2_buffer_pack_u16 (buffer, p->scheme); ++ grub_tpm2_mu_TPMU_SCHEME_KEYEDHASH_Marshal (buffer, p->scheme, &p->details); ++} ++ ++void ++grub_tpm2_mu_TPMS_KEYEDHASH_PARMS_Marshal (grub_tpm2_buffer_t buffer, ++ TPMS_KEYEDHASH_PARMS *p) ++{ ++ grub_tpm2_mu_TPMT_KEYEDHASH_SCHEME_Marshal (buffer, &p->scheme); ++} ++ ++void ++grub_tpm2_mu_TPMT_SYM_DEF_OBJECT_Marshal (grub_tpm2_buffer_t buffer, ++ TPMT_SYM_DEF_OBJECT *p) ++{ ++ grub_tpm2_buffer_pack_u16 (buffer, p->algorithm); ++ grub_tpm2_mu_TPMU_SYM_KEY_BITS_Marshal (buffer, p->algorithm, &p->keyBits); ++ grub_tpm2_mu_TPMU_SYM_MODE_Marshal (buffer, p->algorithm, &p->mode); ++} ++ ++void ++grub_tpm2_mu_TPMU_ASYM_SCHEME_Marshal (grub_tpm2_buffer_t buffer, ++ TPMI_ALG_RSA_DECRYPT scheme, ++ TPMU_ASYM_SCHEME *p __attribute__ ((unused))) ++{ ++ switch (scheme) ++ { ++ case TPM_ALG_NULL: ++ break; ++ default: ++ /* Unsupported */ ++ buffer->error = 1; ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMT_RSA_SCHEME_Marshal (grub_tpm2_buffer_t buffer, ++ TPMT_RSA_SCHEME *p) ++{ ++ grub_tpm2_buffer_pack_u16 (buffer, p->scheme); ++ grub_tpm2_mu_TPMU_ASYM_SCHEME_Marshal (buffer, p->scheme, &p->details); ++} ++ ++void ++grub_tpm2_mu_TPMS_RSA_PARMS_Marshal (grub_tpm2_buffer_t buffer, ++ TPMS_RSA_PARMS *p) ++{ ++ grub_tpm2_mu_TPMT_SYM_DEF_OBJECT_Marshal (buffer, &p->symmetric); ++ grub_tpm2_mu_TPMT_RSA_SCHEME_Marshal (buffer, &p->scheme); ++ grub_tpm2_buffer_pack_u16 (buffer, p->keyBits); ++ grub_tpm2_buffer_pack_u32 (buffer, p->exponent); ++} ++ ++void ++grub_tpm2_mu_TPMS_SYMCIPHER_PARMS_Marshal (grub_tpm2_buffer_t buffer, ++ TPMS_SYMCIPHER_PARMS *p) ++{ ++ grub_tpm2_mu_TPMT_SYM_DEF_OBJECT_Marshal (buffer, &p->sym); ++} ++ ++void ++grub_tpm2_mu_TPMT_ECC_SCHEME_Marshal (grub_tpm2_buffer_t buffer, ++ TPMT_ECC_SCHEME *p) ++{ ++ grub_tpm2_buffer_pack_u16 (buffer, p->scheme); ++ grub_tpm2_mu_TPMU_ASYM_SCHEME_Marshal (buffer, p->scheme, &p->details); ++} ++ ++void ++grub_tpm2_mu_TPMU_KDF_SCHEME_Marshal (grub_tpm2_buffer_t buffer, ++ TPMI_ALG_KDF scheme, ++ TPMU_KDF_SCHEME *p) ++{ ++ switch (scheme) ++ { ++ case TPM_ALG_MGF1: ++ grub_tpm2_buffer_pack_u16 (buffer, p->mgf1.hashAlg); ++ break; ++ case TPM_ALG_KDF1_SP800_56A: ++ grub_tpm2_buffer_pack_u16 (buffer, p->kdf1_sp800_56a.hashAlg); ++ break; ++ case TPM_ALG_KDF2: ++ grub_tpm2_buffer_pack_u16 (buffer, p->kdf2.hashAlg); ++ break; ++ case TPM_ALG_KDF1_SP800_108: ++ grub_tpm2_buffer_pack_u16 (buffer, p->kdf1_sp800_108.hashAlg); ++ break; ++ case TPM_ALG_NULL: ++ break; ++ default: ++ buffer->error = 1; ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMT_KDF_SCHEME_Marshal (grub_tpm2_buffer_t buffer, ++ TPMT_KDF_SCHEME *p) ++{ ++ grub_tpm2_buffer_pack_u16 (buffer, p->scheme); ++ grub_tpm2_mu_TPMU_KDF_SCHEME_Marshal (buffer, p->scheme, &p->details); ++} ++ ++void ++grub_tpm2_mu_TPMS_ECC_PARMS_Marshal (grub_tpm2_buffer_t buffer, ++ TPMS_ECC_PARMS *p) ++{ ++ grub_tpm2_mu_TPMT_SYM_DEF_OBJECT_Marshal (buffer, &p->symmetric); ++ grub_tpm2_mu_TPMT_ECC_SCHEME_Marshal (buffer, &p->scheme); ++ grub_tpm2_buffer_pack_u16 (buffer, p->curveID); ++ grub_tpm2_mu_TPMT_KDF_SCHEME_Marshal (buffer, &p->kdf); ++} ++ ++void ++grub_tpm2_mu_TPMU_PUBLIC_PARMS_Marshal (grub_tpm2_buffer_t buffer, ++ grub_uint32_t type, ++ TPMU_PUBLIC_PARMS *p) ++{ ++ switch (type) ++ { ++ case TPM_ALG_KEYEDHASH: ++ grub_tpm2_mu_TPMS_KEYEDHASH_PARMS_Marshal (buffer, &p->keyedHashDetail); ++ break; ++ case TPM_ALG_SYMCIPHER: ++ grub_tpm2_mu_TPMS_SYMCIPHER_PARMS_Marshal (buffer, &p->symDetail); ++ break; ++ case TPM_ALG_RSA: ++ grub_tpm2_mu_TPMS_RSA_PARMS_Marshal (buffer, &p->rsaDetail); ++ break; ++ case TPM_ALG_ECC: ++ grub_tpm2_mu_TPMS_ECC_PARMS_Marshal (buffer, &p->eccDetail); ++ break; ++ default: ++ buffer->error = 1; ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMS_ECC_POINT_Marshal (grub_tpm2_buffer_t buffer, ++ TPMS_ECC_POINT *p) ++{ ++ grub_tpm2_mu_TPM2B_Marshal (buffer, p->x.size, p->x.buffer); ++ grub_tpm2_mu_TPM2B_Marshal (buffer, p->y.size, p->y.buffer); ++} ++ ++void ++grub_tpm2_mu_TPMU_PUBLIC_ID_Marshal (grub_tpm2_buffer_t buffer, ++ TPMI_ALG_PUBLIC type, ++ TPMU_PUBLIC_ID *p) ++{ ++ switch(type) ++ { ++ case TPM_ALG_KEYEDHASH: ++ grub_tpm2_mu_TPM2B_Marshal (buffer, p->keyedHash.size, ++ p->keyedHash.buffer); ++ break; ++ case TPM_ALG_SYMCIPHER: ++ grub_tpm2_mu_TPM2B_Marshal (buffer, p->sym.size, p->sym.buffer); ++ break; ++ case TPM_ALG_RSA: ++ grub_tpm2_mu_TPM2B_Marshal (buffer, p->rsa.size, p->rsa.buffer); ++ break; ++ case TPM_ALG_ECC: ++ grub_tpm2_mu_TPMS_ECC_POINT_Marshal (buffer, &p->ecc); ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMT_PUBLIC_Marshal (grub_tpm2_buffer_t buffer, ++ TPMT_PUBLIC *p) ++{ ++ grub_tpm2_buffer_pack_u16 (buffer, p->type); ++ grub_tpm2_buffer_pack_u16 (buffer, p->nameAlg); ++ grub_tpm2_mu_TPMA_OBJECT_Marshal (buffer, &p->objectAttributes); ++ grub_tpm2_mu_TPM2B_Marshal (buffer, p->authPolicy.size, p->authPolicy.buffer); ++ grub_tpm2_mu_TPMU_PUBLIC_PARMS_Marshal (buffer, p->type, &p->parameters); ++ grub_tpm2_mu_TPMU_PUBLIC_ID_Marshal (buffer, p->type, &p->unique); ++} ++ ++void ++grub_tpm2_mu_TPM2B_PUBLIC_Marshal (grub_tpm2_buffer_t buffer, ++ TPM2B_PUBLIC *p) ++{ ++ grub_uint32_t start; ++ grub_uint16_t size; ++ ++ if (p) ++ { ++ grub_tpm2_buffer_pack_u16 (buffer, p->size); ++ ++ start = buffer->size; ++ grub_tpm2_mu_TPMT_PUBLIC_Marshal (buffer, &p->publicArea); ++ size = grub_swap_bytes16 (buffer->size - start); ++ grub_memcpy (&buffer->data[start - sizeof (grub_uint16_t)], &size, ++ sizeof (size)); ++ } ++ else ++ grub_tpm2_buffer_pack_u16 (buffer, 0); ++} ++ ++void ++grub_tpm2_mu_TPMS_SENSITIVE_CREATE_Marshal (grub_tpm2_buffer_t buffer, ++ TPMS_SENSITIVE_CREATE *p) ++{ ++ grub_tpm2_mu_TPM2B_Marshal (buffer, p->userAuth.size, p->userAuth.buffer); ++ grub_tpm2_mu_TPM2B_Marshal (buffer, p->data.size, p->data.buffer); ++} ++ ++void ++grub_tpm2_mu_TPM2B_SENSITIVE_CREATE_Marshal (grub_tpm2_buffer_t buffer, ++ TPM2B_SENSITIVE_CREATE *sensitiveCreate) ++{ ++ grub_uint32_t start; ++ grub_uint16_t size; ++ ++ if (sensitiveCreate) ++ { ++ grub_tpm2_buffer_pack_u16 (buffer, sensitiveCreate->size); ++ start = buffer->size; ++ grub_tpm2_mu_TPMS_SENSITIVE_CREATE_Marshal (buffer, ++ &sensitiveCreate->sensitive); ++ size = grub_swap_bytes16 (buffer->size - start); ++ ++ grub_memcpy (&buffer->data[start - sizeof (grub_uint16_t)], &size, ++ sizeof (size)); ++ } ++ else ++ grub_tpm2_buffer_pack_u16 (buffer, 0); ++} ++ ++void ++grub_tpm2_mu_TPM2B_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPM2B* p) ++{ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->size); ++ ++ for (grub_uint16_t i = 0; i < p->size; i++) ++ grub_tpm2_buffer_unpack_u8 (buffer, &p->buffer[i]); ++} ++ ++void ++grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMS_AUTH_RESPONSE* p) ++{ ++ grub_uint8_t tmp; ++ grub_uint32_t tmp32; ++ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->nonce.size); ++ ++ if (p->nonce.size) ++ grub_tpm2_buffer_unpack (buffer, &p->nonce.buffer, p->nonce.size); ++ ++ grub_tpm2_buffer_unpack_u8 (buffer, &tmp); ++ tmp32 = tmp; ++ grub_memcpy (&p->sessionAttributes, &tmp32, sizeof (grub_uint32_t)); ++ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->hmac.size); ++ ++ if (p->hmac.size) ++ grub_tpm2_buffer_unpack (buffer, &p->hmac.buffer, p->hmac.size); ++} ++ ++void ++grub_tpm2_mu_TPM2B_DIGEST_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPM2B_DIGEST* digest) ++{ ++ grub_tpm2_mu_TPM2B_Unmarshal (buffer, (TPM2B*)digest); ++} ++ ++void ++grub_tpm2_mu_TPMA_OBJECT_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMA_OBJECT *p) ++{ ++ grub_tpm2_buffer_unpack_u32 (buffer, (grub_uint32_t*)p); ++} ++ ++void ++grub_tpm2_mu_TPMS_SCHEME_HMAC_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMS_SCHEME_HMAC *p) ++{ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->hashAlg); ++} ++ ++void ++grub_tpm2_mu_TPMS_SCHEME_XOR_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMS_SCHEME_XOR *p) ++{ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->hashAlg); ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->kdf); ++} ++ ++void ++grub_tpm2_mu_TPMU_SCHEME_KEYEDHASH_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMI_ALG_KEYEDHASH_SCHEME scheme, ++ TPMU_SCHEME_KEYEDHASH *p) ++{ ++ switch (scheme) ++ { ++ case TPM_ALG_HMAC: ++ grub_tpm2_mu_TPMS_SCHEME_HMAC_Unmarshal (buffer, &p->hmac); ++ break; ++ case TPM_ALG_XOR: ++ grub_tpm2_mu_TPMS_SCHEME_XOR_Unmarshal (buffer, &p->exclusiveOr); ++ break; ++ case TPM_ALG_NULL: ++ break; ++ default: ++ buffer->error = 1; ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMT_KEYEDHASH_SCHEME_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMT_KEYEDHASH_SCHEME *p) ++{ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->scheme); ++ grub_tpm2_mu_TPMU_SCHEME_KEYEDHASH_Unmarshal (buffer, p->scheme, &p->details); ++} ++ ++void ++grub_tpm2_mu_TPMS_KEYEDHASH_PARMS_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMS_KEYEDHASH_PARMS *p) ++{ ++ grub_tpm2_mu_TPMT_KEYEDHASH_SCHEME_Unmarshal (buffer, &p->scheme); ++} ++ ++void ++grub_tpm2_mu_TPMU_SYM_KEY_BITS_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMI_ALG_SYM_OBJECT algorithm, ++ TPMU_SYM_KEY_BITS *p) ++{ ++ switch (algorithm) ++ { ++ case TPM_ALG_AES: ++ case TPM_ALG_SM4: ++ case TPM_ALG_CAMELLIA: ++ case TPM_ALG_XOR: ++ grub_tpm2_buffer_unpack_u16 (buffer, (grub_uint16_t*) p); ++ break; ++ case TPM_ALG_NULL: ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMU_SYM_MODE_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMI_ALG_SYM_OBJECT algorithm, ++ TPMU_SYM_MODE *p) ++{ ++ switch (algorithm) ++ { ++ case TPM_ALG_AES: ++ case TPM_ALG_SM4: ++ case TPM_ALG_CAMELLIA: ++ grub_tpm2_buffer_unpack_u16 (buffer, (grub_uint16_t*) p); ++ break; ++ case TPM_ALG_XOR: ++ case TPM_ALG_NULL: ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMT_SYM_DEF_OBJECT_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMT_SYM_DEF_OBJECT *p) ++{ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->algorithm); ++ grub_tpm2_mu_TPMU_SYM_KEY_BITS_Unmarshal (buffer, p->algorithm, &p->keyBits); ++ grub_tpm2_mu_TPMU_SYM_MODE_Unmarshal (buffer, p->algorithm, &p->mode); ++} ++ ++void ++grub_tpm2_mu_TPMS_SYMCIPHER_PARMS_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMS_SYMCIPHER_PARMS *p) ++{ ++ grub_tpm2_mu_TPMT_SYM_DEF_OBJECT_Unmarshal (buffer, &p->sym); ++} ++ ++void ++grub_tpm2_mu_TPMU_ASYM_SCHEME_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMI_ALG_RSA_DECRYPT scheme, ++ TPMU_ASYM_SCHEME *p __attribute__((unused))) ++{ ++ switch (scheme) ++ { ++ case TPM_ALG_NULL: ++ break; ++ default: ++ /* Unsupported */ ++ buffer->error = 1; ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMT_RSA_SCHEME_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMT_RSA_SCHEME *p) ++{ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->scheme); ++ grub_tpm2_mu_TPMU_ASYM_SCHEME_Unmarshal (buffer, p->scheme, &p->details); ++} ++ ++void ++grub_tpm2_mu_TPMS_RSA_PARMS_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMS_RSA_PARMS *p) ++{ ++ grub_tpm2_mu_TPMT_SYM_DEF_OBJECT_Unmarshal (buffer, &p->symmetric); ++ grub_tpm2_mu_TPMT_RSA_SCHEME_Unmarshal (buffer, &p->scheme); ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->keyBits); ++ grub_tpm2_buffer_unpack_u32 (buffer, &p->exponent); ++} ++ ++void ++grub_tpm2_mu_TPMT_ECC_SCHEME_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMT_ECC_SCHEME *p) ++{ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->scheme); ++ grub_tpm2_mu_TPMU_ASYM_SCHEME_Unmarshal (buffer, p->scheme, &p->details); ++} ++ ++void ++grub_tpm2_mu_TPMU_KDF_SCHEME_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMI_ALG_KDF scheme, ++ TPMU_KDF_SCHEME *p) ++{ ++ switch (scheme) ++ { ++ case TPM_ALG_MGF1: ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->mgf1.hashAlg); ++ break; ++ case TPM_ALG_KDF1_SP800_56A: ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->kdf1_sp800_56a.hashAlg); ++ break; ++ case TPM_ALG_KDF2: ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->kdf2.hashAlg); ++ break; ++ case TPM_ALG_KDF1_SP800_108: ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->kdf1_sp800_108.hashAlg); ++ break; ++ case TPM_ALG_NULL: ++ break; ++ default: ++ buffer->error = 1; ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMT_KDF_SCHEME_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMT_KDF_SCHEME *p) ++{ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->scheme); ++ grub_tpm2_mu_TPMU_KDF_SCHEME_Unmarshal (buffer, p->scheme, &p->details); ++} ++ ++void ++grub_tpm2_mu_TPMS_ECC_PARMS_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMS_ECC_PARMS *p) ++{ ++ grub_tpm2_mu_TPMT_SYM_DEF_OBJECT_Unmarshal (buffer, &p->symmetric); ++ grub_tpm2_mu_TPMT_ECC_SCHEME_Unmarshal (buffer, &p->scheme ); ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->curveID); ++ grub_tpm2_mu_TPMT_KDF_SCHEME_Unmarshal (buffer, &p->kdf); ++} ++ ++void ++grub_tpm2_mu_TPMU_PUBLIC_PARMS_Unmarshal (grub_tpm2_buffer_t buffer, ++ grub_uint32_t type, ++ TPMU_PUBLIC_PARMS *p) ++{ ++ switch (type) ++ { ++ case TPM_ALG_KEYEDHASH: ++ grub_tpm2_mu_TPMS_KEYEDHASH_PARMS_Unmarshal (buffer, &p->keyedHashDetail); ++ break; ++ case TPM_ALG_SYMCIPHER: ++ grub_tpm2_mu_TPMS_SYMCIPHER_PARMS_Unmarshal (buffer, &p->symDetail); ++ break; ++ case TPM_ALG_RSA: ++ grub_tpm2_mu_TPMS_RSA_PARMS_Unmarshal (buffer, &p->rsaDetail); ++ break; ++ case TPM_ALG_ECC: ++ grub_tpm2_mu_TPMS_ECC_PARMS_Unmarshal (buffer, &p->eccDetail); ++ break; ++ default: ++ buffer->error = 1; ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMS_ECC_POINT_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMS_ECC_POINT *p) ++{ ++ grub_tpm2_mu_TPM2B_Unmarshal (buffer, (TPM2B*) &p->x); ++ grub_tpm2_mu_TPM2B_Unmarshal (buffer, (TPM2B*) &p->y); ++} ++ ++void ++grub_tpm2_mu_TPMU_PUBLIC_ID_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMI_ALG_PUBLIC type, ++ TPMU_PUBLIC_ID *p) ++{ ++ switch(type) ++ { ++ case TPM_ALG_KEYEDHASH: ++ grub_tpm2_mu_TPM2B_Unmarshal (buffer, (TPM2B*) &p->keyedHash); ++ break; ++ case TPM_ALG_SYMCIPHER: ++ grub_tpm2_mu_TPM2B_Unmarshal (buffer, (TPM2B*) &p->sym); ++ break; ++ case TPM_ALG_RSA: ++ grub_tpm2_mu_TPM2B_Unmarshal (buffer, (TPM2B*) &p->rsa); ++ break; ++ case TPM_ALG_ECC: ++ grub_tpm2_mu_TPMS_ECC_POINT_Unmarshal (buffer, &p->ecc); ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMT_PUBLIC_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMT_PUBLIC *p) ++{ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->type); ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->nameAlg); ++ grub_tpm2_mu_TPMA_OBJECT_Unmarshal (buffer, &p->objectAttributes); ++ grub_tpm2_mu_TPM2B_Unmarshal (buffer, (TPM2B*) &p->authPolicy); ++ grub_tpm2_mu_TPMU_PUBLIC_PARMS_Unmarshal (buffer, p->type, &p->parameters); ++ grub_tpm2_mu_TPMU_PUBLIC_ID_Unmarshal (buffer, p->type, &p->unique); ++} ++ ++void ++grub_tpm2_mu_TPM2B_PUBLIC_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPM2B_PUBLIC *p) ++{ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->size); ++ grub_tpm2_mu_TPMT_PUBLIC_Unmarshal (buffer, &p->publicArea); ++} ++ ++void ++grub_tpm2_mu_TPMS_NV_PUBLIC_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMS_NV_PUBLIC *p) ++{ ++ grub_tpm2_buffer_unpack_u32 (buffer, &p->nvIndex); ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->nameAlg); ++ grub_tpm2_buffer_unpack_u32 (buffer, &p->attributes); ++ grub_tpm2_mu_TPM2B_DIGEST_Unmarshal (buffer, &p->authPolicy); ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->dataSize); ++} ++ ++void ++grub_tpm2_mu_TPM2B_NV_PUBLIC_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPM2B_NV_PUBLIC *p) ++{ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->size); ++ grub_tpm2_mu_TPMS_NV_PUBLIC_Unmarshal (buffer, &p->nvPublic); ++} ++ ++void ++grub_tpm2_mu_TPM2B_NAME_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPM2B_NAME *n) ++{ ++ grub_tpm2_buffer_unpack_u16 (buffer, &n->size); ++ grub_tpm2_buffer_unpack (buffer, n->name, n->size); ++} ++ ++void ++grub_tpm2_mu_TPMS_TAGGED_PROPERTY_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMS_TAGGED_PROPERTY* property) ++{ ++ grub_tpm2_buffer_unpack_u32 (buffer, &property->property); ++ grub_tpm2_buffer_unpack_u32 (buffer, &property->value); ++} ++ ++void ++grub_tpm2_mu_TPMS_CAPABILITY_DATA_tpmProperties_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMS_CAPABILITY_DATA* capabilityData) ++{ ++ grub_tpm2_buffer_unpack_u32 (buffer, ++ &capabilityData->data.tpmProperties.count); ++ ++ if (buffer->error) ++ return; ++ ++ for (grub_uint32_t i = 0; i < capabilityData->data.tpmProperties.count; i++) ++ grub_tpm2_mu_TPMS_TAGGED_PROPERTY_Unmarshal (buffer, ++ &capabilityData->data.tpmProperties.tpmProperty[i]); ++} ++ ++void ++grub_tpm2_mu_TPMT_TK_CREATION_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMT_TK_CREATION *p) ++{ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->tag); ++ grub_tpm2_buffer_unpack_u32 (buffer, &p->hierarchy); ++ grub_tpm2_mu_TPM2B_Unmarshal (buffer, (TPM2B*) &p->digest); ++} ++ ++void ++grub_tpm2_mu_TPMS_PCR_SELECTION_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMS_PCR_SELECTION* pcrSelection) ++{ ++ grub_tpm2_buffer_unpack_u16 (buf, &pcrSelection->hash); ++ grub_tpm2_buffer_unpack_u8 (buf, &pcrSelection->sizeOfSelect); ++ ++ for (grub_uint32_t i = 0; i < pcrSelection->sizeOfSelect; i++) ++ grub_tpm2_buffer_unpack_u8 (buf, &pcrSelection->pcrSelect[i]); ++} ++ ++void ++grub_tpm2_mu_TPML_PCR_SELECTION_Unmarshal (grub_tpm2_buffer_t buf, ++ TPML_PCR_SELECTION* pcrSelection) ++{ ++ grub_tpm2_buffer_unpack_u32 (buf, &pcrSelection->count); ++ ++ for (grub_uint32_t i = 0; i < pcrSelection->count; i++) ++ grub_tpm2_mu_TPMS_PCR_SELECTION_Unmarshal (buf, &pcrSelection->pcrSelections[i]); ++} ++ ++void ++grub_tpm2_mu_TPML_DIGEST_Unmarshal (grub_tpm2_buffer_t buf, ++ TPML_DIGEST* digest) ++{ ++ grub_tpm2_buffer_unpack_u32 (buf, &digest->count); ++ ++ for (grub_uint32_t i = 0; i < digest->count; i++) ++ grub_tpm2_mu_TPM2B_DIGEST_Unmarshal (buf, &digest->digests[i]); ++} +diff --git a/grub-core/tpm2/tcg2.c b/grub-core/tpm2/tcg2.c +new file mode 100644 +index 0000000000..44837218a2 +--- /dev/null ++++ b/grub-core/tpm2/tcg2.c +@@ -0,0 +1,143 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * 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 . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static grub_err_t ++grub_tcg2_get_caps (grub_efi_tpm2_protocol_t *protocol, int *tpm2, ++ grub_size_t *max_output_size) ++{ ++ grub_efi_status_t status; ++ ++ static int has_caps = 0; ++ static EFI_TCG2_BOOT_SERVICE_CAPABILITY caps = ++ { ++ .Size = (grub_uint8_t) sizeof (caps) ++ }; ++ ++ if (has_caps) ++ goto exit; ++ ++ status = efi_call_2 (protocol->get_capability, protocol, &caps); ++ if (status != GRUB_EFI_SUCCESS || !caps.TPMPresentFlag) ++ return GRUB_ERR_FILE_NOT_FOUND; ++ ++ has_caps = 1; ++ ++exit: ++ if (tpm2) ++ *tpm2 = caps.TPMPresentFlag; ++ if (max_output_size) ++ *max_output_size = caps.MaxResponseSize; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_tcg2_get_protocol (grub_efi_tpm2_protocol_t **protocol) ++{ ++ static grub_efi_guid_t tpm2_guid = EFI_TPM2_GUID; ++ static grub_efi_tpm2_protocol_t *tpm2_protocol = NULL; ++ ++ int tpm2; ++ grub_efi_handle_t *handles; ++ grub_efi_uintn_t num_handles; ++ grub_efi_handle_t tpm2_handle; ++ grub_err_t err = GRUB_ERR_FILE_NOT_FOUND; ++ ++ if (tpm2_protocol) ++ { ++ *protocol = tpm2_protocol; ++ return GRUB_ERR_NONE; ++ } ++ ++ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &tpm2_guid, NULL, ++ &num_handles); ++ if (!handles || !num_handles) ++ return err; ++ ++ tpm2_handle = handles[0]; ++ ++ tpm2_protocol = grub_efi_open_protocol (tpm2_handle, &tpm2_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ if (!tpm2_protocol) ++ goto exit; ++ ++ err = grub_tcg2_get_caps (tpm2_protocol, &tpm2, NULL); ++ if (err || !tpm2) ++ goto exit; ++ ++ *protocol = tpm2_protocol; ++ err = GRUB_ERR_NONE; ++ ++exit: ++ grub_free (handles); ++ return err; ++} ++ ++grub_err_t ++grub_tcg2_get_max_output_size (grub_size_t *size) ++{ ++ grub_err_t err; ++ grub_size_t max; ++ grub_efi_tpm2_protocol_t *protocol; ++ ++ if (!size) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ err = grub_tcg2_get_protocol (&protocol); ++ if (err) ++ return err; ++ ++ err = grub_tcg2_get_caps (protocol, NULL, &max); ++ if (err) ++ return err; ++ ++ *size = max; ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_tcg2_submit_command (grub_size_t input_size, ++ grub_uint8_t *input, ++ grub_size_t output_size, ++ grub_uint8_t *output) ++{ ++ grub_err_t err; ++ grub_efi_status_t status; ++ grub_efi_tpm2_protocol_t *protocol; ++ ++ if (!input_size || !input || !output_size || !output) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ err = grub_tcg2_get_protocol (&protocol); ++ if (err) ++ return err; ++ ++ status = efi_call_5 (protocol->submit_command, protocol, input_size, input, ++ output_size, output); ++ if (status != GRUB_EFI_SUCCESS) ++ return GRUB_ERR_INVALID_COMMAND; ++ ++ return GRUB_ERR_NONE; ++} +diff --git a/grub-core/tpm2/tpm2.c b/grub-core/tpm2/tpm2.c +new file mode 100644 +index 0000000000..2407a844d2 +--- /dev/null ++++ b/grub-core/tpm2/tpm2.c +@@ -0,0 +1,711 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * 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 . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static TPM_RC ++grub_tpm2_submit_command (TPMI_ST_COMMAND_TAG tag, ++ TPM_CC commandCode, ++ TPM_RC* responseCode, ++ const struct grub_tpm2_buffer* in, ++ struct grub_tpm2_buffer* out) ++{ ++ grub_err_t err; ++ struct grub_tpm2_buffer buf; ++ TPMI_ST_COMMAND_TAG tag_out; ++ grub_uint32_t command_size; ++ grub_size_t max_output_size; ++ ++ /* Marshal */ ++ grub_tpm2_buffer_init (&buf); ++ grub_tpm2_buffer_pack_u16 (&buf, tag); ++ grub_tpm2_buffer_pack_u32 (&buf, 0); ++ grub_tpm2_buffer_pack_u32 (&buf, commandCode); ++ grub_tpm2_buffer_pack (&buf, in->data, in->size); ++ ++ if (buf.error) ++ return TPM_RC_FAILURE; ++ ++ command_size = grub_swap_bytes32 (buf.size); ++ grub_memcpy (&buf.data[sizeof (grub_uint16_t)], &command_size, ++ sizeof (command_size)); ++ ++ /* Stay within output block limits */ ++ err = grub_tcg2_get_max_output_size (&max_output_size); ++ if (err || max_output_size > out->cap) ++ max_output_size = out->cap - 1; ++ ++ /* Submit */ ++ err = grub_tcg2_submit_command (buf.size, buf.data, max_output_size, ++ out->data); ++ if (err) ++ return TPM_RC_FAILURE; ++ ++ /* Unmarshal*/ ++ out->size = sizeof (grub_uint16_t) + sizeof (grub_uint32_t) + ++ sizeof (grub_uint32_t); ++ grub_tpm2_buffer_unpack_u16 (out, &tag_out); ++ grub_tpm2_buffer_unpack_u32 (out, &command_size); ++ grub_tpm2_buffer_unpack_u32 (out, responseCode); ++ out->size = command_size; ++ if (out->error) ++ return TPM_RC_FAILURE; ++ ++ return TPM_RC_SUCCESS; ++} ++ ++TPM_RC ++TPM2_CreatePrimary (TPMI_RH_HIERARCHY primaryHandle, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPM2B_SENSITIVE_CREATE *inSensitive, ++ TPM2B_PUBLIC *inPublic, ++ TPM2B_DATA *outsideInfo, ++ TPML_PCR_SELECTION *creationPCR, ++ TPM_HANDLE *objectHandle, ++ TPM2B_PUBLIC *outPublic, ++ TPM2B_CREATION_DATA *creationData, ++ TPM2B_DIGEST *creationHash, ++ TPMT_TK_CREATION *creationTicket, ++ TPM2B_NAME *name, ++ TPMS_AUTH_RESPONSE *authResponse) ++{ ++ TPM_RC rc; ++ struct grub_tpm2_buffer in; ++ struct grub_tpm2_buffer out; ++ TPM_HANDLE objectHandleTmp; ++ TPM2B_PUBLIC outPublicTmp; ++ TPM2B_CREATION_DATA creationDataTmp; ++ TPM2B_DIGEST creationHashTmp; ++ TPMT_TK_CREATION creationTicketTmp; ++ TPM2B_NAME nameTmp; ++ TPMS_AUTH_RESPONSE authResponseTmp; ++ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS; ++ TPM_RC responseCode; ++ grub_uint32_t parameterSize; ++ ++ if (!objectHandle) ++ objectHandle = &objectHandleTmp; ++ if (!outPublic) ++ outPublic = &outPublicTmp; ++ if (!creationData) ++ creationData = &creationDataTmp; ++ if (!creationHash) ++ creationHash = &creationHashTmp; ++ if (!creationTicket) ++ creationTicket = &creationTicketTmp; ++ if (!name) ++ name = &nameTmp; ++ if (!authResponse) ++ authResponse = &authResponseTmp; ++ ++ grub_memset (outPublic, 0, sizeof (*outPublic)); ++ grub_memset (creationData, 0, sizeof (*creationData)); ++ grub_memset (creationHash, 0, sizeof (*creationHash)); ++ grub_memset (creationTicket, 0, sizeof (*creationTicket)); ++ grub_memset (name, 0, sizeof (*name)); ++ grub_memset (authResponse, 0, sizeof (*authResponse)); ++ ++ /* Marshal */ ++ grub_tpm2_buffer_init (&in); ++ grub_tpm2_buffer_pack_u32 (&in, primaryHandle); ++ if (authCommand) ++ grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (&in, authCommand); ++ grub_tpm2_mu_TPM2B_SENSITIVE_CREATE_Marshal (&in, inSensitive); ++ grub_tpm2_mu_TPM2B_PUBLIC_Marshal (&in, inPublic); ++ grub_tpm2_mu_TPM2B_Marshal (&in, outsideInfo->size, outsideInfo->buffer); ++ grub_tpm2_mu_TPML_PCR_SELECTION_Marshal (&in, creationPCR); ++ if (in.error) ++ return TPM_RC_FAILURE; ++ ++ /* Submit */ ++ grub_tpm2_buffer_init (&out); ++ rc = grub_tpm2_submit_command (tag, TPM_CC_CreatePrimary, &responseCode, &in, ++ &out); ++ if (rc != TPM_RC_SUCCESS) ++ return rc; ++ if (responseCode != TPM_RC_SUCCESS) ++ return responseCode; ++ ++ /* Unmarshal*/ ++ grub_tpm2_buffer_unpack_u32 (&out, objectHandle); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_buffer_unpack_u32 (&out, ¶meterSize); ++ grub_tpm2_mu_TPM2B_PUBLIC_Unmarshal (&out, outPublic); ++ grub_tpm2_mu_TPM2B_Unmarshal (&out, (TPM2B*)creationData); ++ grub_tpm2_mu_TPM2B_Unmarshal (&out, (TPM2B*)creationHash); ++ grub_tpm2_mu_TPMT_TK_CREATION_Unmarshal (&out, creationTicket); ++ grub_tpm2_mu_TPM2B_Unmarshal (&out, (TPM2B*)name); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse); ++ if (out.error) ++ return TPM_RC_FAILURE; ++ ++ return TPM_RC_SUCCESS; ++} ++ ++TPM_RC ++TPM2_StartAuthSession (TPMI_DH_OBJECT tpmKey, ++ TPMI_DH_ENTITY bind, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPM2B_NONCE *nonceCaller, ++ TPM2B_ENCRYPTED_SECRET *encryptedSalt, ++ TPM_SE sessionType, ++ TPMT_SYM_DEF *symmetric, ++ TPMI_ALG_HASH authHash, ++ TPMI_SH_AUTH_SESSION *sessionHandle, ++ TPM2B_NONCE *nonceTpm, ++ TPMS_AUTH_RESPONSE *authResponse) ++{ ++ TPM_RC rc; ++ struct grub_tpm2_buffer in; ++ struct grub_tpm2_buffer out; ++ TPMI_SH_AUTH_SESSION sessionHandleTmp; ++ TPM2B_NONCE nonceTpmTmp; ++ TPMS_AUTH_RESPONSE authResponseTmp; ++ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS; ++ TPM_RC responseCode; ++ grub_uint32_t param_size; ++ ++ if (!sessionHandle) ++ sessionHandle = &sessionHandleTmp; ++ if (!nonceTpm) ++ nonceTpm = &nonceTpmTmp; ++ if (!authResponse) ++ authResponse = &authResponseTmp; ++ ++ grub_memset (sessionHandle, 0, sizeof (*sessionHandle)); ++ grub_memset (nonceTpm, 0, sizeof (*nonceTpm)); ++ grub_memset (authResponse, 0, sizeof (*authResponse)); ++ ++ /* Marshal */ ++ grub_tpm2_buffer_init (&in); ++ grub_tpm2_buffer_pack_u32 (&in, tpmKey); ++ grub_tpm2_buffer_pack_u32 (&in, bind); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (&in, authCommand); ++ grub_tpm2_mu_TPM2B_Marshal (&in, nonceCaller->size, nonceCaller->buffer); ++ grub_tpm2_mu_TPM2B_Marshal (&in, encryptedSalt->size, encryptedSalt->secret); ++ grub_tpm2_buffer_pack_u8 (&in, sessionType); ++ grub_tpm2_mu_TPMT_SYM_DEF_Marshal (&in, symmetric); ++ grub_tpm2_buffer_pack_u16 (&in, authHash); ++ if (in.error) ++ return TPM_RC_FAILURE; ++ ++ /* Submit */ ++ grub_tpm2_buffer_init (&out); ++ rc = grub_tpm2_submit_command (tag, TPM_CC_StartAuthSession, &responseCode, ++ &in, &out); ++ if (rc != TPM_RC_SUCCESS) ++ return rc; ++ if (responseCode != TPM_RC_SUCCESS) ++ return responseCode; ++ ++ /* Unmarshal*/ ++ grub_tpm2_buffer_unpack_u32 (&out, sessionHandle); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_buffer_unpack_u32 (&out, ¶m_size); ++ grub_tpm2_mu_TPM2B_Unmarshal (&out, (TPM2B*)nonceTpm); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse); ++ if (out.error) ++ return TPM_RC_FAILURE; ++ ++ return TPM_RC_SUCCESS; ++} ++ ++TPM_RC ++TPM2_PolicyPCR (TPMI_SH_POLICY policySessions, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPM2B_DIGEST *pcrDigest, ++ TPML_PCR_SELECTION *pcrs, ++ TPMS_AUTH_RESPONSE *authResponse) ++{ ++ TPM_RC rc; ++ struct grub_tpm2_buffer in; ++ struct grub_tpm2_buffer out; ++ TPMS_AUTH_RESPONSE authResponseTmp; ++ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS; ++ TPM_RC responseCode; ++ grub_uint32_t param_size; ++ ++ if (!authResponse) ++ authResponse = &authResponseTmp; ++ ++ grub_memset (authResponse, 0, sizeof (*authResponse)); ++ ++ /* Marshal */ ++ grub_tpm2_buffer_init (&in); ++ grub_tpm2_buffer_pack_u32 (&in, policySessions); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (&in, authCommand); ++ grub_tpm2_mu_TPM2B_Marshal (&in, pcrDigest->size, pcrDigest->buffer); ++ grub_tpm2_mu_TPML_PCR_SELECTION_Marshal (&in, pcrs); ++ if (in.error) ++ return TPM_RC_FAILURE; ++ ++ /* Submit */ ++ grub_tpm2_buffer_init (&out); ++ rc = grub_tpm2_submit_command (tag, TPM_CC_PolicyPCR, &responseCode, &in, ++ &out); ++ if (rc != TPM_RC_SUCCESS) ++ return rc; ++ if (responseCode != TPM_RC_SUCCESS) ++ return responseCode; ++ ++ /* Unmarshal*/ ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_buffer_unpack_u32 (&out, ¶m_size); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse); ++ if (out.error) ++ return TPM_RC_FAILURE; ++ ++ return TPM_RC_SUCCESS; ++} ++ ++TPM_RC ++TPM2_ReadPublic (TPMI_DH_OBJECT objectHandle, ++ const TPMS_AUTH_COMMAND* authCommand, ++ TPM2B_PUBLIC *outPublic) ++{ ++ TPM_RC rc; ++ struct grub_tpm2_buffer in; ++ struct grub_tpm2_buffer out; ++ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS; ++ TPM_RC responseCode; ++ grub_uint32_t parameterSize; ++ ++ /* Marshal */ ++ grub_tpm2_buffer_init (&in); ++ grub_tpm2_buffer_pack_u32 (&in, objectHandle); ++ if (in.error) ++ return TPM_RC_FAILURE; ++ ++ /* Submit */ ++ grub_tpm2_buffer_init (&out); ++ rc = grub_tpm2_submit_command (tag, TPM_CC_ReadPublic, &responseCode, &in, ++ &out); ++ if (rc != TPM_RC_SUCCESS) ++ return rc; ++ if (responseCode != TPM_RC_SUCCESS) ++ return responseCode; ++ ++ /* Unmarshal*/ ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_buffer_unpack_u32 (&out, ¶meterSize); ++ grub_tpm2_mu_TPM2B_PUBLIC_Unmarshal (&out, outPublic); ++ if (out.error) ++ return TPM_RC_FAILURE; ++ ++ return TPM_RC_SUCCESS; ++} ++ ++TPM_RC ++TPM2_Load (TPMI_DH_OBJECT parent_handle, ++ TPMS_AUTH_COMMAND const *authCommand, ++ TPM2B_PRIVATE *inPrivate, ++ TPM2B_PUBLIC *inPublic, ++ TPM_HANDLE *objectHandle, ++ TPM2B_NAME *name, ++ TPMS_AUTH_RESPONSE *authResponse) ++{ ++ TPM_RC rc; ++ struct grub_tpm2_buffer in; ++ struct grub_tpm2_buffer out; ++ TPM_HANDLE objectHandleTmp; ++ TPM2B_NAME nonceTmp; ++ TPMS_AUTH_RESPONSE authResponseTmp; ++ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS; ++ TPM_RC responseCode; ++ grub_uint32_t param_size; ++ ++ if (!objectHandle) ++ objectHandle = &objectHandleTmp; ++ if (!name) ++ name = &nonceTmp; ++ if (!authResponse) ++ authResponse = &authResponseTmp; ++ ++ grub_memset (objectHandle, 0, sizeof (*objectHandle)); ++ grub_memset (name, 0, sizeof (*name)); ++ grub_memset (authResponse, 0, sizeof (*authResponse)); ++ ++ /* Marshal */ ++ grub_tpm2_buffer_init (&in); ++ grub_tpm2_buffer_pack_u32 (&in, parent_handle); ++ if (authCommand) ++ grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (&in, authCommand); ++ grub_tpm2_mu_TPM2B_Marshal (&in, inPrivate->size, inPrivate->buffer); ++ grub_tpm2_mu_TPM2B_PUBLIC_Marshal (&in, inPublic); ++ if (in.error) ++ return TPM_RC_FAILURE; ++ ++ /* Submit */ ++ grub_tpm2_buffer_init (&out); ++ rc = grub_tpm2_submit_command (tag, TPM_CC_Load, &responseCode, &in, &out); ++ if (rc != TPM_RC_SUCCESS) ++ return rc; ++ if (responseCode != TPM_RC_SUCCESS) ++ return responseCode; ++ ++ /* Unmarshal*/ ++ grub_tpm2_buffer_unpack_u32 (&out, objectHandle); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_buffer_unpack_u32 (&out, ¶m_size); ++ grub_tpm2_mu_TPM2B_Unmarshal (&out, (TPM2B*)name); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse); ++ if (out.error) ++ return TPM_RC_FAILURE; ++ ++ return TPM_RC_SUCCESS; ++} ++ ++TPM_RC ++TPM2_Unseal (TPMI_DH_OBJECT itemHandle, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPM2B_SENSITIVE_DATA *outData, ++ TPMS_AUTH_RESPONSE *authResponse) ++{ ++ TPM_RC rc; ++ struct grub_tpm2_buffer in; ++ struct grub_tpm2_buffer out; ++ TPM2B_SENSITIVE_DATA outDataTmp; ++ TPMS_AUTH_RESPONSE authResponseTmp; ++ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS; ++ TPM_RC responseCode; ++ grub_uint32_t param_size; ++ ++ if (!outData) ++ outData = &outDataTmp; ++ if (!authResponse) ++ authResponse = &authResponseTmp; ++ ++ grub_memset (outData, 0, sizeof (*outData)); ++ grub_memset (authResponse, 0, sizeof (*authResponse)); ++ ++ /* Marshal */ ++ grub_tpm2_buffer_init (&in); ++ grub_tpm2_buffer_pack_u32 (&in, itemHandle); ++ if (authCommand) ++ grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (&in, authCommand); ++ if (in.error) ++ return TPM_RC_FAILURE; ++ ++ /* Submit */ ++ grub_tpm2_buffer_init (&out); ++ rc = grub_tpm2_submit_command (tag, TPM_CC_Unseal, &responseCode, &in, &out); ++ if (rc != TPM_RC_SUCCESS) ++ return rc; ++ if (responseCode != TPM_RC_SUCCESS) ++ return responseCode; ++ ++ // Unmarhsal ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_buffer_unpack_u32 (&out, ¶m_size); ++ grub_tpm2_mu_TPM2B_Unmarshal (&out, (TPM2B*)outData); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse); ++ if (out.error) ++ return TPM_RC_FAILURE; ++ ++ return TPM_RC_SUCCESS; ++} ++ ++TPM_RC ++TPM2_FlushContext (TPMI_DH_CONTEXT handle) ++{ ++ TPM_RC rc; ++ struct grub_tpm2_buffer in; ++ struct grub_tpm2_buffer out; ++ TPM_RC responseCode; ++ ++ /* Marshal */ ++ grub_tpm2_buffer_init (&in); ++ grub_tpm2_buffer_pack_u32 (&in, handle); ++ if (in.error) ++ return TPM_RC_FAILURE; ++ ++ /* Submit */ ++ grub_tpm2_buffer_init (&out); ++ rc = grub_tpm2_submit_command (TPM_ST_NO_SESSIONS, TPM_CC_FlushContext, ++ &responseCode, &in, &out); ++ if (rc != TPM_RC_SUCCESS) ++ return rc; ++ if (responseCode != TPM_RC_SUCCESS) ++ return responseCode; ++ ++ /* Unmarshal*/ ++ if (out.error) ++ return TPM_RC_FAILURE; ++ ++ return TPM_RC_SUCCESS; ++} ++ ++TPM_RC ++TPM2_PCR_Read (const TPMS_AUTH_COMMAND *authCommand, ++ TPML_PCR_SELECTION *pcrSelectionIn, ++ grub_uint32_t *pcrUpdateCounter, ++ TPML_PCR_SELECTION *pcrSelectionOut, ++ TPML_DIGEST *pcrValues, ++ TPMS_AUTH_RESPONSE *authResponse) ++{ ++ TPM_RC rc; ++ struct grub_tpm2_buffer in; ++ struct grub_tpm2_buffer out; ++ grub_uint32_t pcrUpdateCounterTmp; ++ TPML_PCR_SELECTION pcrSelectionOutTmp; ++ TPML_DIGEST pcrValuesTmp; ++ TPMS_AUTH_RESPONSE authResponseTmp; ++ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS; ++ TPM_RC responseCode; ++ grub_uint32_t parameterSize; ++ ++ if (!pcrSelectionIn) ++ return TPM_RC_FAILURE; ++ ++ if (!pcrUpdateCounter) ++ pcrUpdateCounter = &pcrUpdateCounterTmp; ++ if (!pcrSelectionOut) ++ pcrSelectionOut = &pcrSelectionOutTmp; ++ if (!pcrValues) ++ pcrValues = &pcrValuesTmp; ++ if (!authResponse) ++ authResponse = &authResponseTmp; ++ ++ /* Marshal */ ++ grub_tpm2_buffer_init (&in); ++ grub_tpm2_mu_TPML_PCR_SELECTION_Marshal (&in, pcrSelectionIn); ++ if (in.error) ++ return TPM_RC_FAILURE; ++ ++ /* Submit */ ++ grub_tpm2_buffer_init (&out); ++ rc = grub_tpm2_submit_command (tag, TPM_CC_PCR_Read, &responseCode, &in, ++ &out); ++ if (rc != TPM_RC_SUCCESS) ++ return rc; ++ if (responseCode != TPM_RC_SUCCESS) ++ return responseCode; ++ ++ /* Unmarshal*/ ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_buffer_unpack_u32 (&out, ¶meterSize); ++ grub_tpm2_buffer_unpack_u32 (&out, pcrUpdateCounter); ++ grub_tpm2_mu_TPML_PCR_SELECTION_Unmarshal (&out, pcrSelectionOut); ++ grub_tpm2_mu_TPML_DIGEST_Unmarshal (&out, pcrValues); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse); ++ if (out.error) ++ return TPM_RC_FAILURE; ++ ++ return TPM_RC_SUCCESS; ++} ++ ++TPM_RC ++TPM2_PolicyGetDigest (TPMI_SH_POLICY policySession, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPM2B_DIGEST *policyDigest, ++ TPMS_AUTH_RESPONSE *authResponse) ++{ ++ TPM_RC rc; ++ struct grub_tpm2_buffer in; ++ struct grub_tpm2_buffer out; ++ TPMS_AUTH_RESPONSE authResponseTmp; ++ TPM2B_DIGEST policyDigestTmp; ++ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS; ++ TPM_RC responseCode; ++ grub_uint32_t parameterSize; ++ ++ if (!authResponse) ++ authResponse = &authResponseTmp; ++ if (!policyDigest) ++ policyDigest = &policyDigestTmp; ++ ++ grub_memset (authResponse, 0, sizeof (*authResponse)); ++ grub_memset (policyDigest, 0, sizeof (*policyDigest)); ++ ++ /* Submit */ ++ grub_tpm2_buffer_init (&in); ++ grub_tpm2_buffer_pack_u32 (&in, policySession); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (&in, authCommand); ++ if (in.error) ++ return TPM_RC_FAILURE; ++ ++ /* Submit */ ++ grub_tpm2_buffer_init (&out); ++ rc = grub_tpm2_submit_command (tag, TPM_CC_PolicyGetDigest, &responseCode, ++ &in, &out); ++ if (rc != TPM_RC_SUCCESS) ++ return rc; ++ if (responseCode != TPM_RC_SUCCESS) ++ return responseCode; ++ ++ /* Unmarshal*/ ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_buffer_unpack_u32 (&out, ¶meterSize); ++ grub_tpm2_mu_TPM2B_Unmarshal (&out, (TPM2B*)policyDigest); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse); ++ if (out.error) ++ return TPM_RC_FAILURE; ++ ++ return TPM_RC_SUCCESS; ++} ++ ++TPM_RC ++TPM2_Create (TPMI_DH_OBJECT parentHandle, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPM2B_SENSITIVE_CREATE *inSensitive, ++ TPM2B_PUBLIC *inPublic, ++ TPM2B_DATA *outsideInfo, ++ TPML_PCR_SELECTION *creationPCR, ++ TPM2B_PRIVATE *outPrivate, ++ TPM2B_PUBLIC *outPublic, ++ TPM2B_CREATION_DATA *creationData, ++ TPM2B_DIGEST *creationHash, ++ TPMT_TK_CREATION *creationTicket, ++ TPMS_AUTH_RESPONSE *authResponse) ++{ ++ struct grub_tpm2_buffer in; ++ struct grub_tpm2_buffer out; ++ TPM2B_PUBLIC outPublicTmp; ++ TPM2B_PRIVATE outPrivateTmp; ++ TPM2B_CREATION_DATA creationDataTmp; ++ TPM2B_DIGEST creationHashTmp; ++ TPMT_TK_CREATION creationTicketTmp; ++ TPMS_AUTH_RESPONSE authResponseTmp; ++ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS:TPM_ST_NO_SESSIONS; ++ TPM_RC responseCode; ++ TPM_RC rc; ++ grub_uint32_t parameterSize; ++ ++ if (!outPrivate) ++ outPrivate = &outPrivateTmp; ++ if (!outPublic) ++ outPublic = &outPublicTmp; ++ if (!creationData) ++ creationData = &creationDataTmp; ++ if (!creationHash) ++ creationHash = &creationHashTmp; ++ if (!creationTicket) ++ creationTicket = &creationTicketTmp; ++ if (!authResponse) ++ authResponse = &authResponseTmp; ++ ++ grub_memset (outPrivate, 0, sizeof (*outPrivate)); ++ grub_memset (outPublic, 0, sizeof (*outPublic)); ++ grub_memset (creationData, 0, sizeof (*creationData)); ++ grub_memset (creationHash, 0, sizeof (*creationHash)); ++ grub_memset (creationTicket, 0, sizeof (*creationTicket)); ++ grub_memset (authResponse, 0, sizeof (*authResponse)); ++ ++ /* Marshal */ ++ grub_tpm2_buffer_init (&in); ++ grub_tpm2_buffer_pack_u32 (&in, parentHandle); ++ if (authCommand) ++ grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (&in, authCommand); ++ grub_tpm2_mu_TPM2B_SENSITIVE_CREATE_Marshal (&in, inSensitive); ++ grub_tpm2_mu_TPM2B_PUBLIC_Marshal (&in, inPublic); ++ grub_tpm2_mu_TPM2B_Marshal (&in, outsideInfo->size, outsideInfo->buffer); ++ grub_tpm2_mu_TPML_PCR_SELECTION_Marshal (&in, creationPCR); ++ if (in.error) ++ return TPM_RC_FAILURE; ++ ++ /* Submit */ ++ grub_tpm2_buffer_init (&out); ++ rc = grub_tpm2_submit_command (tag, TPM_CC_Create, &responseCode, &in, ++ &out); ++ if (rc != TPM_RC_SUCCESS) ++ return rc; ++ if (responseCode != TPM_RC_SUCCESS) ++ return responseCode; ++ ++ /* Unmarshal*/ ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_buffer_unpack_u32 (&out, ¶meterSize); ++ grub_tpm2_mu_TPM2B_Unmarshal (&out, (TPM2B*)outPrivate); ++ grub_tpm2_mu_TPM2B_PUBLIC_Unmarshal (&out, outPublic); ++ grub_tpm2_mu_TPM2B_Unmarshal (&out, (TPM2B*)creationData); ++ grub_tpm2_mu_TPM2B_Unmarshal (&out, (TPM2B*)creationHash); ++ grub_tpm2_mu_TPMT_TK_CREATION_Unmarshal (&out, creationTicket); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal(&out, authResponse); ++ if (out.error) ++ return TPM_RC_FAILURE; ++ ++ return TPM_RC_SUCCESS; ++} ++ ++TPM_RC ++TPM2_EvictControl (TPMI_RH_PROVISION auth, ++ TPMI_DH_OBJECT objectHandle, ++ TPMI_DH_PERSISTENT persistentHandle, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPMS_AUTH_RESPONSE *authResponse) ++{ ++ struct grub_tpm2_buffer in; ++ struct grub_tpm2_buffer out; ++ TPMS_AUTH_RESPONSE authResponseTmp; ++ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS; ++ TPM_RC responseCode; ++ TPM_RC rc; ++ grub_uint32_t parameterSize; ++ ++ if (!authResponse) ++ authResponse = &authResponseTmp; ++ ++ grub_memset (authResponse, 0, sizeof (*authResponse)); ++ ++ /* Marshal */ ++ grub_tpm2_buffer_init (&in); ++ grub_tpm2_buffer_pack_u32 (&in, auth); ++ grub_tpm2_buffer_pack_u32 (&in, objectHandle); ++ if (authCommand) ++ grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (&in, authCommand); ++ grub_tpm2_buffer_pack_u32 (&in, persistentHandle); ++ if (in.error) ++ return TPM_RC_FAILURE; ++ ++ /* Submit */ ++ grub_tpm2_buffer_init (&out); ++ rc = grub_tpm2_submit_command (tag, TPM_CC_EvictControl, &responseCode, &in, ++ &out); ++ if (rc != TPM_RC_SUCCESS) ++ return rc; ++ if (responseCode != TPM_RC_SUCCESS) ++ return responseCode; ++ ++ /* Unmarshal*/ ++ if (tag == TPM_ST_SESSIONS) ++ { ++ grub_tpm2_buffer_unpack_u32 (&out, ¶meterSize); ++ grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal(&out, authResponse); ++ } ++ if (out.error) ++ return TPM_RC_FAILURE; ++ ++ return TPM_RC_SUCCESS; ++} +diff --git a/include/grub/tpm2/buffer.h b/include/grub/tpm2/buffer.h +new file mode 100644 +index 0000000000..ad05393add +--- /dev/null ++++ b/include/grub/tpm2/buffer.h +@@ -0,0 +1,65 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * 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 . ++ */ ++ ++#ifndef GRUB_TPM2_BUFFER_HEADER ++#define GRUB_TPM2_BUFFER_HEADER 1 ++ ++#include ++ ++#define GRUB_TPM2_BUFFER_CAPACITY 4096 ++ ++struct grub_tpm2_buffer ++{ ++ grub_uint8_t data[GRUB_TPM2_BUFFER_CAPACITY]; ++ grub_size_t size; ++ grub_size_t offset; ++ grub_size_t cap; ++ int error; ++}; ++typedef struct grub_tpm2_buffer *grub_tpm2_buffer_t; ++ ++void ++grub_tpm2_buffer_init (grub_tpm2_buffer_t buffer); ++ ++void ++grub_tpm2_buffer_pack (grub_tpm2_buffer_t buffer, const void* data, ++ grub_size_t size); ++ ++void ++grub_tpm2_buffer_pack_u8 (grub_tpm2_buffer_t buffer, grub_uint8_t value); ++ ++void ++grub_tpm2_buffer_pack_u16 (grub_tpm2_buffer_t buffer, grub_uint16_t value); ++ ++void ++grub_tpm2_buffer_pack_u32 (grub_tpm2_buffer_t buffer, grub_uint32_t value); ++ ++void ++grub_tpm2_buffer_unpack (grub_tpm2_buffer_t buffer, void* data, ++ grub_size_t size); ++ ++void ++grub_tpm2_buffer_unpack_u8 (grub_tpm2_buffer_t buffer, grub_uint8_t* value); ++ ++void ++grub_tpm2_buffer_unpack_u16 (grub_tpm2_buffer_t buffer, grub_uint16_t* value); ++ ++void ++grub_tpm2_buffer_unpack_u32 (grub_tpm2_buffer_t buffer, grub_uint32_t* value); ++ ++#endif /* ! GRUB_TPM2_BUFFER_HEADER */ +diff --git a/include/grub/tpm2/internal/functions.h b/include/grub/tpm2/internal/functions.h +new file mode 100644 +index 0000000000..a1c71fae51 +--- /dev/null ++++ b/include/grub/tpm2/internal/functions.h +@@ -0,0 +1,117 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * 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 . ++ */ ++ ++#ifndef GRUB_TPM2_INTERNAL_FUNCTIONS_HEADER ++#define GRUB_TPM2_INTERNAL_FUNCTIONS_HEADER 1 ++ ++#include ++ ++TPM_RC ++TPM2_CreatePrimary (TPMI_RH_HIERARCHY primaryHandle, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPM2B_SENSITIVE_CREATE *inSensitive, ++ TPM2B_PUBLIC *inPublic, ++ TPM2B_DATA *outsideInfo, ++ TPML_PCR_SELECTION *creationPCR, ++ TPM_HANDLE *objectHandle, ++ TPM2B_PUBLIC *outPublic, ++ TPM2B_CREATION_DATA *creationData, ++ TPM2B_DIGEST *creationHash, ++ TPMT_TK_CREATION *creationTicket, ++ TPM2B_NAME *name, ++ TPMS_AUTH_RESPONSE *authResponse); ++ ++TPM_RC ++TPM2_StartAuthSession (TPMI_DH_OBJECT tpmKey, ++ TPMI_DH_ENTITY bind, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPM2B_NONCE *nonceCaller, ++ TPM2B_ENCRYPTED_SECRET *encryptedSalt, ++ TPM_SE sessionType, ++ TPMT_SYM_DEF *symmetric, ++ TPMI_ALG_HASH authHash, ++ TPMI_SH_AUTH_SESSION *sessionHandle, ++ TPM2B_NONCE *nonceTpm, ++ TPMS_AUTH_RESPONSE *authResponse); ++ ++TPM_RC ++TPM2_PolicyPCR (TPMI_SH_POLICY policySession, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPM2B_DIGEST *pcrDigest, ++ TPML_PCR_SELECTION *pcrs, ++ TPMS_AUTH_RESPONSE *authResponse); ++ ++TPM_RC ++TPM2_ReadPublic (TPMI_DH_OBJECT objectHandle, ++ const TPMS_AUTH_COMMAND* authCommand, ++ TPM2B_PUBLIC *outPublic); ++ ++TPM_RC ++TPM2_Load (TPMI_DH_OBJECT parent_handle, ++ TPMS_AUTH_COMMAND const *authCommand, ++ TPM2B_PRIVATE *inPrivate, ++ TPM2B_PUBLIC *inPublic, ++ TPM_HANDLE *objectHandle, ++ TPM2B_NAME *name, ++ TPMS_AUTH_RESPONSE *authResponse); ++ ++TPM_RC ++TPM2_Unseal (TPMI_DH_OBJECT item_handle, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPM2B_SENSITIVE_DATA *outData, ++ TPMS_AUTH_RESPONSE *authResponse); ++ ++TPM_RC ++TPM2_FlushContext (TPMI_DH_CONTEXT handle); ++ ++TPM_RC ++TPM2_PCR_Read (const TPMS_AUTH_COMMAND *authCommand, ++ TPML_PCR_SELECTION *pcrSelectionIn, ++ grub_uint32_t *pcrUpdateCounter, ++ TPML_PCR_SELECTION *pcrSelectionOut, ++ TPML_DIGEST *pcrValues, ++ TPMS_AUTH_RESPONSE *authResponse); ++ ++TPM_RC ++TPM2_PolicyGetDigest (TPMI_SH_POLICY policySession, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPM2B_DIGEST *policyDigest, ++ TPMS_AUTH_RESPONSE *authResponse); ++ ++TPM_RC ++TPM2_Create (TPMI_DH_OBJECT parentHandle, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPM2B_SENSITIVE_CREATE *inSensitive, ++ TPM2B_PUBLIC *inPublic, ++ TPM2B_DATA *outsideInfo, ++ TPML_PCR_SELECTION *creationPCR, ++ TPM2B_PRIVATE *outPrivate, ++ TPM2B_PUBLIC *outPublic, ++ TPM2B_CREATION_DATA *creationData, ++ TPM2B_DIGEST *creationHash, ++ TPMT_TK_CREATION *creationTicket, ++ TPMS_AUTH_RESPONSE *authResponse); ++ ++TPM_RC ++TPM2_EvictControl (TPMI_RH_PROVISION auth, ++ TPMI_DH_OBJECT objectHandle, ++ TPMI_DH_PERSISTENT persistentHandle, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPMS_AUTH_RESPONSE *authResponse); ++ ++#endif /* ! GRUB_TPM2_INTERNAL_FUNCTIONS_HEADER */ +diff --git a/include/grub/tpm2/internal/structs.h b/include/grub/tpm2/internal/structs.h +new file mode 100644 +index 0000000000..75bf99ec8a +--- /dev/null ++++ b/include/grub/tpm2/internal/structs.h +@@ -0,0 +1,675 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * 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 . ++ */ ++ ++#ifndef GRUB_TPM2_INTERNAL_STRUCTS_HEADER ++#define GRUB_TPM2_INTERNAL_STRUCTS_HEADER 1 ++ ++#include ++ ++/* TPMS_TAGGED_PROPERTY Structure */ ++struct TPMS_TAGGED_PROPERTY ++{ ++ TPM_PT property; ++ grub_uint32_t value; ++}; ++typedef struct TPMS_TAGGED_PROPERTY TPMS_TAGGED_PROPERTY; ++ ++/* TPML_TAGGED_TPM_PROPERTY Structure */ ++struct TPML_TAGGED_TPM_PROPERTY ++{ ++ grub_uint32_t count; ++ TPMS_TAGGED_PROPERTY tpmProperty[TPM_MAX_TPM_PROPERTIES]; ++}; ++typedef struct TPML_TAGGED_TPM_PROPERTY TPML_TAGGED_TPM_PROPERTY; ++ ++/* TPMU_CAPABILITIES Structure */ ++union TPMU_CAPABILITIES ++{ ++ TPML_TAGGED_TPM_PROPERTY tpmProperties; ++}; ++typedef union TPMU_CAPABILITIES TPMU_CAPABILITIES; ++ ++/* TPMS_CAPABILITY_DATA Structure */ ++struct TPMS_CAPABILITY_DATA ++{ ++ TPM_CAP capability; ++ TPMU_CAPABILITIES data; ++}; ++typedef struct TPMS_CAPABILITY_DATA TPMS_CAPABILITY_DATA; ++ ++/* TPMS_PCR_SELECT Structure */ ++struct TPMS_PCR_SELECT ++{ ++ grub_uint8_t sizeOfSelect; ++ grub_uint8_t pcrSelect[TPM_PCR_SELECT_MAX]; ++}; ++typedef struct TPMS_PCR_SELECT TPMS_PCR_SELECT; ++ ++/* TPMS_PCR_SELECTION Structure */ ++struct TPMS_PCR_SELECTION ++{ ++ TPMI_ALG_HASH hash; ++ grub_uint8_t sizeOfSelect; ++ grub_uint8_t pcrSelect[TPM_PCR_SELECT_MAX]; ++}; ++typedef struct TPMS_PCR_SELECTION TPMS_PCR_SELECTION; ++ ++static inline void TPMS_PCR_SELECTION_SelectPCR(TPMS_PCR_SELECTION* self, grub_uint32_t n) ++{ ++ self->pcrSelect[(n / 8)] |= (1 << (n % 8)); ++} ++ ++/* TPML_PCR_SELECTION Structure */ ++struct TPML_PCR_SELECTION ++{ ++ grub_uint32_t count; ++ TPMS_PCR_SELECTION pcrSelections[TPM_NUM_PCR_BANKS]; ++}; ++typedef struct TPML_PCR_SELECTION TPML_PCR_SELECTION; ++ ++/* TPMU_HA Structure */ ++union TPMU_HA ++{ ++ grub_uint8_t sha1[TPM_SHA1_DIGEST_SIZE]; ++ grub_uint8_t sha256[TPM_SHA256_DIGEST_SIZE]; ++ grub_uint8_t sha384[TPM_SHA384_DIGEST_SIZE]; ++ grub_uint8_t sha512[TPM_SHA512_DIGEST_SIZE]; ++ grub_uint8_t sm3_256[TPM_SM3_256_DIGEST_SIZE]; ++}; ++typedef union TPMU_HA TPMU_HA; ++ ++/* TPM2B Structure */ ++struct TPM2B ++{ ++ grub_uint16_t size; ++ grub_uint8_t buffer[1]; ++}; ++typedef struct TPM2B TPM2B; ++ ++/* TPM2B_DIGEST Structure */ ++struct TPM2B_DIGEST ++{ ++ grub_uint16_t size; ++ grub_uint8_t buffer[sizeof(TPMU_HA)]; ++}; ++typedef struct TPM2B_DIGEST TPM2B_DIGEST; ++ ++/* TPML_DIGEST Structure */ ++struct TPML_DIGEST ++{ ++ grub_uint32_t count; ++ TPM2B_DIGEST digests[8]; ++}; ++typedef struct TPML_DIGEST TPML_DIGEST; ++ ++/* TPM2B_NONCE Type */ ++typedef TPM2B_DIGEST TPM2B_NONCE; ++ ++/* TPMA_SESSION Structure */ ++struct TPMA_SESSION ++{ ++ unsigned int continueSession:1; ++ unsigned int auditExclusive:1; ++ unsigned int auditReset:1; ++ unsigned int reserved1:2; ++ unsigned int decrypt:1; ++ unsigned int encrypt:1; ++ unsigned int audit:1; ++ unsigned int reserved:24; ++}; ++typedef struct TPMA_SESSION TPMA_SESSION; ++ ++/* TPM2B_AUTH Type */ ++typedef TPM2B_DIGEST TPM2B_AUTH; ++ ++/* TPMS_AUTH_COMMAND Structure */ ++struct TPMS_AUTH_COMMAND ++{ ++ TPMI_SH_AUTH_SESSION sessionHandle; ++ TPM2B_NONCE nonce; ++ TPMA_SESSION sessionAttributes; ++ TPM2B_AUTH hmac; ++}; ++typedef struct TPMS_AUTH_COMMAND TPMS_AUTH_COMMAND; ++ ++/* TPMS_AUTH_RESPONSE Structure */ ++struct TPMS_AUTH_RESPONSE ++{ ++ TPM2B_NONCE nonce; ++ TPMA_SESSION sessionAttributes; ++ TPM2B_AUTH hmac; ++}; ++typedef struct TPMS_AUTH_RESPONSE TPMS_AUTH_RESPONSE; ++ ++/* TPM2B_SENSITIVE_DATA Structure */ ++struct TPM2B_SENSITIVE_DATA ++{ ++ grub_uint16_t size; ++ grub_uint8_t buffer[TPM_MAX_SYM_DATA]; ++}; ++typedef struct TPM2B_SENSITIVE_DATA TPM2B_SENSITIVE_DATA; ++ ++/* TPMS_SENSITIVE_CREATE Structure */ ++struct TPMS_SENSITIVE_CREATE ++{ ++ TPM2B_AUTH userAuth; ++ TPM2B_SENSITIVE_DATA data; ++}; ++typedef struct TPMS_SENSITIVE_CREATE TPMS_SENSITIVE_CREATE; ++ ++/* TPM2B_SENSITIVE_CREATE Structure */ ++struct TPM2B_SENSITIVE_CREATE ++{ ++ grub_uint16_t size; ++ TPMS_SENSITIVE_CREATE sensitive; ++}; ++typedef struct TPM2B_SENSITIVE_CREATE TPM2B_SENSITIVE_CREATE; ++ ++/* TPMA_OBJECT Structure */ ++struct TPMA_OBJECT ++{ ++ unsigned int reserved1:1; ++ unsigned int fixedTPM:1; ++ unsigned int stClear:1; ++ unsigned int reserved2:1; ++ unsigned int fixedParent:1; ++ unsigned int sensitiveDataOrigin:1; ++ unsigned int userWithAuth:1; ++ unsigned int adminWithPolicy:1; ++ unsigned int reserved3:2; ++ unsigned int noDA:1; ++ unsigned int encryptedDuplication:1; ++ unsigned int reserved4:4; ++ unsigned int restricted:1; ++ unsigned int decrypt:1; ++ unsigned int sign:1; ++ unsigned int reserved5:13; ++}; ++typedef struct TPMA_OBJECT TPMA_OBJECT; ++ ++/* TPMS_SCHEME_HASH Structure */ ++struct TPMS_SCHEME_HASH ++{ ++ TPMI_ALG_HASH hashAlg; ++}; ++typedef struct TPMS_SCHEME_HASH TPMS_SCHEME_HASH; ++ ++/* TPMS_SCHEME_HASH Types */ ++typedef TPMS_SCHEME_HASH TPMS_KEY_SCHEME_ECDH; ++typedef TPMS_SCHEME_HASH TPMS_KEY_SCHEME_ECMQV; ++typedef TPMS_SCHEME_HASH TPMS_SIG_SCHEME_RSASSA; ++typedef TPMS_SCHEME_HASH TPMS_SIG_SCHEME_RSAPSS; ++typedef TPMS_SCHEME_HASH TPMS_SIG_SCHEME_ECDSA; ++typedef TPMS_SCHEME_HASH TPMS_SIG_SCHEME_ECDAA; ++typedef TPMS_SCHEME_HASH TPMS_SIG_SCHEME_SM2; ++typedef TPMS_SCHEME_HASH TPMS_SIG_SCHEME_ECSCHNORR; ++typedef TPMS_SCHEME_HASH TPMS_ENC_SCHEME_RSAES; ++typedef TPMS_SCHEME_HASH TPMS_ENC_SCHEME_OAEP; ++typedef TPMS_SCHEME_HASH TPMS_SCHEME_KDF2; ++typedef TPMS_SCHEME_HASH TPMS_SCHEME_MGF1; ++typedef TPMS_SCHEME_HASH TPMS_SCHEME_KDF1_SP800_56A; ++typedef TPMS_SCHEME_HASH TPMS_SCHEME_KDF2; ++typedef TPMS_SCHEME_HASH TPMS_SCHEME_KDF1_SP800_108; ++ ++/* TPMS_SCHEME_HMAC Type */ ++typedef TPMS_SCHEME_HASH TPMS_SCHEME_HMAC; ++ ++/* TPMS_SCHEME_XOR Structure */ ++struct TPMS_SCHEME_XOR ++{ ++ TPMI_ALG_HASH hashAlg; ++ TPMI_ALG_KDF kdf; ++}; ++typedef struct TPMS_SCHEME_XOR TPMS_SCHEME_XOR; ++ ++/* TPMU_SCHEME_KEYEDHASH Union */ ++union TPMU_SCHEME_KEYEDHASH ++{ ++ TPMS_SCHEME_HMAC hmac; ++ TPMS_SCHEME_XOR exclusiveOr; ++}; ++typedef union TPMU_SCHEME_KEYEDHASH TPMU_SCHEME_KEYEDHASH; ++ ++/* TPMT_KEYEDHASH_SCHEME Structure */ ++struct TPMT_KEYEDHASH_SCHEME ++{ ++ TPMI_ALG_KEYEDHASH_SCHEME scheme; ++ TPMU_SCHEME_KEYEDHASH details; ++}; ++typedef struct TPMT_KEYEDHASH_SCHEME TPMT_KEYEDHASH_SCHEME; ++ ++/* TPMS_KEYEDHASH_PARMS Structure */ ++struct TPMS_KEYEDHASH_PARMS ++{ ++ TPMT_KEYEDHASH_SCHEME scheme; ++}; ++typedef struct TPMS_KEYEDHASH_PARMS TPMS_KEYEDHASH_PARMS; ++ ++/* TPMU_SYM_KEY_BITS Union */ ++union TPMU_SYM_KEY_BITS ++{ ++ TPM_KEY_BITS aes; ++ TPM_KEY_BITS exclusiveOr; ++ TPM_KEY_BITS sm4; ++ TPM_KEY_BITS camellia; ++}; ++typedef union TPMU_SYM_KEY_BITS TPMU_SYM_KEY_BITS; ++ ++/* TPMU_SYM_MODE Union */ ++union TPMU_SYM_MODE ++{ ++ TPMI_ALG_SYM_MODE aes; ++ TPMI_ALG_SYM_MODE sm4; ++ TPMI_ALG_SYM_MODE camellia; ++ TPMI_ALG_SYM_MODE sym; ++}; ++typedef union TPMU_SYM_MODE TPMU_SYM_MODE; ++ ++/* TPMT_SYM_DEF_OBJECT Structure */ ++struct TPMT_SYM_DEF_OBJECT ++{ ++ TPMI_ALG_SYM_OBJECT algorithm; ++ TPMU_SYM_KEY_BITS keyBits; ++ TPMU_SYM_MODE mode; ++}; ++typedef struct TPMT_SYM_DEF_OBJECT TPMT_SYM_DEF_OBJECT; ++ ++/* TPMS_SYMCIPHER_PARMS Structure */ ++struct TPMS_SYMCIPHER_PARMS ++{ ++ TPMT_SYM_DEF_OBJECT sym; ++}; ++typedef struct TPMS_SYMCIPHER_PARMS TPMS_SYMCIPHER_PARMS; ++ ++/* TPMU_ASYM_SCHEME Union */ ++union TPMU_ASYM_SCHEME ++{ ++ TPMS_KEY_SCHEME_ECDH ecdh; ++ TPMS_KEY_SCHEME_ECMQV ecmqv; ++ TPMS_SIG_SCHEME_RSASSA rsassa; ++ TPMS_SIG_SCHEME_RSAPSS rsapss; ++ TPMS_SIG_SCHEME_ECDSA ecdsa; ++ TPMS_SIG_SCHEME_ECDAA ecdaa; ++ TPMS_SIG_SCHEME_SM2 sm2; ++ TPMS_SIG_SCHEME_ECSCHNORR ecschnorr; ++ TPMS_ENC_SCHEME_RSAES rsaes; ++ TPMS_ENC_SCHEME_OAEP oaep; ++ TPMS_SCHEME_HASH anySig; ++ unsigned char padding[4]; ++}; ++typedef union TPMU_ASYM_SCHEME TPMU_ASYM_SCHEME; ++ ++/* TPMT_RSA_SCHEME Structure */ ++struct TPMT_RSA_SCHEME ++{ ++ TPMI_ALG_RSA_SCHEME scheme; ++ TPMU_ASYM_SCHEME details; ++}; ++typedef struct TPMT_RSA_SCHEME TPMT_RSA_SCHEME; ++ ++/* TPMS_RSA_PARMS Structure */ ++struct TPMS_RSA_PARMS ++{ ++ TPMT_SYM_DEF_OBJECT symmetric; ++ TPMT_RSA_SCHEME scheme; ++ TPM_KEY_BITS keyBits; ++ grub_uint32_t exponent; ++}; ++typedef struct TPMS_RSA_PARMS TPMS_RSA_PARMS; ++ ++/* TPMT_ECC_SCHEME Structure */ ++struct TPMT_ECC_SCHEME ++{ ++ TPMI_ALG_ECC_SCHEME scheme; ++ TPMU_ASYM_SCHEME details; ++}; ++typedef struct TPMT_ECC_SCHEME TPMT_ECC_SCHEME; ++ ++/* TPMU_KDF_SCHEME Union */ ++union TPMU_KDF_SCHEME ++{ ++ TPMS_SCHEME_MGF1 mgf1; ++ TPMS_SCHEME_KDF1_SP800_56A kdf1_sp800_56a; ++ TPMS_SCHEME_KDF2 kdf2; ++ TPMS_SCHEME_KDF1_SP800_108 kdf1_sp800_108; ++}; ++typedef union TPMU_KDF_SCHEME TPMU_KDF_SCHEME; ++ ++/* TPMT_KDF_SCHEME Structure */ ++struct TPMT_KDF_SCHEME ++{ ++ TPMI_ALG_KDF scheme; ++ TPMU_KDF_SCHEME details; ++}; ++typedef struct TPMT_KDF_SCHEME TPMT_KDF_SCHEME; ++ ++/* TPMS_ECC_PARMS Structure */ ++struct TPMS_ECC_PARMS ++{ ++ TPMT_SYM_DEF_OBJECT symmetric; ++ TPMT_ECC_SCHEME scheme; ++ TPMI_ECC_CURVE curveID; ++ TPMT_KDF_SCHEME kdf; ++}; ++typedef struct TPMS_ECC_PARMS TPMS_ECC_PARMS; ++ ++/* TPMT_ASYM_SCHEME Structure */ ++struct TPMT_ASYM_SCHEME ++{ ++ TPMI_ALG_ASYM_SCHEME scheme; ++ TPMU_ASYM_SCHEME details; ++}; ++typedef struct TPMT_ASYM_SCHEME TPMT_ASYM_SCHEME; ++ ++/* TPMS_ASYM_PARMS Structure */ ++struct TPMS_ASYM_PARMS ++{ ++ TPMT_SYM_DEF_OBJECT symmetric; ++ TPMT_ASYM_SCHEME scheme; ++}; ++typedef struct TPMS_ASYM_PARMS TPMS_ASYM_PARMS; ++ ++/* TPMU_PUBLIC_PARMS Union */ ++union TPMU_PUBLIC_PARMS ++{ ++ TPMS_KEYEDHASH_PARMS keyedHashDetail; ++ TPMS_SYMCIPHER_PARMS symDetail; ++ TPMS_RSA_PARMS rsaDetail; ++ TPMS_ECC_PARMS eccDetail; ++ TPMS_ASYM_PARMS asymDetail; ++}; ++typedef union TPMU_PUBLIC_PARMS TPMU_PUBLIC_PARMS; ++ ++/* TPM2B_PUBLIC_KEY_RSA Structure */ ++struct TPM2B_PUBLIC_KEY_RSA ++{ ++ grub_uint16_t size; ++ grub_uint8_t buffer[TPM_MAX_RSA_KEY_BYTES]; ++}; ++typedef struct TPM2B_PUBLIC_KEY_RSA TPM2B_PUBLIC_KEY_RSA; ++ ++/* TPM2B_ECC_PARAMETER Structure */ ++struct TPM2B_ECC_PARAMETER ++{ ++ grub_uint16_t size; ++ grub_uint8_t buffer[TPM_MAX_ECC_KEY_BYTES]; ++}; ++typedef struct TPM2B_ECC_PARAMETER TPM2B_ECC_PARAMETER; ++ ++/* TPMS_ECC_POINT Structure */ ++struct TPMS_ECC_POINT ++{ ++ TPM2B_ECC_PARAMETER x; ++ TPM2B_ECC_PARAMETER y; ++}; ++typedef struct TPMS_ECC_POINT TPMS_ECC_POINT; ++ ++/* TPMU_ENCRYPTED_SECRET Union */ ++union TPMU_ENCRYPTED_SECRET ++{ ++ grub_uint8_t ecc[sizeof(TPMS_ECC_POINT)]; ++ grub_uint8_t rsa[TPM_MAX_RSA_KEY_BYTES]; ++ grub_uint8_t symmetric[sizeof(TPM2B_DIGEST)]; ++ grub_uint8_t keyedHash[sizeof(TPM2B_DIGEST)]; ++}; ++typedef union TPMU_ENCRYPTED_SECRET TPMU_ENCRYPTED_SECRET; ++ ++/* TPM2B_ENCRYPTED_SECRET Structure */ ++struct TPM2B_ENCRYPTED_SECRET ++{ ++ grub_uint16_t size; ++ grub_uint8_t secret[sizeof(TPMU_ENCRYPTED_SECRET)]; ++}; ++typedef struct TPM2B_ENCRYPTED_SECRET TPM2B_ENCRYPTED_SECRET; ++ ++/* TPMU_PUBLIC_ID Union */ ++union TPMU_PUBLIC_ID ++{ ++ TPM2B_DIGEST keyedHash; ++ TPM2B_DIGEST sym; ++ TPM2B_PUBLIC_KEY_RSA rsa; ++ TPMS_ECC_POINT ecc; ++}; ++typedef union TPMU_PUBLIC_ID TPMU_PUBLIC_ID; ++ ++/* TPMT_PUBLIC Structure */ ++struct TPMT_PUBLIC ++{ ++ TPMI_ALG_PUBLIC type; ++ TPMI_ALG_HASH nameAlg; ++ TPMA_OBJECT objectAttributes; ++ TPM2B_DIGEST authPolicy; ++ TPMU_PUBLIC_PARMS parameters; ++ TPMU_PUBLIC_ID unique; ++}; ++typedef struct TPMT_PUBLIC TPMT_PUBLIC; ++ ++/* TPM2B_PUBLIC Structure */ ++struct TPM2B_PUBLIC ++{ ++ grub_uint16_t size; ++ TPMT_PUBLIC publicArea; ++}; ++typedef struct TPM2B_PUBLIC TPM2B_PUBLIC; ++ ++/* TPMT_HA Structure */ ++struct TPMT_HA ++{ ++ TPMI_ALG_HASH hashAlg; ++ TPMU_HA digest; ++}; ++typedef struct TPMT_HA TPMT_HA; ++ ++/* TPM2B_DATA Structure */ ++struct TPM2B_DATA ++{ ++ grub_uint16_t size; ++ grub_uint8_t buffer[sizeof(TPMT_HA)]; ++}; ++typedef struct TPM2B_DATA TPM2B_DATA; ++ ++/* TPMA_LOCALITY Structure */ ++struct TPMA_LOCALITY ++{ ++ unsigned char TPM_LOC_ZERO:1; ++ unsigned char TPM_LOC_ONE:1; ++ unsigned char TPM_LOC_TWO:1; ++ unsigned char TPM_LOC_THREE:1; ++ unsigned char TPM_LOC_FOUR:1; ++ unsigned char Extended:3; ++}; ++typedef struct TPMA_LOCALITY TPMA_LOCALITY; ++ ++/* TPMU_NAME Union */ ++union TPMU_NAME ++{ ++ TPMT_HA digest; ++ TPM_HANDLE handle; ++}; ++typedef union TPMU_NAME TPMU_NAME; ++ ++/* TPM2B_NAME Structure */ ++struct TPM2B_NAME ++{ ++ grub_uint16_t size; ++ grub_uint8_t name[sizeof(TPMU_NAME)]; ++}; ++typedef struct TPM2B_NAME TPM2B_NAME; ++ ++/* TPMS_CREATION_DATA Structure */ ++struct TPMS_CREATION_DATA ++{ ++ TPML_PCR_SELECTION pcrSelect; ++ TPM2B_DIGEST pcrDigest; ++ TPMA_LOCALITY locality; ++ TPM_ALG_ID parentNameAlg; ++ TPM2B_NAME parentName; ++ TPM2B_NAME parentQualifiedName; ++ TPM2B_DATA outsideInfo; ++}; ++typedef struct TPMS_CREATION_DATA TPMS_CREATION_DATA; ++ ++/* TPM2B_CREATION_DATA Structure */ ++struct TPM2B_CREATION_DATA ++{ ++ grub_uint16_t size; ++ TPMS_CREATION_DATA creationData; ++}; ++typedef struct TPM2B_CREATION_DATA TPM2B_CREATION_DATA; ++ ++/* TPMT_SYM_DEF Structure */ ++struct TPMT_SYM_DEF ++{ ++ TPMI_ALG_SYM algorithm; ++ TPMU_SYM_KEY_BITS keyBits; ++ TPMU_SYM_MODE mode; ++}; ++typedef struct TPMT_SYM_DEF TPMT_SYM_DEF; ++ ++/* TPM2B_MAX_BUFFER Structure */ ++struct TPM2B_MAX_BUFFER ++{ ++ grub_uint16_t size; ++ grub_uint8_t buffer[TPM_MAX_DIGEST_BUFFER]; ++}; ++typedef struct TPM2B_MAX_BUFFER TPM2B_MAX_BUFFER; ++ ++/* TPMT_TK_HASHCHECK Structure */ ++struct TPMT_TK_HASHCHECK ++{ ++ TPM_ST tag; ++ TPMI_RH_HIERARCHY hierarchy; ++ TPM2B_DIGEST digest; ++}; ++typedef struct TPMT_TK_HASHCHECK TPMT_TK_HASHCHECK; ++ ++/* TPM2B_SYM_KEY Structure */ ++struct TPM2B_SYM_KEY ++{ ++ grub_uint16_t size; ++ grub_uint8_t buffer[TPM_MAX_SYM_KEY_BYTES]; ++}; ++typedef struct TPM2B_SYM_KEY TPM2B_SYM_KEY; ++ ++/* TPM2B_PRIVATE_KEY_RSA Structure */ ++struct TPM2B_PRIVATE_KEY_RSA ++{ ++ grub_uint16_t size; ++ grub_uint8_t buffer[TPM_MAX_RSA_KEY_BYTES/2]; ++}; ++typedef struct TPM2B_PRIVATE_KEY_RSA TPM2B_PRIVATE_KEY_RSA; ++ ++/* TPM2B_PRIVATE_VENDOR_SPECIFIC Structure */ ++struct TPM2B_PRIVATE_VENDOR_SPECIFIC ++{ ++ grub_uint16_t size; ++ grub_uint8_t buffer[TPM_PRIVATE_VENDOR_SPECIFIC_BYTES]; ++}; ++typedef struct TPM2B_PRIVATE_VENDOR_SPECIFIC TPM2B_PRIVATE_VENDOR_SPECIFIC; ++ ++/* TPM2B_PRIVATE_VENDOR_SPECIFIC Union */ ++union TPMU_SENSITIVE_COMPOSITE ++{ ++ TPM2B_PRIVATE_KEY_RSA rsa; ++ TPM2B_ECC_PARAMETER ecc; ++ TPM2B_SENSITIVE_DATA bits; ++ TPM2B_SYM_KEY sym; ++ TPM2B_PRIVATE_VENDOR_SPECIFIC any; ++}; ++typedef union TPMU_SENSITIVE_COMPOSITE TPMU_SENSITIVE_COMPOSITE; ++ ++/* TPMT_SENSITIVE Structure */ ++struct TPMT_SENSITIVE ++{ ++ TPMI_ALG_PUBLIC sensitiveType; ++ TPM2B_AUTH authValue; ++ TPM2B_DIGEST seedValue; ++ TPMU_SENSITIVE_COMPOSITE sensitive; ++}; ++typedef struct TPMT_SENSITIVE TPMT_SENSITIVE; ++ ++/* TPM2B_SENSITIVE Structure */ ++struct TPM2B_SENSITIVE ++{ ++ grub_uint16_t size; ++ TPMT_SENSITIVE sensitiveArea; ++}; ++typedef struct TPM2B_SENSITIVE TPM2B_SENSITIVE; ++ ++/* _PRIVATE Structure */ ++struct _PRIVATE ++{ ++ TPM2B_DIGEST integrityOuter; ++ TPM2B_DIGEST integrityInner; ++ TPM2B_SENSITIVE sensitive; ++}; ++typedef struct _PRIVATE _PRIVATE; ++ ++/* TPM2B_PRIVATE Structure */ ++struct TPM2B_PRIVATE ++{ ++ grub_uint16_t size; ++ grub_uint8_t buffer[sizeof(_PRIVATE)]; ++}; ++typedef struct TPM2B_PRIVATE TPM2B_PRIVATE; ++ ++/* TPML_DIGEST_VALUES Structure */ ++struct TPML_DIGEST_VALUES ++{ ++ grub_uint16_t count; ++ TPMT_HA digests[TPM_NUM_PCR_BANKS]; ++}; ++typedef struct TPML_DIGEST_VALUES TPML_DIGEST_VALUES; ++ ++/* TPM2B_MAX_NV_BUFFER Structure */ ++struct TPM2B_MAX_NV_BUFFER ++{ ++ grub_uint16_t size; ++ grub_uint8_t buffer[TPM_MAX_NV_BUFFER_SIZE]; ++}; ++typedef struct TPM2B_MAX_NV_BUFFER TPM2B_MAX_NV_BUFFER; ++ ++/* TPMS_NV_PUBLIC Structure */ ++struct TPMS_NV_PUBLIC ++{ ++ TPMI_RH_NV_INDEX nvIndex; ++ TPMI_ALG_HASH nameAlg; ++ TPMA_NV attributes; ++ TPM2B_DIGEST authPolicy; ++ grub_uint16_t dataSize; ++}; ++typedef struct TPMS_NV_PUBLIC TPMS_NV_PUBLIC; ++ ++/* TPM2B_NV_PUBLIC Structure */ ++struct TPM2B_NV_PUBLIC ++{ ++ grub_uint16_t size; ++ TPMS_NV_PUBLIC nvPublic; ++}; ++typedef struct TPM2B_NV_PUBLIC TPM2B_NV_PUBLIC; ++ ++/* TPMT_TK_CREATION Structure */ ++struct TPMT_TK_CREATION ++{ ++ TPM_ST tag; ++ TPMI_RH_HIERARCHY hierarchy; ++ TPM2B_DIGEST digest; ++}; ++typedef struct TPMT_TK_CREATION TPMT_TK_CREATION; ++ ++#endif /* ! GRUB_TPM2_INTERNAL_STRUCTS_HEADER */ +diff --git a/include/grub/tpm2/internal/types.h b/include/grub/tpm2/internal/types.h +new file mode 100644 +index 0000000000..9714f75d4f +--- /dev/null ++++ b/include/grub/tpm2/internal/types.h +@@ -0,0 +1,372 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * 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 . ++ */ ++ ++#ifndef GRUB_TPM2_INTERNAL_TYPES_HEADER ++#define GRUB_TPM2_INTERNAL_TYPES_HEADER 1 ++ ++#include ++ ++/* TPM2_RC Constants */ ++typedef grub_uint32_t TPM_RC; ++ ++#define TPM_RC_1 ((TPM_RC) 0x100) ++#define TPM_RC_2 ((TPM_RC) 0x200) ++#define TPM_RC_3 ((TPM_RC) 0x300) ++#define TPM_RC_4 ((TPM_RC) 0x400) ++#define TPM_RC_5 ((TPM_RC) 0x500) ++#define TPM_RC_6 ((TPM_RC) 0x600) ++#define TPM_RC_7 ((TPM_RC) 0x700) ++#define TPM_RC_8 ((TPM_RC) 0x800) ++#define TPM_RC_9 ((TPM_RC) 0x900) ++#define TPM_RC_A ((TPM_RC) 0xA00) ++#define TPM_RC_ASYMMETRIC ((TPM_RC) 0x081) ++#define TPM_RC_ATTRIBUTES ((TPM_RC) 0x082) ++#define TPM_RC_AUTH_CONTEXT ((TPM_RC) 0x145) ++#define TPM_RC_AUTH_FAIL ((TPM_RC) 0x08E) ++#define TPM_RC_AUTH_MISSING ((TPM_RC) 0x125) ++#define TPM_RC_AUTHSIZE ((TPM_RC) 0x144) ++#define TPM_RC_AUTH_TYPE ((TPM_RC) 0x124) ++#define TPM_RC_AUTH_UNAVAILABLE ((TPM_RC) 0x12F) ++#define TPM_RC_B ((TPM_RC) 0xB00) ++#define TPM_RC_BAD_AUTH ((TPM_RC) 0x0A2) ++#define TPM_RC_BAD_CONTEXT ((TPM_RC) 0x150) ++#define TPM_RC_BAD_TAG ((TPM_RC) 0x01E) ++#define TPM_RC_BINDING ((TPM_RC) 0x0A5) ++#define TPM_RC_C ((TPM_RC) 0xC00) ++#define TPM_RC_CANCELED ((TPM_RC) 0x909) ++#define TPM_RC_COMMAND_CODE ((TPM_RC) 0x143) ++#define TPM_RC_COMMAND_SIZE ((TPM_RC) 0x142) ++#define TPM_RC_CONTEXT_GAP ((TPM_RC) 0x901) ++#define TPM_RC_CPHASH ((TPM_RC) 0x151) ++#define TPM_RC_CURVE ((TPM_RC) 0x0A6) ++#define TPM_RC_D ((TPM_RC) 0xD00) ++#define TPM_RC_DISABLED ((TPM_RC) 0x120) ++#define TPM_RC_E ((TPM_RC) 0xE00) ++#define TPM_RC_ECC_POINT ((TPM_RC) 0x0A7) ++#define TPM_RC_EXCLUSIVE ((TPM_RC) 0x121) ++#define TPM_RC_EXPIRED ((TPM_RC) 0x0A3) ++#define TPM_RC_F ((TPM_RC) 0xF00) ++#define TPM_RC_FAILURE ((TPM_RC) 0x101) ++#define TPM_RC_H ((TPM_RC) 0x000) ++#define TPM_RC_HANDLE ((TPM_RC) 0x08B) ++#define TPM_RC_HASH ((TPM_RC) 0x083) ++#define TPM_RC_HIERARCHY ((TPM_RC) 0x085) ++#define TPM_RC_HMAC ((TPM_RC) 0x119) ++#define TPM_RC_INITIALIZE ((TPM_RC) 0x100) ++#define TPM_RC_INSUFFICIENT ((TPM_RC) 0x09A) ++#define TPM_RC_INTEGRITY ((TPM_RC) 0x09F) ++#define TPM_RC_KDF ((TPM_RC) 0x08C) ++#define TPM_RC_KEY ((TPM_RC) 0x09C) ++#define TPM_RC_KEY_SIZE ((TPM_RC) 0x087) ++#define TPM_RC_LOCALITY ((TPM_RC) 0x907) ++#define TPM_RC_LOCKOUT ((TPM_RC) 0x921) ++#define TPM_RC_MEMORY ((TPM_RC) 0x904) ++#define TPM_RC_MGF ((TPM_RC) 0x088) ++#define TPM_RC_MODE ((TPM_RC) 0x089) ++#define TPM_RC_NEEDS_TEST ((TPM_RC) 0x153) ++#define TPM_RC_N_MASK ((TPM_RC) 0xF00) ++#define TPM_RC_NONCE ((TPM_RC) 0x08F) ++#define TPM_RC_NO_RESULT ((TPM_RC) 0x154) ++#define TPM_RC_NOT_USED ((TPM_RC) 0x97F) ++#define TPM_RC_NV_AUTHORIZATION ((TPM_RC) 0x149) ++#define TPM_RC_NV_DEFINED ((TPM_RC) 0x14C) ++#define TPM_RC_NV_LOCKED ((TPM_RC) 0x148) ++#define TPM_RC_NV_RANGE ((TPM_RC) 0x146) ++#define TPM_RC_NV_RATE ((TPM_RC) 0x920) ++#define TPM_RC_NV_SIZE ((TPM_RC) 0x147) ++#define TPM_RC_NV_SPACE ((TPM_RC) 0x14B) ++#define TPM_RC_NV_UNAVAILABLE ((TPM_RC) 0x923) ++#define TPM_RC_NV_UNINITIALIZED ((TPM_RC) 0x14A) ++#define TPM_RC_OBJECT_HANDLES ((TPM_RC) 0x906) ++#define TPM_RC_OBJECT_MEMORY ((TPM_RC) 0x902) ++#define TPM_RC_P ((TPM_RC) 0x040) ++#define TPM_RC_PARENT ((TPM_RC) 0x152) ++#define TPM_RC_PCR ((TPM_RC) 0x127) ++#define TPM_RC_PCR_CHANGED ((TPM_RC) 0x128) ++#define TPM_RC_POLICY ((TPM_RC) 0x126) ++#define TPM_RC_POLICY_CC ((TPM_RC) 0x0A4) ++#define TPM_RC_POLICY_FAIL ((TPM_RC) 0x09D) ++#define TPM_RC_PP ((TPM_RC) 0x090) ++#define TPM_RC_PRIVATE ((TPM_RC) 0x10B) ++#define TPM_RC_RANGE ((TPM_RC) 0x08D) ++#define TPM_RC_REBOOT ((TPM_RC) 0x130) ++#define TPM_RC_REFERENCE_H0 ((TPM_RC) 0x910) ++#define TPM_RC_REFERENCE_H1 ((TPM_RC) 0x911) ++#define TPM_RC_REFERENCE_H2 ((TPM_RC) 0x912) ++#define TPM_RC_REFERENCE_H3 ((TPM_RC) 0x913) ++#define TPM_RC_REFERENCE_H4 ((TPM_RC) 0x914) ++#define TPM_RC_REFERENCE_H5 ((TPM_RC) 0x915) ++#define TPM_RC_REFERENCE_H6 ((TPM_RC) 0x916) ++#define TPM_RC_REFERENCE_S0 ((TPM_RC) 0x918) ++#define TPM_RC_REFERENCE_S1 ((TPM_RC) 0x919) ++#define TPM_RC_REFERENCE_S2 ((TPM_RC) 0x91A) ++#define TPM_RC_REFERENCE_S3 ((TPM_RC) 0x91B) ++#define TPM_RC_REFERENCE_S4 ((TPM_RC) 0x91C) ++#define TPM_RC_REFERENCE_S5 ((TPM_RC) 0x91D) ++#define TPM_RC_REFERENCE_S6 ((TPM_RC) 0x91E) ++#define TPM_RC_RESERVED_BITS ((TPM_RC) 0x0A1) ++#define TPM_RC_RETRY ((TPM_RC) 0x922) ++#define TPM_RC_S ((TPM_RC) 0x800) ++#define TPM_RC_SCHEME ((TPM_RC) 0x092) ++#define TPM_RC_SELECTOR ((TPM_RC) 0x098) ++#define TPM_RC_SENSITIVE ((TPM_RC) 0x155) ++#define TPM_RC_SEQUENCE ((TPM_RC) 0x103) ++#define TPM_RC_SESSION_HANDLES ((TPM_RC) 0x905) ++#define TPM_RC_SESSION_MEMORY ((TPM_RC) 0x903) ++#define TPM_RC_SIGNATURE ((TPM_RC) 0x09B) ++#define TPM_RC_SIZE ((TPM_RC) 0x095) ++#define TPM_RC_SUCCESS ((TPM_RC) 0x000) ++#define TPM_RC_SYMMETRIC ((TPM_RC) 0x096) ++#define TPM_RC_TAG ((TPM_RC) 0x097) ++#define TPM_RC_TESTING ((TPM_RC) 0x90A) ++#define TPM_RC_TICKET ((TPM_RC) 0x0A0) ++#define TPM_RC_TOO_MANY_CONTEXTS ((TPM_RC) 0x12E) ++#define TPM_RC_TYPE ((TPM_RC) 0x08A) ++#define TPM_RC_UNBALANCED ((TPM_RC) 0x131) ++#define TPM_RC_UPGRADE ((TPM_RC) 0x12D) ++#define TPM_RC_VALUE ((TPM_RC) 0x084) ++#define TPM_RC_YIELDED ((TPM_RC) 0x908) ++ ++/* TPMA_NV Constants */ ++typedef grub_uint32_t TPMA_NV; ++ ++#define TPMA_NV_PPWRITE ((TPMA_NV) 0x00000001) ++#define TPMA_NV_OWNERWRITE ((TPMA_NV) 0x00000002) ++#define TPMA_NV_AUTHWRITE ((TPMA_NV) 0x00000004) ++#define TPMA_NV_POLICYWRITE ((TPMA_NV) 0x00000008) ++#define TPMA_NV_TPM2_NT_MASK ((TPMA_NV) 0x000000F0) ++#define TPMA_NV_TPM2_NT_SHIFT (4) ++#define TPMA_NV_RESERVED1_MASK ((TPMA_NV) 0x00000300) ++#define TPMA_NV_POLICY_DELETE ((TPMA_NV) 0x00000400) ++#define TPMA_NV_WRITELOCKED ((TPMA_NV) 0x00000800) ++#define TPMA_NV_WRITEALL ((TPMA_NV) 0x00001000) ++#define TPMA_NV_WRITEDEFINE ((TPMA_NV) 0x00002000) ++#define TPMA_NV_WRITE_STCLEAR ((TPMA_NV) 0x00004000) ++#define TPMA_NV_GLOBALLOCK ((TPMA_NV) 0x00008000) ++#define TPMA_NV_PPREAD ((TPMA_NV) 0x00010000) ++#define TPMA_NV_OWNERREAD ((TPMA_NV) 0x00020000) ++#define TPMA_NV_AUTHREAD ((TPMA_NV) 0x00040000) ++#define TPMA_NV_POLICYREAD ((TPMA_NV) 0x00080000) ++#define TPMA_NV_RESERVED2_MASK ((TPMA_NV) 0x01F00000) ++#define TPMA_NV_NO_DA ((TPMA_NV) 0x02000000) ++#define TPMA_NV_ORDERLY ((TPMA_NV) 0x04000000) ++#define TPMA_NV_CLEAR_STCLEAR ((TPMA_NV) 0x08000000) ++#define TPMA_NV_READLOCKED ((TPMA_NV) 0x10000000) ++#define TPMA_NV_WRITTEN ((TPMA_NV) 0x20000000) ++#define TPMA_NV_PLATFORMCREATE ((TPMA_NV) 0x40000000) ++#define TPMA_NV_READ_STCLEAR ((TPMA_NV) 0x80000000) ++ ++/* TPM_ALG_ID Constants */ ++typedef grub_uint16_t TPM_ALG_ID; ++ ++#define TPM_ALG_ERROR ((TPM_ALG_ID) 0x0000) ++#define TPM_ALG_AES ((TPM_ALG_ID) 0x0006) ++#define TPM_ALG_CAMELLIA ((TPM_ALG_ID) 0x0026) ++#define TPM_ALG_CBC ((TPM_ALG_ID) 0x0042) ++#define TPM_ALG_CFB ((TPM_ALG_ID) 0x0043) ++#define TPM_ALG_ECB ((TPM_ALG_ID) 0x0044) ++#define TPM_ALG_ECC ((TPM_ALG_ID) 0x0023) ++#define TPM_ALG_HMAC ((TPM_ALG_ID) 0x0005) ++#define TPM_ALG_KDF1_SP800_108 ((TPM_ALG_ID) 0x0022) ++#define TPM_ALG_KDF1_SP800_56A ((TPM_ALG_ID) 0x0020) ++#define TPM_ALG_KDF2 ((TPM_ALG_ID) 0x0021) ++#define TPM_ALG_KEYEDHASH ((TPM_ALG_ID) 0x0008) ++#define TPM_ALG_MGF1 ((TPM_ALG_ID) 0x0007) ++#define TPM_ALG_NULL ((TPM_ALG_ID) 0x0010) ++#define TPM_ALG_RSA ((TPM_ALG_ID) 0x0001) ++#define TPM_ALG_SHA1 ((TPM_ALG_ID) 0x0004) ++#define TPM_ALG_SHA256 ((TPM_ALG_ID) 0x000B) ++#define TPM_ALG_SHA384 ((TPM_ALG_ID) 0x000C) ++#define TPM_ALG_SHA512 ((TPM_ALG_ID) 0x000D) ++#define TPM_ALG_SM3_256 ((TPM_ALG_ID) 0x0012) ++#define TPM_ALG_SM4 ((TPM_ALG_ID) 0x0013) ++#define TPM_ALG_SYMCIPHER ((TPM_ALG_ID) 0x0025) ++#define TPM_ALG_XOR ((TPM_ALG_ID) 0x000A) ++ ++/* TPM_CAP Constants */ ++typedef grub_uint32_t TPM_CAP; ++ ++#define TPM_CAP_FIRST ((TPM_CAP) 0x00000000) ++#define TPM_CAP_ALGS ((TPM_CAP) 0x00000000) ++#define TPM_CAP_HANDLES ((TPM_CAP) 0x00000001) ++#define TPM_CAP_COMMANDS ((TPM_CAP) 0x00000002) ++#define TPM_CAP_PP_COMMANDS ((TPM_CAP) 0x00000003) ++#define TPM_CAP_AUDIT_COMMANDS ((TPM_CAP) 0x00000004) ++#define TPM_CAP_PCRS ((TPM_CAP) 0x00000005) ++#define TPM_CAP_TPM_PROPERTIES ((TPM_CAP) 0x00000006) ++#define TPM_CAP_PCR_PROPERTIES ((TPM_CAP) 0x00000007) ++#define TPM_CAP_ECC_CURVES ((TPM_CAP) 0x00000008) ++#define TPM_CAP_LAST ((TPM_CAP) 0x00000008) ++#define TPM_CAP_VENDOR_PROPERTY ((TPM_CAP) 0x00000100) ++ ++/* TPM_PT Constants */ ++typedef grub_uint32_t TPM_PT; ++ ++#define TPM_PT_NONE ((TPM_PT) 0x00000000) ++#define PT_GROUP ((TPM_PT) 0x00000100) ++#define PT_FIXED ((TPM_PT) (PT_GROUP * 1)) ++#define TPM_PT_FAMILY_INDICATOR ((TPM_PT) (PT_FIXED + 0)) ++#define TPM_PT_LEVEL ((TPM_PT) (PT_FIXED + 1)) ++#define TPM_PT_REVISION ((TPM_PT) (PT_FIXED + 2)) ++#define TPM_PT_DAY_OF_YEAR ((TPM_PT) (PT_FIXED + 3)) ++#define TPM_PT_YEAR ((TPM_PT) (PT_FIXED + 4)) ++#define TPM_PT_PCR_COUNT ((TPM_PT) (PT_FIXED + 18)) ++ ++/* TPM_SE Constants */ ++typedef grub_uint8_t TPM_SE; ++ ++#define TPM_SE_HMAC ((TPM_SE) 0x00) ++#define TPM_SE_POLICY ((TPM_SE) 0x01) ++#define TPM_SE_TRIAL ((TPM_SE) 0x03) ++ ++/* TPMI_YES_NO Constants */ ++typedef grub_uint8_t TPMI_YES_NO; ++ ++#define TPM_NO ((TPMI_YES_NO)0) ++#define TPM_YES ((TPMI_YES_NO)1) ++ ++/* TPM_ST Constants */ ++typedef grub_uint16_t TPM_ST; ++typedef TPM_ST TPMI_ST_COMMAND_TAG; ++ ++#define TPM_ST_NO_SESSIONS ((TPMI_ST_COMMAND_TAG) 0x8001) ++#define TPM_ST_SESSIONS ((TPMI_ST_COMMAND_TAG) 0x8002) ++ ++/* TPM_HANDLE Types */ ++typedef grub_uint32_t TPM_HANDLE; ++ ++typedef TPM_HANDLE TPMI_RH_HIERARCHY; ++typedef TPM_HANDLE TPMI_RH_LOCKOUT; ++typedef TPM_HANDLE TPMI_SH_AUTH_SESSION; ++typedef TPM_HANDLE TPMI_DH_CONTEXT; ++typedef TPM_HANDLE TPMI_DH_OBJECT; ++typedef TPM_HANDLE TPMI_DH_ENTITY; ++typedef TPM_HANDLE TPMI_SH_POLICY; ++typedef TPM_HANDLE TPMI_DH_PCR; ++typedef TPM_HANDLE TPMI_RH_NV_AUTH; ++typedef TPM_HANDLE TPMI_RH_NV_INDEX; ++ ++/* TPM_RH Constants */ ++typedef TPM_HANDLE TPM_RH; ++ ++#define TPM_RH_FIRST ((TPM_RH) 0x40000000) ++#define TPM_RH_SRK ((TPM_RH) 0x40000000) ++#define TPM_RH_OWNER ((TPM_RH) 0x40000001) ++#define TPM_RH_REVOKE ((TPM_RH) 0x40000002) ++#define TPM_RH_TRANSPORT ((TPM_RH) 0x40000003) ++#define TPM_RH_OPERATOR ((TPM_RH) 0x40000004) ++#define TPM_RH_ADMIN ((TPM_RH) 0x40000005) ++#define TPM_RH_EK ((TPM_RH) 0x40000006) ++#define TPM_RH_NULL ((TPM_RH) 0x40000007) ++#define TPM_RH_UNASSIGNED ((TPM_RH) 0x40000008) ++#define TPM_RS_PW ((TPM_RH) 0x40000009) ++#define TPM_RH_LOCKOUT ((TPM_RH) 0x4000000A) ++#define TPM_RH_ENDORSEMENT ((TPM_RH) 0x4000000B) ++#define TPM_RH_PLATFORM ((TPM_RH) 0x4000000C) ++#define TPM_RH_PLATFORM_NV ((TPM_RH) 0x4000000D) ++#define TPM_RH_AUTH_00 ((TPM_RH) 0x40000010) ++#define TPM_RH_AUTH_FF ((TPM_RH) 0x4000010F) ++#define TPM_RH_LAST ((TPM_RH) 0x4000010F) ++ ++/* TPM2_ECC_CURVE Constants */ ++typedef grub_uint16_t TPM2_ECC_CURVE; ++ ++#define TPM_ECC_NONE ((TPM_ECC_CURVE) 0x0000) ++#define TPM_ECC_NIST_P192 ((TPM_ECC_CURVE) 0x0001) ++#define TPM_ECC_NIST_P224 ((TPM_ECC_CURVE) 0x0002) ++#define TPM_ECC_NIST_P256 ((TPM_ECC_CURVE) 0x0003) ++#define TPM_ECC_NIST_P384 ((TPM_ECC_CURVE) 0x0004) ++#define TPM_ECC_NIST_P521 ((TPM_ECC_CURVE) 0x0005) ++#define TPM_ECC_BN_P256 ((TPM_ECC_CURVE) 0x0010) ++#define TPM_ECC_BN_P638 ((TPM_ECC_CURVE) 0x0011) ++#define TPM_ECC_SM2_P256 ((TPM_ECC_CURVE) 0x0020) ++ ++/* TPM_CC Constants */ ++typedef grub_uint32_t TPM_CC; ++ ++#define TPM_CC_EvictControl ((TPM_CC) 0x00000120) ++#define TPM_CC_CreatePrimary ((TPM_CC) 0x00000131) ++#define TPM_CC_Create ((TPM_CC) 0x00000153) ++#define TPM_CC_FlushContext ((TPM_CC) 0x00000165) ++#define TPM_CC_ReadPublic ((TPM_CC) 0x00000173) ++#define TPM_CC_StartAuthSession ((TPM_CC) 0x00000176) ++#define TPM_CC_PolicyPCR ((TPM_CC) 0x0000017f) ++#define TPM_CC_NV_Read ((TPM_CC) 0x0000014e) ++#define TPM_CC_NV_ReadPublic ((TPM_CC) 0x00000169) ++#define TPM_CC_GetCapability ((TPM_CC) 0x0000017a) ++#define TPM_CC_PCR_Read ((TPM_CC) 0x0000017e) ++#define TPM_CC_Load ((TPM_CC) 0x00000157) ++#define TPM_CC_Unseal ((TPM_CC) 0x0000015e) ++#define TPM_CC_PolicyGetDigest ((TPM_CC) 0x00000189) ++ ++/* Hash algorithm sizes */ ++#define TPM_SHA1_DIGEST_SIZE 20 ++#define TPM_SHA256_DIGEST_SIZE 32 ++#define TPM_SM3_256_DIGEST_SIZE 32 ++#define TPM_SHA384_DIGEST_SIZE 48 ++#define TPM_SHA512_DIGEST_SIZE 64 ++ ++/* Encryption algorithm sizes */ ++#define TPM_MAX_SYM_BLOCK_SIZE 16 ++#define TPM_MAX_SYM_DATA 256 ++#define TPM_MAX_ECC_KEY_BYTES 128 ++#define TPM_MAX_SYM_KEY_BYTES 32 ++#define TPM_MAX_RSA_KEY_BYTES 512 ++ ++/* Buffer Size Constants */ ++#define TPM_MAX_PCRS 32 ++#define TPM_NUM_PCR_BANKS 16 ++#define TPM_PCR_SELECT_MAX ((TPM_MAX_PCRS + 7) / 8) ++#define TPM_MAX_DIGEST_BUFFER 1024 ++#define TPM_MAX_TPM_PROPERTIES 8 ++#define TPM_MAX_NV_BUFFER_SIZE 2048 ++#define TPM_PRIVATE_VENDOR_SPECIFIC_BYTES 1280 ++ ++/* TPM_GENERATED Constants */ ++typedef grub_uint32_t TPM_GENERATED; ++ ++#define TPM_GENERATED_VALUE ((TPM_GENERATED) 0xff544347) ++ ++/* TPM_ALG_ID Types */ ++typedef TPM_ALG_ID TPMI_ALG_PUBLIC; ++typedef TPM_ALG_ID TPMI_ALG_HASH; ++typedef TPM_ALG_ID TPMI_ALG_KEYEDHASH_SCHEME; ++typedef TPM_ALG_ID TPMI_ALG_KDF; ++typedef TPM_ALG_ID TPMI_ALG_SYM_OBJECT; ++typedef TPM_ALG_ID TPMI_ALG_SYM_MODE; ++typedef TPM_ALG_ID TPMI_ALG_RSA_DECRYPT; ++typedef TPM_ALG_ID TPMI_ALG_ECC_SCHEME; ++typedef TPM_ALG_ID TPMI_ALG_ASYM_SCHEME; ++typedef TPM_ALG_ID TPMI_ALG_RSA_SCHEME; ++typedef TPM_ALG_ID TPMI_ALG_SYM; ++ ++/* TPM_KEY_BITS Type */ ++typedef grub_uint16_t TPM_KEY_BITS; ++ ++/* TPM_ECC_CURVE Types */ ++typedef grub_uint16_t TPM_ECC_CURVE; ++ ++typedef TPM_ECC_CURVE TPMI_ECC_CURVE; ++ ++/* TPMI_RH_PROVISION Type */ ++typedef TPM_HANDLE TPMI_RH_PROVISION; ++ ++/* TPMI_RH_PROVISION Type */ ++typedef TPM_HANDLE TPMI_DH_PERSISTENT; ++ ++#endif /* ! GRUB_TPM2_INTERNAL_TYPES_HEADER */ +diff --git a/include/grub/tpm2/mu.h b/include/grub/tpm2/mu.h +new file mode 100644 +index 0000000000..4f4058f9d6 +--- /dev/null ++++ b/include/grub/tpm2/mu.h +@@ -0,0 +1,292 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * 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 . ++ */ ++ ++#ifndef GRUB_TPM2_MU_HEADER ++#define GRUB_TPM2_MU_HEADER 1 ++ ++#include ++#include ++ ++void ++grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (grub_tpm2_buffer_t buf, ++ const TPMS_AUTH_COMMAND* authCommand); ++ ++void ++grub_tpm2_mu_TPM2B_Marshal (grub_tpm2_buffer_t buf, ++ grub_uint16_t size, ++ const grub_uint8_t* buffer); ++ ++void ++grub_tpm2_mu_TPMU_SYM_KEY_BITS_Marshal (grub_tpm2_buffer_t buf, ++ TPMI_ALG_SYM_OBJECT algorithm, ++ TPMU_SYM_KEY_BITS *p); ++ ++void ++grub_tpm2_mu_TPMU_SYM_MODE_Marshal (grub_tpm2_buffer_t buf, ++ TPMI_ALG_SYM_OBJECT algorithm, ++ TPMU_SYM_MODE *p); ++ ++void ++grub_tpm2_mu_TPMT_SYM_DEF_Marshal (grub_tpm2_buffer_t buf, ++ TPMT_SYM_DEF *p); ++ ++void ++grub_tpm2_mu_TPMS_PCR_SELECTION_Marshal (grub_tpm2_buffer_t buf, ++ const TPMS_PCR_SELECTION* pcrSelection); ++ ++void ++grub_tpm2_mu_TPML_PCR_SELECTION_Marshal (grub_tpm2_buffer_t buf, ++ const TPML_PCR_SELECTION* pcrSelection); ++ ++void ++grub_tpm2_mu_TPMA_OBJECT_Marshal (grub_tpm2_buffer_t buf, ++ const TPMA_OBJECT *p); ++ ++void ++grub_tpm2_mu_TPMS_SCHEME_XOR_Marshal (grub_tpm2_buffer_t buf, ++ TPMS_SCHEME_XOR *p); ++ ++void ++grub_tpm2_mu_TPMS_SCHEME_HMAC_Marshal (grub_tpm2_buffer_t buf, ++ TPMS_SCHEME_HMAC *p); ++ ++void ++grub_tpm2_mu_TPMU_SCHEME_KEYEDHASH_Marshal (grub_tpm2_buffer_t buf, ++ TPMI_ALG_KEYEDHASH_SCHEME scheme, ++ TPMU_SCHEME_KEYEDHASH *p); ++ ++void ++grub_tpm2_mu_TPMT_KEYEDHASH_SCHEME_Marshal (grub_tpm2_buffer_t buf, ++ TPMT_KEYEDHASH_SCHEME *p); ++ ++void ++grub_tpm2_mu_TPMS_KEYEDHASH_PARMS_Marshal (grub_tpm2_buffer_t buf, ++ TPMS_KEYEDHASH_PARMS *p); ++ ++void ++grub_tpm2_mu_TPMT_SYM_DEF_OBJECT_Marshal (grub_tpm2_buffer_t buf, ++ TPMT_SYM_DEF_OBJECT *p); ++ ++void ++grub_tpm2_mu_TPMU_ASYM_SCHEME_Marshal (grub_tpm2_buffer_t buf, ++ TPMI_ALG_RSA_DECRYPT scheme, ++ TPMU_ASYM_SCHEME *p); ++ ++void ++grub_tpm2_mu_TPMT_RSA_SCHEME_Marshal (grub_tpm2_buffer_t buf, ++ TPMT_RSA_SCHEME *p); ++ ++void ++grub_tpm2_mu_TPMS_RSA_PARMS_Marshal (grub_tpm2_buffer_t buf, ++ TPMS_RSA_PARMS *p); ++ ++void ++grub_tpm2_mu_TPMS_SYMCIPHER_PARMS_Marshal (grub_tpm2_buffer_t buf, ++ TPMS_SYMCIPHER_PARMS *p); ++ ++void ++grub_tpm2_mu_TPMT_ECC_SCHEME_Marshal (grub_tpm2_buffer_t buf, ++ TPMT_ECC_SCHEME *p); ++ ++void ++grub_tpm2_mu_TPMU_KDF_SCHEME_Marshal (grub_tpm2_buffer_t buf, ++ TPMI_ALG_KDF scheme, ++ TPMU_KDF_SCHEME *p); ++ ++void ++grub_tpm2_mu_TPMT_KDF_SCHEME_Marshal (grub_tpm2_buffer_t buf, ++ TPMT_KDF_SCHEME *p); ++ ++void ++grub_tpm2_mu_TPMS_ECC_PARMS_Marshal (grub_tpm2_buffer_t buf, ++ TPMS_ECC_PARMS *p); ++ ++void ++grub_tpm2_mu_TPMU_PUBLIC_PARMS_Marshal (grub_tpm2_buffer_t buf, ++ grub_uint32_t type, ++ TPMU_PUBLIC_PARMS *p); ++ ++void ++grub_tpm2_mu_TPMS_ECC_POINT_Marshal (grub_tpm2_buffer_t buf, ++ TPMS_ECC_POINT *p); ++ ++void ++grub_tpm2_mu_TPMU_PUBLIC_ID_Marshal (grub_tpm2_buffer_t buf, ++ TPMI_ALG_PUBLIC type, ++ TPMU_PUBLIC_ID *p); ++ ++void ++grub_tpm2_mu_TPMT_PUBLIC_Marshal (grub_tpm2_buffer_t buf, ++ TPMT_PUBLIC *p); ++ ++void ++grub_tpm2_mu_TPM2B_PUBLIC_Marshal (grub_tpm2_buffer_t buf, ++ TPM2B_PUBLIC *p); ++ ++void ++grub_tpm2_mu_TPMS_SENSITIVE_CREATE_Marshal (grub_tpm2_buffer_t buf, ++ TPMS_SENSITIVE_CREATE *p); ++ ++void ++grub_tpm2_mu_TPM2B_SENSITIVE_CREATE_Marshal (grub_tpm2_buffer_t buf, ++ TPM2B_SENSITIVE_CREATE *sensitiveCreate); ++ ++void ++grub_tpm2_mu_TPM2B_Unmarshal (grub_tpm2_buffer_t buf, ++ TPM2B* p); ++ ++void ++grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMS_AUTH_RESPONSE* p); ++ ++void ++grub_tpm2_mu_TPM2B_DIGEST_Unmarshal (grub_tpm2_buffer_t buf, ++ TPM2B_DIGEST* digest); ++ ++void ++grub_tpm2_mu_TPMA_OBJECT_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMA_OBJECT *p); ++ ++void ++grub_tpm2_mu_TPMS_SCHEME_HMAC_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMS_SCHEME_HMAC *p); ++ ++void ++grub_tpm2_mu_TPMS_SCHEME_XOR_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMS_SCHEME_XOR *p); ++ ++void ++grub_tpm2_mu_TPMU_SCHEME_KEYEDHASH_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMI_ALG_KEYEDHASH_SCHEME scheme, ++ TPMU_SCHEME_KEYEDHASH *p); ++ ++void ++grub_tpm2_mu_TPMT_KEYEDHASH_SCHEME_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMT_KEYEDHASH_SCHEME *p); ++ ++void ++grub_tpm2_mu_TPMS_KEYEDHASH_PARMS_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMS_KEYEDHASH_PARMS *p); ++ ++void ++grub_tpm2_mu_TPMU_SYM_KEY_BITS_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMI_ALG_SYM_OBJECT algorithm, ++ TPMU_SYM_KEY_BITS *p); ++ ++void ++grub_tpm2_mu_TPMU_SYM_MODE_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMI_ALG_SYM_OBJECT algorithm, ++ TPMU_SYM_MODE *p); ++ ++void ++grub_tpm2_mu_TPMT_SYM_DEF_OBJECT_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMT_SYM_DEF_OBJECT *p); ++ ++void ++grub_tpm2_mu_TPMS_SYMCIPHER_PARMS_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMS_SYMCIPHER_PARMS *p); ++ ++void ++grub_tpm2_mu_TPMU_ASYM_SCHEME_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMI_ALG_RSA_DECRYPT scheme, ++ TPMU_ASYM_SCHEME *p); ++ ++void ++grub_tpm2_mu_TPMT_RSA_SCHEME_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMT_RSA_SCHEME *p); ++ ++void ++grub_tpm2_mu_TPMS_RSA_PARMS_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMS_RSA_PARMS *p); ++ ++void ++grub_tpm2_mu_TPMT_ECC_SCHEME_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMT_ECC_SCHEME *p); ++ ++void ++grub_tpm2_mu_TPMU_KDF_SCHEME_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMI_ALG_KDF scheme, ++ TPMU_KDF_SCHEME *p); ++ ++void ++grub_tpm2_mu_TPMT_KDF_SCHEME_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMT_KDF_SCHEME *p); ++ ++void ++grub_tpm2_mu_TPMS_ECC_PARMS_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMS_ECC_PARMS *p); ++ ++void ++grub_tpm2_mu_TPMU_PUBLIC_PARMS_Unmarshal (grub_tpm2_buffer_t buf, ++ grub_uint32_t type, ++ TPMU_PUBLIC_PARMS *p); ++ ++void ++grub_tpm2_mu_TPMS_ECC_POINT_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMS_ECC_POINT *p); ++ ++void ++grub_tpm2_mu_TPMU_PUBLIC_ID_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMI_ALG_PUBLIC type, ++ TPMU_PUBLIC_ID *p); ++ ++void ++grub_tpm2_mu_TPMT_PUBLIC_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMT_PUBLIC *p); ++ ++void ++grub_tpm2_mu_TPM2B_PUBLIC_Unmarshal (grub_tpm2_buffer_t buf, ++ TPM2B_PUBLIC *p); ++ ++void ++grub_tpm2_mu_TPMS_NV_PUBLIC_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMS_NV_PUBLIC *p); ++ ++void ++grub_tpm2_mu_TPM2B_NV_PUBLIC_Unmarshal (grub_tpm2_buffer_t buf, ++ TPM2B_NV_PUBLIC *p); ++ ++void ++grub_tpm2_mu_TPM2B_NAME_Unmarshal (grub_tpm2_buffer_t buf, ++ TPM2B_NAME *n); ++ ++void ++grub_tpm2_mu_TPMS_TAGGED_PROPERTY_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMS_TAGGED_PROPERTY* property); ++ ++void ++grub_tpm2_mu_TPMS_CAPABILITY_DATA_tpmProperties_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMS_CAPABILITY_DATA* capabilityData); ++ ++void ++grub_tpm2_mu_TPMT_TK_CREATION_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMT_TK_CREATION *p); ++ ++void ++grub_tpm2_mu_TPMS_PCR_SELECTION_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMS_PCR_SELECTION* pcrSelection); ++ ++void ++grub_tpm2_mu_TPML_PCR_SELECTION_Unmarshal (grub_tpm2_buffer_t buf, ++ TPML_PCR_SELECTION* pcrSelection); ++ ++void ++grub_tpm2_mu_TPML_DIGEST_Unmarshal (grub_tpm2_buffer_t buf, ++ TPML_DIGEST* digest); ++ ++#endif /* ! GRUB_TPM2_MU_HEADER */ +diff --git a/include/grub/tpm2/tcg2.h b/include/grub/tpm2/tcg2.h +new file mode 100644 +index 0000000000..99f2fdd3b9 +--- /dev/null ++++ b/include/grub/tpm2/tcg2.h +@@ -0,0 +1,34 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * 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 . ++ */ ++ ++#ifndef GRUB_TPM2_TCG2_HEADER ++#define GRUB_TPM2_TCG2_HEADER 1 ++ ++#include ++#include ++ ++grub_err_t ++grub_tcg2_get_max_output_size (grub_size_t *size); ++ ++grub_err_t ++grub_tcg2_submit_command (grub_size_t input_size, ++ grub_uint8_t *input, ++ grub_size_t output_size, ++ grub_uint8_t *output); ++ ++#endif /* ! GRUB_TPM2_TCG2_HEADER */ +diff --git a/include/grub/tpm2/tpm2.h b/include/grub/tpm2/tpm2.h +new file mode 100644 +index 0000000000..4b7a9fbb57 +--- /dev/null ++++ b/include/grub/tpm2/tpm2.h +@@ -0,0 +1,38 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * 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 . ++ */ ++ ++#ifndef GRUB_TPM2_TPM2_HEADER ++#define GRUB_TPM2_TPM2_HEADER 1 ++ ++#include ++#include ++#include ++ ++/* Defined in: TCG TPM Specification, v1.59, Part 2, Section 10.6.1. */ ++#define TPM2_PCR_TO_SELECT(x) ((x) / 8) ++#define TPM2_PCR_TO_BIT(x) (1 << ((x) % 8)) ++ ++/* Well-Known Windows SRK handle */ ++#define TPM2_SRK_HANDLE 0x81000001 ++ ++typedef struct TPM2_SEALED_KEY { ++ TPM2B_PUBLIC public; ++ TPM2B_PRIVATE private; ++} TPM2_SEALED_KEY; ++ ++#endif /* ! GRUB_TPM2_TPM2_HEADER */ +-- +2.34.1 + diff --git a/0011-video-readers-png-Sanity-check-some-huffman-codes.patch b/0011-video-readers-png-Sanity-check-some-huffman-codes.patch new file mode 100644 index 0000000..fc2ea65 --- /dev/null +++ b/0011-video-readers-png-Sanity-check-some-huffman-codes.patch @@ -0,0 +1,42 @@ +From bbbb410d5d7d29d935e7108c77a0368e4e007a43 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 6 Jul 2021 19:19:11 +1000 +Subject: [PATCH 11/32] video/readers/png: Sanity check some huffman codes + +ASAN picked up two OOB global reads: we weren't checking if some code +values fit within the cplens or cpdext arrays. Check and throw an error +if not. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/video/readers/png.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index d7ed5aa6cf..7f2ba7849b 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -753,6 +753,9 @@ grub_png_read_dynamic_block (struct grub_png_data *data) + int len, dist, pos; + + n -= 257; ++ if (((unsigned int) n) >= ARRAY_SIZE (cplens)) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "png: invalid huff code"); + len = cplens[n]; + if (cplext[n]) + len += grub_png_get_bits (data, cplext[n]); +@@ -760,6 +763,9 @@ grub_png_read_dynamic_block (struct grub_png_data *data) + return grub_errno; + + n = grub_png_get_huff_code (data, &data->dist_table); ++ if (((unsigned int) n) >= ARRAY_SIZE (cpdist)) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "png: invalid huff code"); + dist = cpdist[n]; + if (cpdext[n]) + dist += grub_png_get_bits (data, cpdext[n]); +-- +2.34.1 + diff --git a/0012-libtasn1-disable-code-not-needed-in-grub.patch b/0012-libtasn1-disable-code-not-needed-in-grub.patch new file mode 100644 index 0000000..b2ee029 --- /dev/null +++ b/0012-libtasn1-disable-code-not-needed-in-grub.patch @@ -0,0 +1,310 @@ +From 40099cf0d4d68e79db9e71d78070f37c73f998a0 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 1 May 2020 17:12:23 +1000 +Subject: [PATCH 12/23] libtasn1: disable code not needed in grub + +We don't expect to be able to write ASN.1, only read it, +so we can disable some code. + +Do that with #if 0/#endif, rather than deletion. This means +that the difference between upstream and grub is smaller, +which should make updating libtasn1 easier in the future. + +With these exclusions we also avoid the need for minmax.h, +which is convenient because it means we don't have to +import it from gnulib. + +Signed-off-by: Daniel Axtens +--- + grub-core/lib/libtasn1/lib/coding.c | 12 ++++++++++-- + grub-core/lib/libtasn1/lib/decoding.c | 2 ++ + grub-core/lib/libtasn1/lib/element.c | 4 ++-- + grub-core/lib/libtasn1/lib/errors.c | 3 +++ + grub-core/lib/libtasn1/lib/structure.c | 10 ++++++---- + include/grub/libtasn1.h | 15 +++++++++++++++ + 6 files changed, 38 insertions(+), 8 deletions(-) + +diff --git a/grub-core/lib/libtasn1/lib/coding.c b/grub-core/lib/libtasn1/lib/coding.c +index 671104f63..b3d826710 100644 +--- a/grub-core/lib/libtasn1/lib/coding.c ++++ b/grub-core/lib/libtasn1/lib/coding.c +@@ -30,11 +30,11 @@ + #include "parser_aux.h" + #include + #include "element.h" +-#include "minmax.h" + #include + + #define MAX_TAG_LEN 16 + ++#if 0 + /******************************************************/ + /* Function : _asn1_error_description_value_not_found */ + /* Description: creates the ErrorDescription string */ +@@ -58,6 +58,7 @@ _asn1_error_description_value_not_found (asn1_node node, + Estrcat (ErrorDescription, "' not found"); + + } ++#endif + + /** + * asn1_length_der: +@@ -244,6 +245,7 @@ asn1_encode_simple_der (unsigned int etype, const unsigned char *str, + return ASN1_SUCCESS; + } + ++#if 0 + /******************************************************/ + /* Function : _asn1_time_der */ + /* Description: creates the DER coding for a TIME */ +@@ -278,7 +280,7 @@ _asn1_time_der (unsigned char *str, int str_len, unsigned char *der, + + return ASN1_SUCCESS; + } +- ++#endif + + /* + void +@@ -519,6 +521,7 @@ asn1_bit_der (const unsigned char *str, int bit_len, + } + + ++#if 0 + /******************************************************/ + /* Function : _asn1_complete_explicit_tag */ + /* Description: add the length coding to the EXPLICIT */ +@@ -595,6 +598,7 @@ _asn1_complete_explicit_tag (asn1_node node, unsigned char *der, + + return ASN1_SUCCESS; + } ++#endif + + const tag_and_class_st _asn1_tags[] = { + [ASN1_ETYPE_GENERALSTRING] = +@@ -647,6 +651,8 @@ const tag_and_class_st _asn1_tags[] = { + + unsigned int _asn1_tags_size = sizeof (_asn1_tags) / sizeof (_asn1_tags[0]); + ++ ++#if 0 + /******************************************************/ + /* Function : _asn1_insert_tag_der */ + /* Description: creates the DER coding of tags of one */ +@@ -1423,3 +1429,5 @@ error: + asn1_delete_structure (&node); + return err; + } ++ ++#endif +\ No newline at end of file +diff --git a/grub-core/lib/libtasn1/lib/decoding.c b/grub-core/lib/libtasn1/lib/decoding.c +index b1a35356f..b8130b956 100644 +--- a/grub-core/lib/libtasn1/lib/decoding.c ++++ b/grub-core/lib/libtasn1/lib/decoding.c +@@ -1620,6 +1620,7 @@ asn1_der_decoding (asn1_node * element, const void *ider, int ider_len, + return asn1_der_decoding2 (element, ider, &ider_len, 0, errorDescription); + } + ++#if 0 + /** + * asn1_der_decoding_element: + * @structure: pointer to an ASN1 structure +@@ -1650,6 +1651,7 @@ asn1_der_decoding_element (asn1_node * structure, const char *elementName, + { + return asn1_der_decoding (structure, ider, len, errorDescription); + } ++#endif + + /** + * asn1_der_decoding_startEnd: +diff --git a/grub-core/lib/libtasn1/lib/element.c b/grub-core/lib/libtasn1/lib/element.c +index 86e64f2cf..8cd6b662c 100644 +--- a/grub-core/lib/libtasn1/lib/element.c ++++ b/grub-core/lib/libtasn1/lib/element.c +@@ -191,7 +191,7 @@ _asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcache) + return ASN1_SUCCESS; + } + +- ++#if 0 + /** + * asn1_write_value: + * @node_root: pointer to a structure +@@ -646,7 +646,7 @@ asn1_write_value (asn1_node node_root, const char *name, + + return ASN1_SUCCESS; + } +- ++#endif + + #define PUT_VALUE( ptr, ptr_size, data, data_size) \ + *len = data_size; \ +diff --git a/grub-core/lib/libtasn1/lib/errors.c b/grub-core/lib/libtasn1/lib/errors.c +index 4dadbd96d..41921d813 100644 +--- a/grub-core/lib/libtasn1/lib/errors.c ++++ b/grub-core/lib/libtasn1/lib/errors.c +@@ -57,6 +57,8 @@ static const libtasn1_error_entry error_algorithms[] = { + {0, 0} + }; + ++ ++#if 0 + /** + * asn1_perror: + * @error: is an error returned by a libtasn1 function. +@@ -73,6 +75,7 @@ asn1_perror (int error) + const char *str = asn1_strerror (error); + fprintf (stderr, "LIBTASN1 ERROR: %s\n", str ? str : "(null)"); + } ++#endif + + /** + * asn1_strerror: +diff --git a/grub-core/lib/libtasn1/lib/structure.c b/grub-core/lib/libtasn1/lib/structure.c +index c0802202e..45435732c 100644 +--- a/grub-core/lib/libtasn1/lib/structure.c ++++ b/grub-core/lib/libtasn1/lib/structure.c +@@ -76,7 +76,7 @@ _asn1_find_left (asn1_node_const node) + return node->left; + } + +- ++#if 0 + int + _asn1_create_static_structure (asn1_node_const pointer, + char *output_file_name, char *vector_name) +@@ -155,7 +155,7 @@ _asn1_create_static_structure (asn1_node_const pointer, + + return ASN1_SUCCESS; + } +- ++#endif + + /** + * asn1_array2tree: +@@ -721,7 +721,7 @@ asn1_create_element (asn1_node_const definitions, const char *source_name, + return res; + } + +- ++#if 0 + /** + * asn1_print_structure: + * @out: pointer to the output file (e.g. stdout). +@@ -1062,7 +1062,7 @@ asn1_print_structure (FILE * out, asn1_node_const structure, const char *name, + } + } + } +- ++#endif + + + /** +@@ -1158,6 +1158,7 @@ asn1_find_structure_from_oid (asn1_node_const definitions, + return NULL; /* ASN1_ELEMENT_NOT_FOUND; */ + } + ++#if 0 + /** + * asn1_copy_node: + * @dst: Destination asn1 node. +@@ -1207,6 +1208,7 @@ asn1_copy_node (asn1_node dst, const char *dst_name, + + return result; + } ++#endif + + /** + * asn1_dup_node: +diff --git a/include/grub/libtasn1.h b/include/grub/libtasn1.h +index fc695a28a..0c3a44881 100644 +--- a/include/grub/libtasn1.h ++++ b/include/grub/libtasn1.h +@@ -314,6 +314,8 @@ extern "C" + /* Functions definitions */ + /***********************************/ + ++/* These functions are not used in grub and should not be referenced. */ ++# if 0 + extern ASN1_API int + asn1_parser2tree (const char *file, + asn1_node * definitions, char *error_desc); +@@ -322,14 +324,17 @@ extern "C" + asn1_parser2array (const char *inputFileName, + const char *outputFileName, + const char *vectorName, char *error_desc); ++# endif + + extern ASN1_API int + asn1_array2tree (const asn1_static_node * array, + asn1_node * definitions, char *errorDescription); + ++# if 0 + extern ASN1_API void + asn1_print_structure (FILE * out, asn1_node_const structure, + const char *name, int mode); ++# endif + + extern ASN1_API int + asn1_create_element (asn1_node_const definitions, +@@ -343,9 +348,11 @@ extern "C" + extern ASN1_API int + asn1_delete_element (asn1_node structure, const char *element_name); + ++# if 0 + extern ASN1_API int + asn1_write_value (asn1_node node_root, const char *name, + const void *ivalue, int len); ++# endif + + extern ASN1_API int + asn1_read_value (asn1_node_const root, const char *name, +@@ -362,9 +369,11 @@ extern "C" + asn1_number_of_elements (asn1_node_const element, const char *name, + int *num); + ++# if 0 + extern ASN1_API int + asn1_der_coding (asn1_node_const element, const char *name, + void *ider, int *len, char *ErrorDescription); ++# endif + + extern ASN1_API int + asn1_der_decoding2 (asn1_node * element, const void *ider, +@@ -375,6 +384,7 @@ extern "C" + asn1_der_decoding (asn1_node * element, const void *ider, + int ider_len, char *errorDescription); + ++# if 0 + /* Do not use. Use asn1_der_decoding() instead. */ + extern ASN1_API int + asn1_der_decoding_element (asn1_node * structure, +@@ -382,6 +392,7 @@ extern "C" + const void *ider, int len, + char *errorDescription) + _ASN1_GCC_ATTR_DEPRECATED; ++# endif + + extern ASN1_API int + asn1_der_decoding_startEnd (asn1_node element, +@@ -407,12 +418,16 @@ extern "C" + const char + *oidValue); + ++# if 0 + __LIBTASN1_PURE__ + extern ASN1_API const char *asn1_check_version (const char *req_version); ++# endif + + __LIBTASN1_PURE__ extern ASN1_API const char *asn1_strerror (int error); + ++# if 0 + extern ASN1_API void asn1_perror (int error); ++# endif + + # define ASN1_MAX_TAG_SIZE 4 + # define ASN1_MAX_LENGTH_SIZE 9 +-- +2.31.1 + diff --git a/0012-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch b/0012-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch new file mode 100644 index 0000000..bb15c69 --- /dev/null +++ b/0012-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch @@ -0,0 +1,55 @@ +From 5e53d73775f6dc9b9b08536cbac2f8a5e2559903 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Fri, 28 Oct 2022 21:31:39 +0800 +Subject: [PATCH 12/12] normal/charset: Fix an integer overflow in + grub_unicode_aglomerate_comb() + +The out->ncomb is a bit-field of 8 bits. So, the max possible value is 255. +However, code in grub_unicode_aglomerate_comb() doesn't check for an +overflow when incrementing out->ncomb. If out->ncomb is already 255, +after incrementing it will get 0 instead of 256, and cause illegal +memory access in subsequent processing. + +This patch introduces GRUB_UNICODE_NCOMB_MAX to represent the max +acceptable value of ncomb. The code now checks for this limit and +ignores additional combining characters when limit is reached. + +Reported-by: Daniel Axtens +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +--- + grub-core/normal/charset.c | 3 +++ + include/grub/unicode.h | 2 ++ + 2 files changed, 5 insertions(+) + +diff --git a/grub-core/normal/charset.c b/grub-core/normal/charset.c +index 7a5a7c153..c243ca6da 100644 +--- a/grub-core/normal/charset.c ++++ b/grub-core/normal/charset.c +@@ -472,6 +472,9 @@ grub_unicode_aglomerate_comb (const grub_uint32_t *in, grub_size_t inlen, + if (!haveout) + continue; + ++ if (out->ncomb == GRUB_UNICODE_NCOMB_MAX) ++ continue; ++ + if (comb_type == GRUB_UNICODE_COMB_MC + || comb_type == GRUB_UNICODE_COMB_ME + || comb_type == GRUB_UNICODE_COMB_MN) +diff --git a/include/grub/unicode.h b/include/grub/unicode.h +index 4de986a85..c4f6fca04 100644 +--- a/include/grub/unicode.h ++++ b/include/grub/unicode.h +@@ -147,7 +147,9 @@ struct grub_unicode_glyph + grub_uint8_t bidi_level:6; /* minimum: 6 */ + enum grub_bidi_type bidi_type:5; /* minimum: :5 */ + ++#define GRUB_UNICODE_NCOMB_MAX ((1 << 8) - 1) + unsigned ncomb:8; ++ + /* Hint by unicode subsystem how wide this character usually is. + Real width is determined by font. Set only in UTF-8 stream. */ + int estimated_width:8; +-- +2.35.3 + diff --git a/0012-protectors-Add-TPM2-Key-Protector.patch b/0012-protectors-Add-TPM2-Key-Protector.patch new file mode 100644 index 0000000..95a5876 --- /dev/null +++ b/0012-protectors-Add-TPM2-Key-Protector.patch @@ -0,0 +1,977 @@ +From b173db7537920ee5706e1c961fea3086ada6b6dd Mon Sep 17 00:00:00 2001 +From: Hernan Gatta +Date: Tue, 1 Feb 2022 05:02:55 -0800 +Subject: [PATCH 12/14] protectors: Add TPM2 Key Protector + +The TPM2 key protector is a module that enables the automatic retrieval of a +fully-encrypted disk's unlocking key from a TPM 2.0. + +The theory of operation is such that the module accepts various arguments, most +of which are optional and therefore possess reasonable defaults. One of these +arguments is the keyfile parameter, which is mandatory. + +The value of this parameter must be a path to a sealed key file (e.g., +(hd0,gpt1)/boot/grub2/sealed_key). This sealed key file is created via the +grub-protect tool. The tool utilizes the TPM's sealing functionality to seal +(i.e., encrypt) an unlocking key using a Storage Root Key (SRK) to the values of +various Platform Configuration Registers (PCRs). These PCRs reflect the state of +the system as it boots. If the values are as expected, the system may be +considered trustworthy, at which point the TPM allows for a caller to utilize +the private component of the SRK to unseal (i.e., decrypt) the sealed key file. +The caller, in this case, is this key protector. + +The TPM2 key protector registers two commands: + +- tpm2_key_protector_init: Initializes the state of the TPM2 key protector for + later usage, clearing any previous state, too, if + any. + +- tpm2_key_protector_clear: Clears any state set by tpm2_key_protector_init. + +The way this is expected to be used requires the user to, either interactively +or, normally, via a boot script, initialize (i.e., configure) the key protector +and then specify that it be used by the cryptomount command (modifications to +this command are in a different patch). + +For instance: + +tpm2_key_protector_init --keyfile=KEYFILE1 +cryptomount DISK1 -k tpm2 + +tpm2_key_protector_init --keyfile=KEYFILE2 --pcrs=7,11 +cryptomount DISK2 -k tpm2 + +If a user does not initialize the key protector and attempts to use it anyway, +the protector returns an error. + +Signed-off-by: Hernan Gatta +--- + grub-core/Makefile.core.def | 10 + + grub-core/tpm2/args.c | 129 ++++++ + grub-core/tpm2/module.c | 710 ++++++++++++++++++++++++++++++ + include/grub/tpm2/internal/args.h | 39 ++ + 4 files changed, 888 insertions(+) + create mode 100644 grub-core/tpm2/args.c + create mode 100644 grub-core/tpm2/module.c + create mode 100644 include/grub/tpm2/internal/args.h + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index b0001a33cf..850cee2b13 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2561,6 +2561,16 @@ module = { + enable = efi; + }; + ++module = { ++ name = tpm2; ++ common = tpm2/args.c; ++ common = tpm2/buffer.c; ++ common = tpm2/module.c; ++ common = tpm2/mu.c; ++ common = tpm2/tpm2.c; ++ efi = tpm2/tcg2.c; ++}; ++ + module = { + name = tr; + common = commands/tr.c; +diff --git a/grub-core/tpm2/args.c b/grub-core/tpm2/args.c +new file mode 100644 +index 0000000000..90c7cd8991 +--- /dev/null ++++ b/grub-core/tpm2/args.c +@@ -0,0 +1,129 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * 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 . ++ */ ++ ++#include ++#include ++#include ++#include ++ ++grub_err_t ++grub_tpm2_protector_parse_pcrs (char *value, grub_uint8_t *pcrs, ++ grub_uint8_t *pcr_count) ++{ ++ char *current_pcr = value; ++ char *next_pcr; ++ unsigned long pcr; ++ grub_uint8_t i; ++ ++ if (grub_strlen (value) == 0) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ *pcr_count = 0; ++ for (i = 0; i < TPM_MAX_PCRS; i++) ++ { ++ next_pcr = grub_strchr (current_pcr, ','); ++ if (next_pcr == current_pcr) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("Empty entry in PCR list")); ++ if (next_pcr) ++ *next_pcr = '\0'; ++ ++ grub_errno = GRUB_ERR_NONE; ++ pcr = grub_strtoul (current_pcr, NULL, 10); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_error (grub_errno, ++ N_("Entry '%s' in PCR list is not a number"), ++ current_pcr); ++ ++ if (pcr > TPM_MAX_PCRS) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("Entry %lu in PCR list is too large to be a PCR " ++ "number, PCR numbers range from 0 to %u"), ++ pcr, TPM_MAX_PCRS); ++ ++ pcrs[i] = (grub_uint8_t)pcr; ++ *pcr_count += 1; ++ ++ if (!next_pcr) ++ break; ++ ++ current_pcr = next_pcr + 1; ++ if (*current_pcr == '\0') ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("Trailing comma at the end of PCR list")); ++ } ++ ++ if (i == TPM_MAX_PCRS) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("Too many PCRs in PCR list, the maximum number of " ++ "PCRs is %u"), TPM_MAX_PCRS); ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_tpm2_protector_parse_asymmetric (const char *value, TPM_ALG_ID *asymmetric) ++{ ++ if (grub_strcasecmp (value, "ECC") == 0) ++ *asymmetric = TPM_ALG_ECC; ++ else if (grub_strcasecmp (value, "RSA") == 0) ++ *asymmetric = TPM_ALG_RSA; ++ else ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("Value '%s' is not a valid asymmetric key type"), ++ value); ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_tpm2_protector_parse_bank (const char *value, TPM_ALG_ID *bank) ++{ ++ if (grub_strcasecmp (value, "SHA1") == 0) ++ *bank = TPM_ALG_SHA1; ++ else if (grub_strcasecmp (value, "SHA256") == 0) ++ *bank = TPM_ALG_SHA256; ++ else if (grub_strcasecmp (value, "SHA384") == 0) ++ *bank = TPM_ALG_SHA384; ++ else ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("Value '%s' is not a valid PCR bank"), value); ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_tpm2_protector_parse_tpm_handle (const char *value, TPM_HANDLE *handle) ++{ ++ unsigned long num; ++ ++ grub_errno = GRUB_ERR_NONE; ++ num = grub_strtoul (value, NULL, 0); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_error (grub_errno, N_("TPM handle value '%s' is not a number"), ++ value); ++ ++ if (num > GRUB_UINT_MAX) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("Value %lu is too large to be a TPM handle, TPM " ++ "handles are unsigned 32-bit integers"), num); ++ ++ *handle = (TPM_HANDLE)num; ++ ++ return GRUB_ERR_NONE; ++} +diff --git a/grub-core/tpm2/module.c b/grub-core/tpm2/module.c +new file mode 100644 +index 0000000000..3f2f386f7e +--- /dev/null ++++ b/grub-core/tpm2/module.c +@@ -0,0 +1,710 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * 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 . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++typedef enum grub_tpm2_protector_mode ++{ ++ GRUB_TPM2_PROTECTOR_MODE_UNSET, ++ GRUB_TPM2_PROTECTOR_MODE_SRK, ++ GRUB_TPM2_PROTECTOR_MODE_NV ++} grub_tpm2_protector_mode_t; ++ ++struct grub_tpm2_protector_context ++{ ++ grub_tpm2_protector_mode_t mode; ++ grub_uint8_t pcrs[TPM_MAX_PCRS]; ++ grub_uint8_t pcr_count; ++ TPM_ALG_ID asymmetric; ++ TPM_ALG_ID bank; ++ const char *keyfile; ++ TPM_HANDLE srk; ++ TPM_HANDLE nv; ++}; ++ ++static const struct grub_arg_option grub_tpm2_protector_init_cmd_options[] = ++ { ++ /* Options for all modes */ ++ { ++ .longarg = "mode", ++ .shortarg = 'm', ++ .flags = 0, ++ .arg = NULL, ++ .type = ARG_TYPE_STRING, ++ .doc = ++ N_("Unseal key using SRK ('srk') (default) or retrieve it from an NV " ++ "Index ('nv')."), ++ }, ++ { ++ .longarg = "pcrs", ++ .shortarg = 'p', ++ .flags = 0, ++ .arg = NULL, ++ .type = ARG_TYPE_STRING, ++ .doc = ++ N_("Comma-separated list of PCRs used to authorize key release " ++ "(e.g., '7,11', default is 7."), ++ }, ++ { ++ .longarg = "bank", ++ .shortarg = 'b', ++ .flags = 0, ++ .arg = NULL, ++ .type = ARG_TYPE_STRING, ++ .doc = ++ N_("Bank of PCRs used to authorize key release: " ++ "SHA1, SHA256 (default), or SHA384."), ++ }, ++ /* SRK-mode options */ ++ { ++ .longarg = "keyfile", ++ .shortarg = 'k', ++ .flags = 0, ++ .arg = NULL, ++ .type = ARG_TYPE_STRING, ++ .doc = ++ N_("Required in SRK mode, path to the sealed key file to unseal using " ++ "the TPM (e.g., (hd0,gpt1)/boot/grub2/sealed_key)."), ++ }, ++ { ++ .longarg = "srk", ++ .shortarg = 's', ++ .flags = 0, ++ .arg = NULL, ++ .type = ARG_TYPE_STRING, ++ .doc = ++ N_("In SRK mode, the SRK handle if the SRK is persistent " ++ "(default is 0x81000001)."), ++ }, ++ { ++ .longarg = "asymmetric", ++ .shortarg = 'a', ++ .flags = 0, ++ .arg = NULL, ++ .type = ARG_TYPE_STRING, ++ .doc = ++ N_("In SRK mode, the type of SRK: RSA (default) or ECC."), ++ }, ++ /* NV Index-mode options */ ++ { ++ .longarg = "nvindex", ++ .shortarg = 'n', ++ .flags = 0, ++ .arg = NULL, ++ .type = ARG_TYPE_STRING, ++ .doc = ++ N_("Required in NV Index mode, the NV handle to read which must " ++ "readily exist on the TPM and which contains the key."), ++ }, ++ /* End of list */ ++ {0, 0, 0, 0, 0, 0} ++ }; ++ ++static grub_extcmd_t grub_tpm2_protector_init_cmd; ++static grub_extcmd_t grub_tpm2_protector_clear_cmd; ++static struct grub_tpm2_protector_context grub_tpm2_protector_ctx = { 0 }; ++ ++static grub_err_t ++grub_tpm2_protector_srk_read_keyfile (const char *filepath, void **buffer, ++ grub_size_t *buffer_size) ++{ ++ grub_file_t sealed_key_file; ++ grub_off_t sealed_key_size; ++ void *sealed_key_buffer; ++ grub_off_t sealed_key_read; ++ ++ sealed_key_file = grub_file_open (filepath, GRUB_FILE_TYPE_NONE); ++ if (!sealed_key_file) ++ { ++ grub_dprintf ("tpm2", "Could not open sealed key file.\n"); ++ /* grub_file_open sets grub_errno on error, and if we do no unset it, ++ * future calls to grub_file_open will fail (and so will anybody up the ++ * stack who checks the value, if any). */ ++ grub_errno = GRUB_ERR_NONE; ++ return GRUB_ERR_FILE_NOT_FOUND; ++ } ++ ++ sealed_key_size = grub_file_size (sealed_key_file); ++ if (!sealed_key_size) ++ { ++ grub_dprintf ("tpm2", "Could not read sealed key file size.\n"); ++ grub_file_close (sealed_key_file); ++ return GRUB_ERR_OUT_OF_RANGE; ++ } ++ ++ sealed_key_buffer = grub_malloc (sealed_key_size); ++ if (!sealed_key_buffer) ++ { ++ grub_dprintf ("tpm2", "Could not allocate buffer for sealed key.\n"); ++ grub_file_close (sealed_key_file); ++ return GRUB_ERR_OUT_OF_MEMORY; ++ } ++ ++ sealed_key_read = grub_file_read (sealed_key_file, sealed_key_buffer, ++ sealed_key_size); ++ if (sealed_key_read != sealed_key_size) ++ { ++ grub_dprintf ("tpm2", "Could not retrieve sealed key file contents.\n"); ++ grub_free (sealed_key_buffer); ++ grub_file_close (sealed_key_file); ++ return GRUB_ERR_FILE_READ_ERROR; ++ } ++ ++ grub_file_close (sealed_key_file); ++ ++ *buffer = sealed_key_buffer; ++ *buffer_size = sealed_key_size; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_tpm2_protector_srk_unmarshal_keyfile (void *sealed_key, ++ grub_size_t sealed_key_size, ++ TPM2_SEALED_KEY *sk) ++{ ++ struct grub_tpm2_buffer buf; ++ ++ grub_tpm2_buffer_init (&buf); ++ if (sealed_key_size > buf.cap) ++ { ++ grub_dprintf ("tpm2", "Sealed key file is larger than decode buffer " ++ "(%lu vs %lu bytes).\n", sealed_key_size, buf.cap); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ grub_memcpy (buf.data, sealed_key, sealed_key_size); ++ buf.size = sealed_key_size; ++ ++ grub_tpm2_mu_TPM2B_PUBLIC_Unmarshal (&buf, &sk->public); ++ grub_tpm2_mu_TPM2B_Unmarshal (&buf, (TPM2B *)&sk->private); ++ ++ if (buf.error) ++ { ++ grub_dprintf ("tpm2", "Could not unmarshal sealed key file, it is likely " ++ "malformed.\n"); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_tpm2_protector_srk_get (const struct grub_tpm2_protector_context *ctx, ++ TPM_HANDLE *srk) ++{ ++ TPM_RC rc; ++ TPM2B_PUBLIC public; ++ TPMS_AUTH_COMMAND authCommand = { 0 }; ++ TPM2B_SENSITIVE_CREATE inSensitive = { 0 }; ++ TPM2B_PUBLIC inPublic = { 0 }; ++ TPM2B_DATA outsideInfo = { 0 }; ++ TPML_PCR_SELECTION creationPcr = { 0 }; ++ TPM2B_PUBLIC outPublic = { 0 }; ++ TPM2B_CREATION_DATA creationData = { 0 }; ++ TPM2B_DIGEST creationHash = { 0 }; ++ TPMT_TK_CREATION creationTicket = { 0 }; ++ TPM2B_NAME srkName = { 0 }; ++ TPM_HANDLE srkHandle; ++ ++ /* Find SRK */ ++ rc = TPM2_ReadPublic (ctx->srk, NULL, &public); ++ if (rc == TPM_RC_SUCCESS) ++ { ++ *srk = ctx->srk; ++ return GRUB_ERR_NONE; ++ } ++ ++ /* The handle exists but its public area could not be read. */ ++ if ((rc & ~TPM_RC_N_MASK) != TPM_RC_HANDLE) ++ { ++ grub_dprintf ("tpm2", "The SRK handle (0x%x) exists on the TPM but its " ++ "public area could not be read (TPM2_ReadPublic " ++ "failed with TSS/TPM error %u).\n", ctx->srk, rc); ++ return GRUB_ERR_BAD_DEVICE; ++ } ++ ++ /* Create SRK */ ++ authCommand.sessionHandle = TPM_RS_PW; ++ inPublic.publicArea.type = ctx->asymmetric; ++ inPublic.publicArea.nameAlg = TPM_ALG_SHA256; ++ inPublic.publicArea.objectAttributes.restricted = 1; ++ inPublic.publicArea.objectAttributes.userWithAuth = 1; ++ inPublic.publicArea.objectAttributes.decrypt = 1; ++ inPublic.publicArea.objectAttributes.fixedTPM = 1; ++ inPublic.publicArea.objectAttributes.fixedParent = 1; ++ inPublic.publicArea.objectAttributes.sensitiveDataOrigin = 1; ++ inPublic.publicArea.objectAttributes.noDA = 1; ++ ++ if (ctx->asymmetric == TPM_ALG_RSA) ++ { ++ inPublic.publicArea.parameters.rsaDetail.symmetric.algorithm = TPM_ALG_AES; ++ inPublic.publicArea.parameters.rsaDetail.symmetric.keyBits.aes = 128; ++ inPublic.publicArea.parameters.rsaDetail.symmetric.mode.aes = TPM_ALG_CFB; ++ inPublic.publicArea.parameters.rsaDetail.scheme.scheme = TPM_ALG_NULL; ++ inPublic.publicArea.parameters.rsaDetail.keyBits = 2048; ++ inPublic.publicArea.parameters.rsaDetail.exponent = 0; ++ } ++ else if (ctx->asymmetric == TPM_ALG_ECC) ++ { ++ inPublic.publicArea.parameters.eccDetail.symmetric.algorithm = TPM_ALG_AES; ++ inPublic.publicArea.parameters.eccDetail.symmetric.keyBits.aes = 128; ++ inPublic.publicArea.parameters.eccDetail.symmetric.mode.aes = TPM_ALG_CFB; ++ inPublic.publicArea.parameters.eccDetail.scheme.scheme = TPM_ALG_NULL; ++ inPublic.publicArea.parameters.eccDetail.curveID = TPM_ECC_NIST_P256; ++ inPublic.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL; ++ } ++ else ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ rc = TPM2_CreatePrimary (TPM_RH_OWNER, &authCommand, &inSensitive, &inPublic, ++ &outsideInfo, &creationPcr, &srkHandle, &outPublic, ++ &creationData, &creationHash, &creationTicket, ++ &srkName, NULL); ++ if (rc != TPM_RC_SUCCESS) ++ { ++ grub_dprintf ("tpm2", "Could not create SRK (TPM2_CreatePrimary failed " ++ "with TSS/TPM error %u).\n", rc); ++ return GRUB_ERR_BAD_DEVICE; ++ } ++ ++ *srk = srkHandle; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_tpm2_protector_srk_recover (const struct grub_tpm2_protector_context *ctx, ++ grub_uint8_t **key, grub_size_t *key_size) ++{ ++ TPM_RC rc; ++ TPM2_SEALED_KEY sealed_key; ++ void *sealed_key_bytes; ++ grub_size_t sealed_key_size; ++ TPM_HANDLE srk_handle; ++ TPM2B_NONCE nonceCaller = { 0 }; ++ TPM2B_ENCRYPTED_SECRET salt = { 0 }; ++ TPMT_SYM_DEF symmetric = { 0 }; ++ TPM2B_NONCE nonceTPM = { 0 }; ++ TPMI_SH_AUTH_SESSION session; ++ TPML_PCR_SELECTION pcrSel = { ++ .count = 1, ++ .pcrSelections = { ++ { ++ .hash = ctx->bank, ++ .sizeOfSelect = 3, ++ .pcrSelect = { 0 } ++ }, ++ } ++ }; ++ TPMS_AUTH_COMMAND authCmd = { 0 }; ++ TPM_HANDLE sealed_key_handle; ++ TPM2B_NAME name; ++ TPMS_AUTH_RESPONSE authResponse; ++ TPM2B_SENSITIVE_DATA data; ++ grub_uint8_t *key_out; ++ grub_uint8_t i; ++ grub_err_t err; ++ ++ /* Retrieve Sealed Key */ ++ err = grub_tpm2_protector_srk_read_keyfile (ctx->keyfile, &sealed_key_bytes, ++ &sealed_key_size); ++ if (err) ++ return grub_error (err, N_("Failed to read key file %s"), ctx->keyfile); ++ ++ err = grub_tpm2_protector_srk_unmarshal_keyfile (sealed_key_bytes, ++ sealed_key_size, ++ &sealed_key); ++ if (err) ++ { ++ grub_error (err, N_("Failed to unmarshal key, ensure the key file is in " ++ "TPM wire format")); ++ goto exit1; ++ } ++ ++ /* Get SRK */ ++ err = grub_tpm2_protector_srk_get (ctx, &srk_handle); ++ if (err) ++ { ++ grub_error (err, N_("Failed to retrieve the SRK")); ++ goto exit1; ++ } ++ ++ err = GRUB_ERR_BAD_DEVICE; ++ ++ /* Start Auth Session */ ++ nonceCaller.size = TPM_SHA256_DIGEST_SIZE; ++ symmetric.algorithm = TPM_ALG_NULL; ++ ++ rc = TPM2_StartAuthSession (TPM_RH_NULL, TPM_RH_NULL, 0, &nonceCaller, &salt, ++ TPM_SE_POLICY, &symmetric, TPM_ALG_SHA256, ++ &session, &nonceTPM, 0); ++ if (rc) ++ { ++ grub_error (err, N_("Failed to start auth session (TPM2_StartAuthSession " ++ "failed with TSS/TPM error %u)"), rc); ++ goto exit2; ++ } ++ ++ /* Policy PCR */ ++ for (i = 0; i < ctx->pcr_count; i++) ++ pcrSel ++ .pcrSelections[0] ++ .pcrSelect[TPM2_PCR_TO_SELECT(ctx->pcrs[i])] ++ |= TPM2_PCR_TO_BIT(ctx->pcrs[i]); ++ ++ rc = TPM2_PolicyPCR (session, NULL, NULL, &pcrSel, NULL); ++ if (rc) ++ { ++ grub_error (err, N_("Failed to submit PCR policy (TPM2_PolicyPCR failed " ++ "with TSS/TPM error %u)"), rc); ++ goto exit3; ++ } ++ ++ /* Load Sealed Key */ ++ authCmd.sessionHandle = TPM_RS_PW; ++ rc = TPM2_Load (srk_handle, &authCmd, &sealed_key.private, &sealed_key.public, ++ &sealed_key_handle, &name, &authResponse); ++ if (rc) ++ { ++ grub_error (err, N_("Failed to load sealed key (TPM2_Load failed with " ++ "TSS/TPM error %u)"), rc); ++ goto exit3; ++ } ++ ++ /* Unseal Sealed Key */ ++ authCmd.sessionHandle = session; ++ grub_memset (&authResponse, 0, sizeof (authResponse)); ++ ++ rc = TPM2_Unseal (sealed_key_handle, &authCmd, &data, &authResponse); ++ if (rc) ++ { ++ grub_error (err, N_("Failed to unseal sealed key (TPM2_Unseal failed " ++ "with TSS/TPM error %u)"), rc); ++ goto exit4; ++ } ++ ++ /* Epilogue */ ++ key_out = grub_malloc (data.size); ++ if (!key_out) ++ { ++ err = GRUB_ERR_OUT_OF_MEMORY; ++ grub_error (err, N_("No memory left to allocate unlock key buffer")); ++ goto exit4; ++ } ++ ++ grub_memcpy (key_out, data.buffer, data.size); ++ ++ *key = key_out; ++ *key_size = data.size; ++ ++ err = GRUB_ERR_NONE; ++ ++exit4: ++ TPM2_FlushContext (sealed_key_handle); ++ ++exit3: ++ TPM2_FlushContext (session); ++ ++exit2: ++ TPM2_FlushContext (srk_handle); ++ ++exit1: ++ grub_free (sealed_key_bytes); ++ return err; ++} ++ ++static grub_err_t ++grub_tpm2_protector_nv_recover (const struct grub_tpm2_protector_context *ctx, ++ grub_uint8_t **key, grub_size_t *key_size) ++{ ++ (void)ctx; ++ (void)key; ++ (void)key_size; ++ ++ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ N_("NV Index mode is not implemented yet")); ++} ++ ++static grub_err_t ++grub_tpm2_protector_recover (const struct grub_tpm2_protector_context *ctx, ++ grub_uint8_t **key, grub_size_t *key_size) ++{ ++ switch (ctx->mode) ++ { ++ case GRUB_TPM2_PROTECTOR_MODE_SRK: ++ return grub_tpm2_protector_srk_recover (ctx, key, key_size); ++ case GRUB_TPM2_PROTECTOR_MODE_NV: ++ return grub_tpm2_protector_nv_recover (ctx, key, key_size); ++ default: ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++} ++ ++static grub_err_t ++grub_tpm2_protector_recover_key (grub_uint8_t **key, grub_size_t *key_size) ++{ ++ grub_err_t err; ++ ++ /* Expect a call to tpm2_protector_init before anybody tries to use us */ ++ if (grub_tpm2_protector_ctx.mode == GRUB_TPM2_PROTECTOR_MODE_UNSET) ++ return grub_error (GRUB_ERR_INVALID_COMMAND, ++ N_("Cannot use TPM2 key protector without initializing " ++ "it, call tpm2_protector_init first")); ++ ++ if (!key) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ err = grub_tpm2_protector_recover (&grub_tpm2_protector_ctx, key, key_size); ++ if (err) ++ return err; ++ ++ return GRUB_ERR_NONE; ++} ++ ++ ++static grub_err_t ++grub_tpm2_protector_check_args (struct grub_tpm2_protector_context *ctx) ++{ ++ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_UNSET) ++ ctx->mode = GRUB_TPM2_PROTECTOR_MODE_SRK; ++ ++ /* Checks for SRK mode */ ++ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_SRK && !ctx->keyfile) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("In SRK mode, a key file must be specified: " ++ "--keyfile or -k")); ++ ++ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_SRK && ctx->nv) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("In SRK mode, an NV Index cannot be specified")); ++ ++ /* Checks for NV mode */ ++ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV && !ctx->nv) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("In NV Index mode, an NV Index must be specified: " ++ "--nvindex or -n")); ++ ++ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV && ctx->keyfile) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("In NV Index mode, a keyfile cannot be specified")); ++ ++ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV && ctx->srk) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("In NV Index mode, an SRK cannot be specified")); ++ ++ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV && ctx->asymmetric) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("In NV Index mode, an asymmetric key type cannot be " ++ "specified")); ++ ++ /* Defaults assignment */ ++ if (!ctx->bank) ++ ctx->bank = TPM_ALG_SHA256; ++ ++ if (!ctx->pcr_count) ++ { ++ ctx->pcrs[0] = 7; ++ ctx->pcr_count = 1; ++ } ++ ++ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_SRK) ++ { ++ if (!ctx->srk) ++ ctx->srk = TPM2_SRK_HANDLE; ++ ++ if (!ctx->asymmetric) ++ ctx->asymmetric = TPM_ALG_RSA; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_tpm2_protector_parse_keyfile (const char *value, const char **keyfile) ++{ ++ if (grub_strlen (value) == 0) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ *keyfile = grub_strdup (value); ++ if (!*keyfile) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ N_("No memory to duplicate keyfile path")); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_tpm2_protector_parse_mode (const char *value, ++ grub_tpm2_protector_mode_t *mode) ++{ ++ if (grub_strcmp (value, "srk") == 0) ++ *mode = GRUB_TPM2_PROTECTOR_MODE_SRK; ++ else if (grub_strcmp (value, "nv") == 0) ++ *mode = GRUB_TPM2_PROTECTOR_MODE_NV; ++ else ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("Value '%s' is not a valid TPM2 key protector mode"), ++ value); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_tpm2_protector_init_cmd_handler (grub_extcmd_context_t ctxt, int argc, ++ char **args __attribute__ ((unused))) ++{ ++ struct grub_arg_list *state = ctxt->state; ++ grub_err_t err; ++ ++ if (argc) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("The TPM2 key protector does not accept any " ++ "non-option arguments (i.e., like -o and/or --option " ++ "only)")); ++ ++ grub_free ((void *) grub_tpm2_protector_ctx.keyfile); ++ grub_memset (&grub_tpm2_protector_ctx, 0, sizeof (grub_tpm2_protector_ctx)); ++ ++ if (state[0].set) /* mode */ ++ { ++ err = grub_tpm2_protector_parse_mode (state[0].arg, ++ &grub_tpm2_protector_ctx.mode); ++ if (err) ++ return err; ++ } ++ ++ if (state[1].set) /* pcrs */ ++ { ++ err = grub_tpm2_protector_parse_pcrs (state[1].arg, ++ grub_tpm2_protector_ctx.pcrs, ++ &grub_tpm2_protector_ctx.pcr_count); ++ if (err) ++ return err; ++ } ++ ++ if (state[2].set) /* bank */ ++ { ++ err = grub_tpm2_protector_parse_bank (state[2].arg, ++ &grub_tpm2_protector_ctx.bank); ++ if (err) ++ return err; ++ } ++ ++ if (state[3].set) /* keyfile */ ++ { ++ err = grub_tpm2_protector_parse_keyfile (state[3].arg, ++ &grub_tpm2_protector_ctx.keyfile); ++ if (err) ++ return err; ++ } ++ ++ if (state[4].set) /* srk */ ++ { ++ err = grub_tpm2_protector_parse_tpm_handle (state[4].arg, ++ &grub_tpm2_protector_ctx.srk); ++ if (err) ++ return err; ++ } ++ ++ if (state[5].set) /* asymmetric */ ++ { ++ err = grub_tpm2_protector_parse_asymmetric (state[5].arg, ++ &grub_tpm2_protector_ctx.asymmetric); ++ if (err) ++ return err; ++ } ++ ++ if (state[6].set) /* nvindex */ ++ { ++ err = grub_tpm2_protector_parse_tpm_handle (state[6].arg, ++ &grub_tpm2_protector_ctx.nv); ++ if (err) ++ return err; ++ } ++ ++ err = grub_tpm2_protector_check_args (&grub_tpm2_protector_ctx); ++ ++ /* This command only initializes the protector, so nothing else to do. */ ++ ++ return err; ++} ++ ++static grub_err_t ++grub_tpm2_protector_clear_cmd_handler (grub_extcmd_context_t ctxt __attribute__ ((unused)), ++ int argc, ++ char **args __attribute__ ((unused))) ++{ ++ if (argc) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("tpm2_key_protector_clear accepts no arguments")); ++ ++ grub_free ((void *) grub_tpm2_protector_ctx.keyfile); ++ grub_memset (&grub_tpm2_protector_ctx, 0, sizeof (grub_tpm2_protector_ctx)); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static struct grub_key_protector grub_tpm2_key_protector = ++ { ++ .name = "tpm2", ++ .recover_key = grub_tpm2_protector_recover_key ++ }; ++ ++GRUB_MOD_INIT (tpm2) ++{ ++ grub_tpm2_protector_init_cmd = ++ grub_register_extcmd ("tpm2_key_protector_init", ++ grub_tpm2_protector_init_cmd_handler, 0, ++ N_("[-m mode] " ++ "[-p pcr_list] " ++ "[-b pcr_bank] " ++ "[-k sealed_key_file_path] " ++ "[-s srk_handle] " ++ "[-a asymmetric_key_type] " ++ "[-n nv_index]"), ++ N_("Initialize the TPM2 key protector."), ++ grub_tpm2_protector_init_cmd_options); ++ grub_tpm2_protector_clear_cmd = ++ grub_register_extcmd ("tpm2_key_protector_clear", ++ grub_tpm2_protector_clear_cmd_handler, 0, NULL, ++ N_("Clear the TPM2 key protector if previously initialized."), ++ NULL); ++ grub_key_protector_register (&grub_tpm2_key_protector); ++} ++ ++GRUB_MOD_FINI (tpm2) ++{ ++ grub_free ((void *) grub_tpm2_protector_ctx.keyfile); ++ grub_memset (&grub_tpm2_protector_ctx, 0, sizeof (grub_tpm2_protector_ctx)); ++ ++ grub_key_protector_unregister (&grub_tpm2_key_protector); ++ grub_unregister_extcmd (grub_tpm2_protector_clear_cmd); ++ grub_unregister_extcmd (grub_tpm2_protector_init_cmd); ++} +diff --git a/include/grub/tpm2/internal/args.h b/include/grub/tpm2/internal/args.h +new file mode 100644 +index 0000000000..6341fce1c5 +--- /dev/null ++++ b/include/grub/tpm2/internal/args.h +@@ -0,0 +1,39 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * 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 . ++ */ ++ ++#ifndef GRUB_TPM2_INTERNAL_ARGS_HEADER ++#define GRUB_TPM2_INTERNAL_ARGS_HEADER 1 ++ ++#include ++#include ++ ++grub_err_t ++grub_tpm2_protector_parse_pcrs (char *value, grub_uint8_t *pcrs, ++ grub_uint8_t *pcr_count); ++ ++grub_err_t ++grub_tpm2_protector_parse_asymmetric (const char *value, ++ TPM_ALG_ID *asymmetric); ++ ++grub_err_t ++grub_tpm2_protector_parse_bank (const char *value, TPM_ALG_ID *bank); ++ ++grub_err_t ++grub_tpm2_protector_parse_tpm_handle (const char *value, TPM_HANDLE *handle); ++ ++#endif /* ! GRUB_TPM2_INTERNAL_ARGS_HEADER */ +-- +2.34.1 + diff --git a/0012-tpm-Build-tpm-as-module.patch b/0012-tpm-Build-tpm-as-module.patch new file mode 100644 index 0000000..80cfb0a --- /dev/null +++ b/0012-tpm-Build-tpm-as-module.patch @@ -0,0 +1,56 @@ +From 54b6ba5f27dd9eb9ec2f1a41e7160964ab94451c Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Wed, 23 Nov 2016 16:52:16 +0800 +Subject: Build tpm as module + +Add --suse-enable-tpm option to grub2-install. + +Index: grub-2.04~rc1/util/grub-install.c +=================================================================== +--- grub-2.04~rc1.orig/util/grub-install.c ++++ grub-2.04~rc1/util/grub-install.c +@@ -80,6 +80,7 @@ static char *label_color; + static char *label_bgcolor; + static char *product_version; + static int add_rs_codes = 1; ++static int suse_enable_tpm = 0; + + enum + { +@@ -106,6 +107,7 @@ enum + OPTION_DISK_MODULE, + OPTION_NO_BOOTSECTOR, + OPTION_NO_RS_CODES, ++ OPTION_SUSE_ENABLE_TPM, + OPTION_MACPPC_DIRECTORY, + OPTION_ZIPL_DIRECTORY, + OPTION_LABEL_FONT, +@@ -231,6 +233,10 @@ argp_parser (int key, char *arg, struct + add_rs_codes = 0; + return 0; + ++ case OPTION_SUSE_ENABLE_TPM: ++ suse_enable_tpm = 1; ++ return 0; ++ + case OPTION_DEBUG: + verbosity++; + return 0; +@@ -292,6 +298,7 @@ static struct argp_option options[] = { + {"no-rs-codes", OPTION_NO_RS_CODES, 0, 0, + N_("Do not apply any reed-solomon codes when embedding core.img. " + "This option is only available on x86 BIOS targets."), 0}, ++ {"suse-enable-tpm", OPTION_SUSE_ENABLE_TPM, 0, 0, N_("install TPM modules"), 0}, + + {"debug", OPTION_DEBUG, 0, OPTION_HIDDEN, 0, 2}, + {"no-floppy", OPTION_NO_FLOPPY, 0, OPTION_HIDDEN, 0, 2}, +@@ -1320,6 +1327,9 @@ main (int argc, char *argv[]) + else if (disk_module && disk_module[0]) + grub_install_push_module (disk_module); + ++ if (suse_enable_tpm && platform == GRUB_INSTALL_PLATFORM_X86_64_EFI) ++ grub_install_push_module ("tpm"); ++ + relative_grubdir = grub_make_system_path_relative_to_its_root (grubdir); + if (relative_grubdir[0] == '\0') + { diff --git a/0012-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch b/0012-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch new file mode 100644 index 0000000..4c96221 --- /dev/null +++ b/0012-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch @@ -0,0 +1,258 @@ +From 27134e18072a9dffb2bda6b74cd312be5360baa0 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 28 Jun 2021 14:16:14 +1000 +Subject: [PATCH 12/32] video/readers/jpeg: Abort sooner if a read operation + fails + +Fuzzing revealed some inputs that were taking a long time, potentially +forever, because they did not bail quickly upon encountering an I/O error. + +Try to catch I/O errors sooner and bail out. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/video/readers/jpeg.c | 86 +++++++++++++++++++++++++++------- + 1 file changed, 70 insertions(+), 16 deletions(-) + +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index e31602f766..10225abd53 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -109,9 +109,17 @@ static grub_uint8_t + grub_jpeg_get_byte (struct grub_jpeg_data *data) + { + grub_uint8_t r; ++ grub_ssize_t bytes_read; + + r = 0; +- grub_file_read (data->file, &r, 1); ++ bytes_read = grub_file_read (data->file, &r, 1); ++ ++ if (bytes_read != 1) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: unexpected end of data"); ++ return 0; ++ } + + return r; + } +@@ -120,9 +128,17 @@ static grub_uint16_t + grub_jpeg_get_word (struct grub_jpeg_data *data) + { + grub_uint16_t r; ++ grub_ssize_t bytes_read; + + r = 0; +- grub_file_read (data->file, &r, sizeof (grub_uint16_t)); ++ bytes_read = grub_file_read (data->file, &r, sizeof (grub_uint16_t)); ++ ++ if (bytes_read != sizeof (grub_uint16_t)) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: unexpected end of data"); ++ return 0; ++ } + + return grub_be_to_cpu16 (r); + } +@@ -135,6 +151,11 @@ grub_jpeg_get_bit (struct grub_jpeg_data *data) + if (data->bit_mask == 0) + { + data->bit_save = grub_jpeg_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: file read error"); ++ return 0; ++ } + if (data->bit_save == JPEG_ESC_CHAR) + { + if (grub_jpeg_get_byte (data) != 0) +@@ -143,6 +164,11 @@ grub_jpeg_get_bit (struct grub_jpeg_data *data) + "jpeg: invalid 0xFF in data stream"); + return 0; + } ++ if (grub_errno != GRUB_ERR_NONE) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: file read error"); ++ return 0; ++ } + } + data->bit_mask = 0x80; + } +@@ -161,7 +187,7 @@ grub_jpeg_get_number (struct grub_jpeg_data *data, int num) + return 0; + + msb = value = grub_jpeg_get_bit (data); +- for (i = 1; i < num; i++) ++ for (i = 1; i < num && grub_errno == GRUB_ERR_NONE; i++) + value = (value << 1) + (grub_jpeg_get_bit (data) != 0); + if (!msb) + value += 1 - (1 << num); +@@ -202,6 +228,8 @@ grub_jpeg_decode_huff_table (struct grub_jpeg_data *data) + while (data->file->offset + sizeof (count) + 1 <= next_marker) + { + id = grub_jpeg_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + ac = (id >> 4) & 1; + id &= 0xF; + if (id > 1) +@@ -252,6 +280,8 @@ grub_jpeg_decode_quan_table (struct grub_jpeg_data *data) + + next_marker = data->file->offset; + next_marker += grub_jpeg_get_word (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + if (next_marker > data->file->size) + { +@@ -263,6 +293,8 @@ grub_jpeg_decode_quan_table (struct grub_jpeg_data *data) + <= next_marker) + { + id = grub_jpeg_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + if (id >= 0x10) /* Upper 4-bit is precision. */ + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: only 8-bit precision is supported"); +@@ -294,6 +326,9 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data) + next_marker = data->file->offset; + next_marker += grub_jpeg_get_word (data); + ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; ++ + if (grub_jpeg_get_byte (data) != 8) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: only 8-bit precision is supported"); +@@ -319,6 +354,8 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); + + ss = grub_jpeg_get_byte (data); /* Sampling factor. */ ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + if (!id) + { + grub_uint8_t vs, hs; +@@ -498,7 +535,7 @@ grub_jpeg_idct_transform (jpeg_data_unit_t du) + } + } + +-static void ++static grub_err_t + grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) + { + int h1, h2, qt; +@@ -513,6 +550,9 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) + data->dc_value[id] += + grub_jpeg_get_number (data, grub_jpeg_get_huff_code (data, h1)); + ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; ++ + du[0] = data->dc_value[id] * (int) data->quan_table[qt][0]; + pos = 1; + while (pos < ARRAY_SIZE (data->quan_table[qt])) +@@ -527,11 +567,13 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) + num >>= 4; + pos += num; + ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; ++ + if (pos >= ARRAY_SIZE (jpeg_zigzag_order)) + { +- grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "jpeg: invalid position in zigzag order!?"); +- return; ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: invalid position in zigzag order!?"); + } + + du[jpeg_zigzag_order[pos]] = val * (int) data->quan_table[qt][pos]; +@@ -539,6 +581,7 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) + } + + grub_jpeg_idct_transform (du); ++ return GRUB_ERR_NONE; + } + + static void +@@ -597,7 +640,8 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) + data_offset += grub_jpeg_get_word (data); + + cc = grub_jpeg_get_byte (data); +- ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + if (cc != 3 && cc != 1) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: component count must be 1 or 3"); +@@ -610,7 +654,8 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) + id = grub_jpeg_get_byte (data) - 1; + if ((id < 0) || (id >= 3)) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); +- ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + ht = grub_jpeg_get_byte (data); + data->comp_index[id][1] = (ht >> 4); + data->comp_index[id][2] = (ht & 0xF) + 2; +@@ -618,11 +663,14 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) + if ((data->comp_index[id][1] < 0) || (data->comp_index[id][1] > 3) || + (data->comp_index[id][2] < 0) || (data->comp_index[id][2] > 3)) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid hufftable index"); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + } + + grub_jpeg_get_byte (data); /* Skip 3 unused bytes. */ + grub_jpeg_get_word (data); +- ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + if (data->file->offset != data_offset) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos"); + +@@ -640,6 +688,7 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data) + { + unsigned c1, vb, hb, nr1, nc1; + int rst = data->dri; ++ grub_err_t err = GRUB_ERR_NONE; + + vb = 8 << data->log_vs; + hb = 8 << data->log_hs; +@@ -660,17 +709,22 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data) + + for (r2 = 0; r2 < (1U << data->log_vs); r2++) + for (c2 = 0; c2 < (1U << data->log_hs); c2++) +- grub_jpeg_decode_du (data, 0, data->ydu[r2 * 2 + c2]); ++ { ++ err = grub_jpeg_decode_du (data, 0, data->ydu[r2 * 2 + c2]); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ } + + if (data->color_components >= 3) + { +- grub_jpeg_decode_du (data, 1, data->cbdu); +- grub_jpeg_decode_du (data, 2, data->crdu); ++ err = grub_jpeg_decode_du (data, 1, data->cbdu); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ err = grub_jpeg_decode_du (data, 2, data->crdu); ++ if (err != GRUB_ERR_NONE) ++ return err; + } + +- if (grub_errno) +- return grub_errno; +- + nr2 = (data->r1 == nr1 - 1) ? (data->image_height - data->r1 * vb) : vb; + nc2 = (c1 == nc1 - 1) ? (data->image_width - c1 * hb) : hb; + +-- +2.34.1 + diff --git a/0013-cryptodisk-Support-key-protectors.patch b/0013-cryptodisk-Support-key-protectors.patch new file mode 100644 index 0000000..a66509e --- /dev/null +++ b/0013-cryptodisk-Support-key-protectors.patch @@ -0,0 +1,336 @@ +From 9888bf40d960339a59dc18fb6e1df5f65b4668e3 Mon Sep 17 00:00:00 2001 +From: Hernan Gatta +Date: Tue, 1 Feb 2022 05:02:56 -0800 +Subject: [PATCH 13/14] cryptodisk: Support key protectors + +Add a new parameter to cryptomount to support the key protectors framework: -k. +The parameter is used to automatically retrieve a key from specified key +protectors. The parameter may be repeated to specify any number of key +protectors. These are tried in order until one provides a usable key for any +given disk. + +Signed-off-by: +--- + Makefile.util.def | 1 + + grub-core/disk/cryptodisk.c | 166 +++++++++++++++++++++++++++++------- + include/grub/cryptodisk.h | 14 +++ + 3 files changed, 151 insertions(+), 30 deletions(-) + +diff --git a/Makefile.util.def b/Makefile.util.def +index ef5c818e0e..b3ec2a4bb6 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -35,6 +35,7 @@ library = { + common = grub-core/kern/list.c; + common = grub-core/kern/misc.c; + common = grub-core/kern/partition.c; ++ common = grub-core/kern/protectors.c; + common = grub-core/lib/crypto.c; + common = grub-core/lib/json/json.c; + common = grub-core/disk/luks.c; +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 497097394f..00c44773fb 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + #ifdef GRUB_UTIL + #include +@@ -42,6 +43,8 @@ static const struct grub_arg_option options[] = + {"all", 'a', 0, N_("Mount all."), 0, 0}, + {"boot", 'b', 0, N_("Mount all volumes with `boot' flag set."), 0, 0}, + {"password", 'p', 0, N_("Password to open volumes."), 0, ARG_TYPE_STRING}, ++ {"protector", 'k', GRUB_ARG_OPTION_REPEATABLE, ++ N_("Unlock volume(s) using key protector(s)."), 0, ARG_TYPE_STRING}, + {0, 0, 0, 0, 0, 0} + }; + +@@ -1000,7 +1003,8 @@ grub_cryptodisk_scan_device_real (const char *name, + { + grub_err_t ret = GRUB_ERR_NONE; + grub_cryptodisk_t dev; +- grub_cryptodisk_dev_t cr; ++ grub_cryptodisk_dev_t cr, crd = NULL; ++ int i; + int askpass = 0; + char *part = NULL; + +@@ -1016,39 +1020,108 @@ grub_cryptodisk_scan_device_real (const char *name, + return NULL; + if (!dev) + continue; ++ crd = cr; ++ } + +- if (!cargs->key_len) +- { +- /* Get the passphrase from the user, if no key data. */ +- askpass = 1; +- part = grub_partition_get_name (source->partition); +- grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, +- source->partition != NULL ? "," : "", +- part != NULL ? part : N_("UNKNOWN"), +- dev->uuid); +- grub_free (part); +- +- cargs->key_data = grub_malloc (GRUB_CRYPTODISK_MAX_PASSPHRASE); +- if (cargs->key_data == NULL) +- return NULL; +- +- if (!grub_password_get ((char *) cargs->key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE)) +- { +- grub_error (GRUB_ERR_BAD_ARGUMENT, "passphrase not supplied"); +- goto error; +- } +- cargs->key_len = grub_strlen ((char *) cargs->key_data); +- } ++ if (!dev) ++ { ++ grub_error (GRUB_ERR_BAD_MODULE, ++ "no cryptodisk module can handle this device"); ++ return NULL; ++ } + +- ret = cr->recover_key (source, dev, cargs); +- if (ret != GRUB_ERR_NONE) ++ if (cargs->protectors) ++ { ++ for (i = 0; cargs->protectors[i]; i++) ++ { ++ if (cargs->key_cache[i].invalid) ++ continue; ++ ++ if (!cargs->key_cache[i].key) ++ { ++ ret = grub_key_protector_recover_key (cargs->protectors[i], ++ &cargs->key_cache[i].key, ++ &cargs->key_cache[i].key_len); ++ if (ret) ++ { ++ if (grub_errno) ++ { ++ grub_print_error (); ++ grub_errno = GRUB_ERR_NONE; ++ } ++ ++ grub_dprintf ("cryptodisk", ++ "failed to recover a key from key protector " ++ "%s, will not try it again for any other " ++ "disks, if any, during this invocation of " ++ "cryptomount\n", ++ cargs->protectors[i]); ++ ++ cargs->key_cache[i].invalid = 1; ++ continue; ++ } ++ } ++ ++ cargs->key_data = cargs->key_cache[i].key; ++ cargs->key_len = cargs->key_cache[i].key_len; ++ ++ ret = crd->recover_key (source, dev, cargs); ++ if (ret) ++ { ++ part = grub_partition_get_name (source->partition); ++ grub_dprintf ("cryptodisk", ++ "recovered a key from key protector %s but it " ++ "failed to unlock %s%s%s (%s)\n", ++ cargs->protectors[i], source->name, ++ source->partition != NULL ? "," : "", ++ part != NULL ? part : N_("UNKNOWN"), dev->uuid); ++ grub_free (part); ++ continue; ++ } ++ else ++ { ++ grub_cryptodisk_insert (dev, name, source); ++ goto cleanup; ++ }; ++ } ++ ++ part = grub_partition_get_name (source->partition); ++ grub_error (GRUB_ERR_ACCESS_DENIED, ++ N_("no key protector provided a usable key for %s%s%s (%s)"), ++ source->name, source->partition != NULL ? "," : "", ++ part != NULL ? part : N_("UNKNOWN"), dev->uuid); ++ grub_free (part); + goto error; ++ } + +- grub_cryptodisk_insert (dev, name, source); ++ if (!cargs->key_len) ++ { ++ /* Get the passphrase from the user, if no key data. */ ++ askpass = 1; ++ part = grub_partition_get_name (source->partition); ++ grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, ++ source->partition != NULL ? "," : "", ++ part != NULL ? part : N_("UNKNOWN"), dev->uuid); ++ grub_free (part); ++ ++ cargs->key_data = grub_malloc (GRUB_CRYPTODISK_MAX_PASSPHRASE); ++ if (cargs->key_data == NULL) ++ goto error; ++ ++ if (!grub_password_get ((char *) cargs->key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE)) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "passphrase not supplied"); ++ goto error; ++ } ++ cargs->key_len = grub_strlen ((char *) cargs->key_data); ++ } ++ ++ ret = crd->recover_key (source, dev, cargs); ++ if (ret != GRUB_ERR_NONE) ++ goto error; ++ ++ grub_cryptodisk_insert (dev, name, source); + +- goto cleanup; +- } +- grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk module can handle this device"); + goto cleanup; + + error: +@@ -1155,6 +1228,20 @@ grub_cryptodisk_scan_device (const char *name, + return ret; + } + ++static void ++grub_cryptodisk_clear_key_cache (struct grub_cryptomount_args *cargs) ++{ ++ int i; ++ ++ if (!cargs->key_cache) ++ return; ++ ++ for (i = 0; cargs->protectors[i]; i++) ++ grub_free (cargs->key_cache[i].key); ++ ++ grub_free (cargs->key_cache); ++} ++ + static grub_err_t + grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + { +@@ -1167,12 +1254,25 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + if (grub_cryptodisk_list == NULL) + return grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk modules loaded"); + ++ if (state[3].set && state[4].set) /* password and key protector */ ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ "a password and a key protector cannot both be set"); ++ + if (state[3].set) /* password */ + { + cargs.key_data = (grub_uint8_t *) state[3].arg; + cargs.key_len = grub_strlen (state[3].arg); + } + ++ if (state[4].set) /* key protector(s) */ ++ { ++ cargs.key_cache = grub_zalloc (state[4].set * sizeof (*cargs.key_cache)); ++ if (!cargs.key_cache) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "no memory for key protector key cache"); ++ cargs.protectors = state[4].args; ++ } ++ + if (state[0].set) /* uuid */ + { + int found_uuid; +@@ -1181,6 +1281,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + dev = grub_cryptodisk_get_by_uuid (args[0]); + if (dev) + { ++ grub_cryptodisk_clear_key_cache (&cargs); + grub_dprintf ("cryptodisk", + "already mounted as crypto%lu\n", dev->id); + return GRUB_ERR_NONE; +@@ -1189,6 +1290,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + cargs.check_boot = state[2].set; + cargs.search_uuid = args[0]; + found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, &cargs); ++ grub_cryptodisk_clear_key_cache (&cargs); + + if (found_uuid) + return GRUB_ERR_NONE; +@@ -1208,6 +1310,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + { + cargs.check_boot = state[2].set; + grub_device_iterate (&grub_cryptodisk_scan_device, &cargs); ++ grub_cryptodisk_clear_key_cache (&cargs); + return GRUB_ERR_NONE; + } + else +@@ -1231,6 +1334,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + disk = grub_disk_open (diskname); + if (!disk) + { ++ grub_cryptodisk_clear_key_cache (&cargs); + if (disklast) + *disklast = ')'; + return grub_errno; +@@ -1241,12 +1345,14 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + { + grub_dprintf ("cryptodisk", "already mounted as crypto%lu\n", dev->id); + grub_disk_close (disk); ++ grub_cryptodisk_clear_key_cache (&cargs); + if (disklast) + *disklast = ')'; + return GRUB_ERR_NONE; + } + + dev = grub_cryptodisk_scan_device_real (diskname, disk, &cargs); ++ grub_cryptodisk_clear_key_cache (&cargs); + + grub_disk_close (disk); + if (disklast) +@@ -1385,7 +1491,7 @@ GRUB_MOD_INIT (cryptodisk) + { + grub_disk_dev_register (&grub_cryptodisk_dev); + cmd = grub_register_extcmd ("cryptomount", grub_cmd_cryptomount, 0, +- N_("[-p password] "), ++ N_("[-p password] [-k protector [-k protector ...]] "), + N_("Mount a crypto device."), options); + grub_procfs_register ("luks_script", &luks_script); + } +diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h +index c6524c9ea9..b556498fba 100644 +--- a/include/grub/cryptodisk.h ++++ b/include/grub/cryptodisk.h +@@ -67,6 +67,16 @@ typedef gcry_err_code_t + (*grub_cryptodisk_rekey_func_t) (struct grub_cryptodisk *dev, + grub_uint64_t zoneno); + ++struct grub_cryptomount_cached_key ++{ ++ grub_uint8_t *key; ++ grub_size_t key_len; ++ ++ /* The key protector associated with this cache entry failed, so avoid it ++ * even if the cached entry (an instance of this structure) is empty. */ ++ int invalid; ++}; ++ + struct grub_cryptomount_args + { + /* scan: Flag to indicate that only bootable volumes should be decrypted */ +@@ -77,6 +87,10 @@ struct grub_cryptomount_args + grub_uint8_t *key_data; + /* recover_key: Length of key_data */ + grub_size_t key_len; ++ /* recover_key: Names of the key protectors to use (NULL-terminated) */ ++ char **protectors; ++ /* recover_key: Key cache to avoid invoking the same key protector twice */ ++ struct grub_cryptomount_cached_key *key_cache; + }; + typedef struct grub_cryptomount_args *grub_cryptomount_args_t; + +-- +2.34.1 + diff --git a/0013-libtasn1-changes-for-grub-compatibility.patch b/0013-libtasn1-changes-for-grub-compatibility.patch new file mode 100644 index 0000000..097de0f --- /dev/null +++ b/0013-libtasn1-changes-for-grub-compatibility.patch @@ -0,0 +1,212 @@ +From f05ba09c9adea447d3ca837c73498b9619306180 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 1 May 2020 20:44:29 +1000 +Subject: [PATCH 13/23] libtasn1: changes for grub compatibility + +Do a few things to make libtasn1 compile as part of grub: + + - redefine _asn1_strcat. grub removed strcat so replace it with the + appropriate calls to memcpy and strlen. Use this internally where + strcat was used. + + - replace c_isdigit with grub_isdigit (and don't import c-ctype from + gnulib) grub_isdigit provides the same functionality as c_isdigit: it + determines if the input is an ASCII digit without regard for locale. + + - replace GL_ATTRIBUTE_PURE with __attribute__((pure)) which been + supported since gcc-2.96. This avoids messing around with gnulib. + + - adjust libtasn1.h: drop the ASN1_API logic, it's not needed for our + modules. Unconditionally support const and pure attributes and adjust + header paths. + + - adjust header paths to "grub/libtasn1.h". + + - replace a 64 bit division with a call to grub_divmod64, preventing + creation of __udivdi3 calls on 32 bit platforms. + +Signed-off-by: Daniel Axtens + +--- + +v2: Clean up strcat handling, thanks Stefan Berger. +--- + grub-core/lib/libtasn1/lib/decoding.c | 11 +++++----- + grub-core/lib/libtasn1/lib/element.c | 3 ++- + grub-core/lib/libtasn1/lib/gstr.c | 4 ++-- + grub-core/lib/libtasn1/lib/int.h | 4 ++-- + grub-core/lib/libtasn1/lib/parser_aux.c | 7 +++--- + include/grub/libtasn1.h | 29 +++++++------------------ + 6 files changed, 24 insertions(+), 34 deletions(-) + +diff --git a/grub-core/lib/libtasn1/lib/decoding.c b/grub-core/lib/libtasn1/lib/decoding.c +index b8130b956..beeb6a176 100644 +--- a/grub-core/lib/libtasn1/lib/decoding.c ++++ b/grub-core/lib/libtasn1/lib/decoding.c +@@ -32,7 +32,8 @@ + #include + #include + #include +-#include "c-ctype.h" ++ ++#define c_isdigit grub_isdigit + + #ifdef DEBUG + # define warn() fprintf(stderr, "%s: %d\n", __func__, __LINE__) +@@ -2016,8 +2017,8 @@ asn1_expand_octet_string (asn1_node_const definitions, asn1_node * element, + (p2->type & CONST_ASSIGN)) + { + strcpy (name, definitions->name); +- strcat (name, "."); +- strcat (name, p2->name); ++ _asn1_strcat (name, "."); ++ _asn1_strcat (name, p2->name); + + len = sizeof (value); + result = asn1_read_value (definitions, name, value, &len); +@@ -2034,8 +2035,8 @@ asn1_expand_octet_string (asn1_node_const definitions, asn1_node * element, + if (p2) + { + strcpy (name, definitions->name); +- strcat (name, "."); +- strcat (name, p2->name); ++ _asn1_strcat (name, "."); ++ _asn1_strcat (name, p2->name); + + result = asn1_create_element (definitions, name, &aux); + if (result == ASN1_SUCCESS) +diff --git a/grub-core/lib/libtasn1/lib/element.c b/grub-core/lib/libtasn1/lib/element.c +index 8cd6b662c..150b9b377 100644 +--- a/grub-core/lib/libtasn1/lib/element.c ++++ b/grub-core/lib/libtasn1/lib/element.c +@@ -30,9 +30,10 @@ + #include "parser_aux.h" + #include + #include "structure.h" +-#include "c-ctype.h" + #include "element.h" + ++#define c_isdigit grub_isdigit ++ + void + _asn1_hierarchical_name (asn1_node_const node, char *name, int name_size) + { +diff --git a/grub-core/lib/libtasn1/lib/gstr.c b/grub-core/lib/libtasn1/lib/gstr.c +index 1475ed51b..b729089db 100644 +--- a/grub-core/lib/libtasn1/lib/gstr.c ++++ b/grub-core/lib/libtasn1/lib/gstr.c +@@ -36,13 +36,13 @@ _asn1_str_cat (char *dest, size_t dest_tot_size, const char *src) + + if (dest_tot_size - dest_size > str_size) + { +- strcat (dest, src); ++ _asn1_strcat (dest, src); + } + else + { + if (dest_tot_size > dest_size) + { +- strncat (dest, src, (dest_tot_size - dest_size) - 1); ++ memcpy (dest + dest_size, src, (dest_tot_size - dest_size) - 1); + dest[dest_tot_size - 1] = 0; + } + } +diff --git a/grub-core/lib/libtasn1/lib/int.h b/grub-core/lib/libtasn1/lib/int.h +index 404cd1562..edfe84a0e 100644 +--- a/grub-core/lib/libtasn1/lib/int.h ++++ b/grub-core/lib/libtasn1/lib/int.h +@@ -35,7 +35,7 @@ + # include + # endif + +-# include ++# include "grub/libtasn1.h" + + # define ASN1_SMALL_VALUE_SIZE 16 + +@@ -115,7 +115,7 @@ extern const tag_and_class_st _asn1_tags[]; + # define _asn1_strtoul(n,e,b) strtoul((const char *) n, e, b) + # define _asn1_strcmp(a,b) strcmp((const char *)a, (const char *)b) + # define _asn1_strcpy(a,b) strcpy((char *)a, (const char *)b) +-# define _asn1_strcat(a,b) strcat((char *)a, (const char *)b) ++# define _asn1_strcat(a,b) memcpy((char *)a + strlen((const char *)a), (const char *)b, strlen((const char *)b) + 1) + + # if SIZEOF_UNSIGNED_LONG_INT == 8 + # define _asn1_strtou64(n,e,b) strtoul((const char *) n, e, b) +diff --git a/grub-core/lib/libtasn1/lib/parser_aux.c b/grub-core/lib/libtasn1/lib/parser_aux.c +index c99c5a4cb..a933f03ed 100644 +--- a/grub-core/lib/libtasn1/lib/parser_aux.c ++++ b/grub-core/lib/libtasn1/lib/parser_aux.c +@@ -26,7 +26,8 @@ + #include "gstr.h" + #include "structure.h" + #include "element.h" +-#include "c-ctype.h" ++ ++#define c_isdigit grub_isdigit + + char _asn1_identifierMissing[ASN1_MAX_NAME_SIZE + 1]; /* identifier name not found */ + +@@ -40,7 +41,7 @@ char _asn1_identifierMissing[ASN1_MAX_NAME_SIZE + 1]; /* identifier name not fou + #ifdef __clang__ + __attribute__((no_sanitize ("integer"))) + #endif +- _GL_ATTRIBUTE_PURE static unsigned int _asn1_hash_name (const char *x) ++ __attribute__((__pure__)) static unsigned int _asn1_hash_name (const char *x) + { + const unsigned char *s = (unsigned char *) x; + unsigned h = 0; +@@ -632,7 +633,7 @@ _asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE]) + count = 0; + do + { +- d = val / 10; ++ d = grub_divmod64(val, 10, NULL); + r = val - d * 10; + temp[start + count] = '0' + (char) r; + count++; +diff --git a/include/grub/libtasn1.h b/include/grub/libtasn1.h +index 0c3a44881..2ea058a3b 100644 +--- a/include/grub/libtasn1.h ++++ b/include/grub/libtasn1.h +@@ -34,29 +34,16 @@ + #ifndef LIBTASN1_H + # define LIBTASN1_H + +-# ifndef ASN1_API +-# if defined ASN1_BUILDING && defined HAVE_VISIBILITY && HAVE_VISIBILITY +-# define ASN1_API __attribute__((__visibility__("default"))) +-# elif defined ASN1_BUILDING && defined _MSC_VER && ! defined ASN1_STATIC +-# define ASN1_API __declspec(dllexport) +-# elif defined _MSC_VER && ! defined ASN1_STATIC +-# define ASN1_API __declspec(dllimport) +-# else +-# define ASN1_API +-# endif +-# endif ++/* grub: ASN1_API is not used */ ++# define ASN1_API ++ ++/* grub: all our supported compilers support these attributes */ ++# define __LIBTASN1_CONST__ __attribute__((const)) ++# define __LIBTASN1_PURE__ __attribute__((pure)) + +-# ifdef __GNUC__ +-# define __LIBTASN1_CONST__ __attribute__((const)) +-# define __LIBTASN1_PURE__ __attribute__((pure)) +-# else +-# define __LIBTASN1_CONST__ +-# define __LIBTASN1_PURE__ +-# endif + +-# include +-# include +-# include /* for FILE* */ ++# include ++# include + + # ifdef __cplusplus + extern "C" +-- +2.31.1 + diff --git a/0013-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch b/0013-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch new file mode 100644 index 0000000..9aee5ee --- /dev/null +++ b/0013-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch @@ -0,0 +1,32 @@ +From 8f8282090a1d1469bffd0db6a07275882628caeb Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 28 Jun 2021 14:16:58 +1000 +Subject: [PATCH 13/32] video/readers/jpeg: Do not reallocate a given huff + table + +Fix a memory leak where an invalid file could cause us to reallocate +memory for a huffman table we had already allocated memory for. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/video/readers/jpeg.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index 10225abd53..caa211f06d 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -245,6 +245,9 @@ grub_jpeg_decode_huff_table (struct grub_jpeg_data *data) + n += count[i]; + + id += ac * 2; ++ if (data->huff_value[id] != NULL) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: attempt to reallocate huffman table"); + data->huff_value[id] = grub_malloc (n); + if (grub_errno) + return grub_errno; +-- +2.34.1 + diff --git a/0014-libtasn1-compile-into-asn1-module.patch b/0014-libtasn1-compile-into-asn1-module.patch new file mode 100644 index 0000000..e725712 --- /dev/null +++ b/0014-libtasn1-compile-into-asn1-module.patch @@ -0,0 +1,73 @@ +From f3b818444fe8628d581f5efe23d55554f23718c8 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 5 Jun 2020 17:47:25 +1000 +Subject: [PATCH 14/23] libtasn1: compile into asn1 module + +Create a wrapper file that specifies the module license. +Set up the makefile so it is built. + +Signed-off-by: Daniel Axtens +--- + grub-core/Makefile.core.def | 15 +++++++++++++++ + grub-core/lib/libtasn1_wrap/wrap.c | 26 ++++++++++++++++++++++++++ + 2 files changed, 41 insertions(+) + create mode 100644 grub-core/lib/libtasn1_wrap/wrap.c + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 5525aa194..f0df8ed94 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2575,3 +2575,18 @@ module = { + name = cmdline; + common = lib/cmdline.c; + }; ++ ++module = { ++ name = asn1; ++ common = lib/libtasn1/lib/decoding.c; ++ common = lib/libtasn1/lib/coding.c; ++ common = lib/libtasn1/lib/element.c; ++ common = lib/libtasn1/lib/structure.c; ++ common = lib/libtasn1/lib/parser_aux.c; ++ common = lib/libtasn1/lib/gstr.c; ++ common = lib/libtasn1/lib/errors.c; ++ common = lib/libtasn1_wrap/wrap.c; ++ cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)'; ++ // -Wno-type-limits comes from libtasn1's configure.ac ++ cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB) -I$(srcdir)/lib/libtasn1/lib -Wno-type-limits'; ++}; +diff --git a/grub-core/lib/libtasn1_wrap/wrap.c b/grub-core/lib/libtasn1_wrap/wrap.c +new file mode 100644 +index 000000000..622ba942e +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/wrap.c +@@ -0,0 +1,26 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 IBM Corporation ++ * ++ * 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 . ++ */ ++ ++#include ++ ++/* ++ * libtasn1 is provided under LGPL2.1+, which is compatible ++ * with GPL3+. As Grub as a whole is under GPL3+, this module ++ * is therefore under GPL3+ also. ++ */ ++GRUB_MOD_LICENSE ("GPLv3+"); +-- +2.31.1 + diff --git a/0014-util-grub-protect-Add-new-tool.patch b/0014-util-grub-protect-Add-new-tool.patch new file mode 100644 index 0000000..e3d0692 --- /dev/null +++ b/0014-util-grub-protect-Add-new-tool.patch @@ -0,0 +1,1408 @@ +From a913983cb75594e08b425e3c099185b2f4187663 Mon Sep 17 00:00:00 2001 +From: Hernan Gatta +Date: Tue, 1 Feb 2022 05:02:57 -0800 +Subject: [PATCH 14/14] util/grub-protect: Add new tool + +To utilize the key protectors framework, there must be a way to protect +full-disk encryption keys in the first place. The grub-protect tool includes +support for the TPM2 key protector but other protectors that require setup ahead +of time can be supported in the future. + +For the TPM2 key protector, the intended flow is for a user to have a LUKS 1 or +LUKS 2-protected fully-encrypted disk. The user then creates a new key file, say +by reading /dev/urandom into a file, and creates a new LUKS key slot for this +key. Then, the user invokes the grub-protect tool to seal this key file to a set +of PCRs using the system's TPM 2.0. The resulting sealed key file is stored in +an unencrypted partition such as the EFI System Partition (ESP) so that GRUB may +read it. The user also ensures the cryptomount command is included in GRUB's +boot script and that it carries the requisite key protector (-k) parameter. + +Sample usage: + +$ dd if=/dev/urandom of=key bs=1 count=32 +$ sudo cryptsetup luksAddKey /dev/sdb1 key --pbkdf=pbkdf2 --hash=sha512 + +$ sudo grub-protect --action=add + --protector=tpm2 + --tpm2-keyfile=key + --tpm2-outfile=/boot/efi/boot/grub2/sealed_key + +Then, in the boot script: + +tpm2_key_protector_init -k (hd0,gpt1)/boot/grub2/sealed_key +cryptomount -u b20f95d0834842bc9197bd78b36732f8 -k tpm2 + +where the UUID corresponds to /dev/sdb1. + +Signed-off-by: Hernan Gatta +--- + Makefile.util.def | 18 + + configure.ac | 1 + + util/grub-protect.c | 1314 +++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 1334 insertions(+) + create mode 100644 util/grub-protect.c + +diff --git a/Makefile.util.def b/Makefile.util.def +index b3ec2a4bb6..08f681cd8b 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -207,6 +207,24 @@ program = { + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; + }; + ++program = { ++ name = grub-protect; ++ ++ common = grub-core/osdep/init.c; ++ common = grub-core/tpm2/args.c; ++ common = grub-core/tpm2/buffer.c; ++ common = grub-core/tpm2/mu.c; ++ common = grub-core/tpm2/tpm2.c; ++ common = util/grub-protect.c; ++ common = util/probe.c; ++ ++ ldadd = libgrubmods.a; ++ ldadd = libgrubgcry.a; ++ ldadd = libgrubkern.a; ++ ldadd = grub-core/lib/gnulib/libgnu.a; ++ ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ++}; ++ + program = { + name = grub-mkrelpath; + mansection = 1; +diff --git a/configure.ac b/configure.ac +index 906eb1cedc..ba717a9600 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -71,6 +71,7 @@ grub_TRANSFORM([grub-mkpasswd-pbkdf2]) + grub_TRANSFORM([grub-mkrelpath]) + grub_TRANSFORM([grub-mkrescue]) + grub_TRANSFORM([grub-probe]) ++grub_TRANSFORM([grub-protect]) + grub_TRANSFORM([grub-reboot]) + grub_TRANSFORM([grub-script-check]) + grub_TRANSFORM([grub-set-default]) +diff --git a/util/grub-protect.c b/util/grub-protect.c +new file mode 100644 +index 0000000000..23ee78d32a +--- /dev/null ++++ b/util/grub-protect.c +@@ -0,0 +1,1314 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * 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 . ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#pragma GCC diagnostic ignored "-Wmissing-prototypes" ++#pragma GCC diagnostic ignored "-Wmissing-declarations" ++#include ++#pragma GCC diagnostic error "-Wmissing-prototypes" ++#pragma GCC diagnostic error "-Wmissing-declarations" ++ ++#include "progname.h" ++ ++/* Unprintable option keys for argp */ ++typedef enum grub_protect_opt ++{ ++ /* General */ ++ GRUB_PROTECT_OPT_ACTION = 'a', ++ GRUB_PROTECT_OPT_PROTECTOR = 'p', ++ /* TPM2 */ ++ GRUB_PROTECT_OPT_TPM2_DEVICE = 0x100, ++ GRUB_PROTECT_OPT_TPM2_PCRS, ++ GRUB_PROTECT_OPT_TPM2_ASYMMETRIC, ++ GRUB_PROTECT_OPT_TPM2_BANK, ++ GRUB_PROTECT_OPT_TPM2_SRK, ++ GRUB_PROTECT_OPT_TPM2_KEYFILE, ++ GRUB_PROTECT_OPT_TPM2_OUTFILE, ++ GRUB_PROTECT_OPT_TPM2_PERSIST, ++ GRUB_PROTECT_OPT_TPM2_EVICT ++} grub_protect_opt; ++ ++/* Option flags to keep track of specified arguments */ ++typedef enum grub_protect_arg ++{ ++ /* General */ ++ GRUB_PROTECT_ARG_ACTION = 1 << 0, ++ GRUB_PROTECT_ARG_PROTECTOR = 1 << 1, ++ /* TPM2 */ ++ GRUB_PROTECT_ARG_TPM2_DEVICE = 1 << 2, ++ GRUB_PROTECT_ARG_TPM2_PCRS = 1 << 3, ++ GRUB_PROTECT_ARG_TPM2_ASYMMETRIC = 1 << 4, ++ GRUB_PROTECT_ARG_TPM2_BANK = 1 << 5, ++ GRUB_PROTECT_ARG_TPM2_SRK = 1 << 6, ++ GRUB_PROTECT_ARG_TPM2_KEYFILE = 1 << 7, ++ GRUB_PROTECT_ARG_TPM2_OUTFILE = 1 << 8, ++ GRUB_PROTECT_ARG_TPM2_PERSIST = 1 << 9, ++ GRUB_PROTECT_ARG_TPM2_EVICT = 1 << 10 ++} grub_protect_arg_t; ++ ++typedef enum grub_protect_protector ++{ ++ GRUB_PROTECT_TYPE_ERROR, ++ GRUB_PROTECT_TYPE_TPM2 ++} grub_protect_protector_t; ++ ++typedef enum grub_protect_action ++{ ++ GRUB_PROTECT_ACTION_ERROR, ++ GRUB_PROTECT_ACTION_ADD, ++ GRUB_PROTECT_ACTION_REMOVE ++} grub_protect_action_t; ++ ++struct grub_protect_args ++{ ++ grub_protect_arg_t args; ++ grub_protect_action_t action; ++ grub_protect_protector_t protector; ++ ++ const char *tpm2_device; ++ grub_uint8_t tpm2_pcrs[TPM_MAX_PCRS]; ++ grub_uint8_t tpm2_pcr_count; ++ TPM_ALG_ID tpm2_asymmetric; ++ TPM_ALG_ID tpm2_bank; ++ TPM_HANDLE tpm2_srk; ++ const char *tpm2_keyfile; ++ const char *tpm2_outfile; ++ int tpm2_persist; ++ int tpm2_evict; ++}; ++ ++static struct argp_option grub_protect_options[] = ++ { ++ /* Top-level options */ ++ { ++ .name = "action", ++ .key = 'a', ++ .arg = "ADD|REMOVE", ++ .flags = 0, ++ .doc = ++ N_("Add or remove a key protector to or from a key."), ++ .group = 0 ++ }, ++ { ++ .name = "protector", ++ .key = 'p', ++ .arg = "TPM2", ++ .flags = 0, ++ .doc = ++ N_("Key protector to use (only TPM2 is currently supported)."), ++ .group = 0 ++ }, ++ /* TPM2 key protector options */ ++ { ++ .name = "tpm2-device", ++ .key = GRUB_PROTECT_OPT_TPM2_DEVICE, ++ .arg = "FILE", ++ .flags = 0, ++ .doc = ++ N_("Path to the TPM2 device (default is /dev/tpm0)."), ++ .group = 0 ++ }, ++ { ++ .name = "tpm2-pcrs", ++ .key = GRUB_PROTECT_OPT_TPM2_PCRS, ++ .arg = "0[,1]...", ++ .flags = 0, ++ .doc = ++ N_("Comma-separated list of PCRs used to authorize key release " ++ "(e.g., '7,11', default is 7."), ++ .group = 0 ++ }, ++ { ++ .name = "tpm2-bank", ++ .key = GRUB_PROTECT_OPT_TPM2_BANK, ++ .arg = "SHA1|SHA256|SHA384", ++ .flags = 0, ++ .doc = ++ N_("Bank of PCRs used to authorize key release: " ++ "SHA1, SHA256 (default), or SHA384."), ++ .group = 0 ++ }, ++ { ++ .name = "tpm2-keyfile", ++ .key = GRUB_PROTECT_OPT_TPM2_KEYFILE, ++ .arg = "FILE", ++ .flags = 0, ++ .doc = ++ N_("Path to a file that contains the cleartext key to protect."), ++ .group = 0 ++ }, ++ { ++ .name = "tpm2-outfile", ++ .key = GRUB_PROTECT_OPT_TPM2_OUTFILE, ++ .arg = "FILE", ++ .flags = 0, ++ .doc = ++ N_("Path to the file that will contain the key after sealing (must be " ++ "accessible to GRUB during boot)."), ++ .group = 0 ++ }, ++ { ++ .name = "tpm2-srk", ++ .key = GRUB_PROTECT_OPT_TPM2_SRK, ++ .arg = "NUM", ++ .flags = 0, ++ .doc = ++ N_("The SRK handle if the SRK is to be made persistent " ++ "(default is 0x81000001)."), ++ .group = 0 ++ }, ++ { ++ .name = "tpm2-asymmetric", ++ .key = GRUB_PROTECT_OPT_TPM2_ASYMMETRIC, ++ .arg = "RSA|ECC", ++ .flags = 0, ++ .doc = ++ N_("The type of SRK: RSA (default) or ECC."), ++ .group = 0 ++ }, ++ { ++ .name = "tpm2-persist", ++ .key = GRUB_PROTECT_OPT_TPM2_PERSIST, ++ .arg = NULL, ++ .flags = 0, ++ .doc = ++ N_("Whether to persist the SRK onto the TPM, otherwise it is recreated " ++ "ephemerally during boot (default is to not persist it)."), ++ .group = 0 ++ }, ++ { ++ .name = "tpm2-evict", ++ .key = GRUB_PROTECT_OPT_TPM2_EVICT, ++ .arg = NULL, ++ .flags = 0, ++ .doc = ++ N_("Evict a previously persisted SRK from the TPM, if any."), ++ .group = 0 ++ }, ++ /* End of list */ ++ { 0, 0, 0, 0, 0, 0 } ++ }; ++ ++static int grub_protector_tpm2_fd = -1; ++ ++static grub_err_t ++grub_protect_read_file (const char *filepath, void **buffer, ++ size_t *buffer_size) ++{ ++ grub_err_t err; ++ FILE *f; ++ long len; ++ void *buf; ++ ++ f = fopen (filepath, "rb"); ++ if (!f) ++ return GRUB_ERR_FILE_NOT_FOUND; ++ ++ if (fseek (f, 0, SEEK_END)) ++ { ++ err = GRUB_ERR_FILE_READ_ERROR; ++ goto exit1; ++ } ++ ++ len = ftell (f); ++ if (!len) ++ { ++ err = GRUB_ERR_FILE_READ_ERROR; ++ goto exit1; ++ } ++ ++ rewind (f); ++ ++ buf = grub_malloc (len); ++ if (!buf) ++ { ++ err = GRUB_ERR_OUT_OF_MEMORY; ++ goto exit1; ++ } ++ ++ if (fread (buf, len, 1, f) != 1) ++ { ++ err = GRUB_ERR_FILE_READ_ERROR; ++ goto exit2; ++ } ++ ++ *buffer = buf; ++ *buffer_size = len; ++ ++ buf = NULL; ++ err = GRUB_ERR_NONE; ++ ++exit2: ++ grub_free (buf); ++ ++exit1: ++ fclose (f); ++ ++ return err; ++} ++ ++static grub_err_t ++grub_protect_write_file (const char *filepath, void *buffer, size_t buffer_size) ++{ ++ grub_err_t err; ++ FILE *f; ++ ++ f = fopen (filepath, "wb"); ++ if (!f) ++ return GRUB_ERR_FILE_NOT_FOUND; ++ ++ if (fwrite (buffer, buffer_size, 1, f) != 1) ++ { ++ err = GRUB_ERR_WRITE_ERROR; ++ goto exit1; ++ } ++ ++ err = GRUB_ERR_NONE; ++ ++exit1: ++ fclose (f); ++ ++ return err; ++} ++ ++static grub_err_t ++grub_protect_get_grub_drive_for_file (const char *filepath, char **drive) ++{ ++ grub_err_t err = GRUB_ERR_IO; ++ char *disk; ++ char **devices; ++ char *grub_dev; ++ char *grub_path; ++ char *efi_drive; ++ char *partition; ++ char *grub_drive; ++ grub_device_t dev; ++ grub_size_t grub_drive_len; ++ int n; ++ ++ grub_path = grub_canonicalize_file_name (filepath); ++ if (!grub_path) ++ goto exit1; ++ ++ devices = grub_guess_root_devices (grub_path); ++ if (!devices || !devices[0]) ++ goto exit2; ++ ++ disk = devices[0]; ++ ++ grub_util_pull_device (disk); ++ ++ grub_dev = grub_util_get_grub_dev (disk); ++ if (!grub_dev) ++ goto exit3; ++ ++ dev = grub_device_open (grub_dev); ++ if (!dev) ++ goto exit4; ++ ++ efi_drive = grub_util_guess_efi_drive (disk); ++ if (!efi_drive) ++ goto exit5; ++ ++ partition = grub_partition_get_name (dev->disk->partition); ++ if (!partition) ++ goto exit6; ++ ++ grub_drive_len = grub_strlen (efi_drive) + grub_strlen (partition) + 3; ++ grub_drive = grub_malloc (grub_drive_len + 1); ++ if (!grub_drive) ++ goto exit7; ++ ++ n = grub_snprintf (grub_drive, grub_drive_len + 1, "(%s,%s)", efi_drive, ++ partition); ++ if (n != grub_drive_len) ++ goto exit8; ++ ++ *drive = grub_drive; ++ grub_drive = NULL; ++ err = GRUB_ERR_NONE; ++ ++exit8: ++ grub_free (grub_drive); ++ ++exit7: ++ grub_free (partition); ++ ++exit6: ++ grub_free (efi_drive); ++ ++exit5: ++ grub_device_close (dev); ++ ++exit4: ++ grub_free (grub_dev); ++ ++exit3: ++ grub_free (devices); ++ ++exit2: ++ grub_free (grub_path); ++ ++exit1: ++ return err; ++} ++ ++grub_err_t ++grub_tcg2_get_max_output_size (grub_size_t *size) ++{ ++ if (!size) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ *size = GRUB_TPM2_BUFFER_CAPACITY; ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_tcg2_submit_command (grub_size_t input_size, grub_uint8_t *input, ++ grub_size_t output_size, grub_uint8_t *output) ++{ ++ static const grub_size_t header_size = sizeof (grub_uint16_t) + ++ (2 * sizeof(grub_uint32_t)); ++ ++ if (write (grub_protector_tpm2_fd, input, input_size) != input_size) ++ return GRUB_ERR_BAD_DEVICE; ++ ++ if (read (grub_protector_tpm2_fd, output, output_size) < header_size) ++ return GRUB_ERR_BAD_DEVICE; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_protect_tpm2_open_device (const char *dev_node) ++{ ++ if (grub_protector_tpm2_fd != -1) ++ return GRUB_ERR_NONE; ++ ++ grub_protector_tpm2_fd = open (dev_node, O_RDWR); ++ if (grub_protector_tpm2_fd == -1) ++ { ++ fprintf (stderr, _("Could not open TPM device (Error: %u).\n"), errno); ++ return GRUB_ERR_FILE_NOT_FOUND; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_protect_tpm2_close_device (void) ++{ ++ int err; ++ ++ if (grub_protector_tpm2_fd == -1) ++ return GRUB_ERR_NONE; ++ ++ err = close (grub_protector_tpm2_fd); ++ if (err) ++ { ++ fprintf (stderr, _("Could not close TPM device (Error: %u).\n"), errno); ++ return GRUB_ERR_IO; ++ } ++ ++ grub_protector_tpm2_fd = -1; ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_protect_tpm2_get_policy_digest (struct grub_protect_args *args, ++ TPM2B_DIGEST *digest) ++{ ++ TPM_RC rc; ++ TPML_PCR_SELECTION pcr_sel = { ++ .count = 1, ++ .pcrSelections = { ++ { ++ .hash = args->tpm2_bank, ++ .sizeOfSelect = 3, ++ .pcrSelect = { 0 } ++ }, ++ } ++ }; ++ TPML_PCR_SELECTION pcr_sel_out = { 0 }; ++ TPML_DIGEST pcr_values = { 0 }; ++ grub_uint8_t *pcr_digest; ++ grub_size_t pcr_digest_len; ++ grub_uint8_t *pcr_concat; ++ grub_size_t pcr_concat_len; ++ grub_uint8_t *pcr_cursor; ++ const gcry_md_spec_t *hash_spec; ++ TPM2B_NONCE nonce = { 0 }; ++ TPM2B_ENCRYPTED_SECRET salt = { 0 }; ++ TPMT_SYM_DEF symmetric = { 0 }; ++ TPMI_SH_AUTH_SESSION session = 0; ++ TPM2B_DIGEST pcr_digest_in = { ++ .size = TPM_SHA256_DIGEST_SIZE, ++ .buffer = { 0 } ++ }; ++ TPM2B_DIGEST policy_digest = { 0 }; ++ grub_uint8_t i; ++ grub_err_t err; ++ ++ /* PCR Read */ ++ for (i = 0; i < args->tpm2_pcr_count; i++) ++ pcr_sel ++ .pcrSelections[0] ++ .pcrSelect[TPM2_PCR_TO_SELECT(args->tpm2_pcrs[i])] ++ |= TPM2_PCR_TO_BIT(args->tpm2_pcrs[i]); ++ ++ rc = TPM2_PCR_Read (NULL, &pcr_sel, NULL, &pcr_sel_out, &pcr_values, NULL); ++ if (rc != TPM_RC_SUCCESS) ++ { ++ fprintf (stderr, _("Failed to read PCRs (TPM error: 0x%x).\n"), rc); ++ return GRUB_ERR_BAD_DEVICE; ++ } ++ ++ if ((pcr_sel_out.count != pcr_sel.count) || ++ (pcr_sel.pcrSelections[0].sizeOfSelect != ++ pcr_sel_out.pcrSelections[0].sizeOfSelect)) ++ { ++ fprintf (stderr, _("Could not read all the specified PCRs.\n")); ++ return GRUB_ERR_BAD_DEVICE; ++ } ++ ++ /* Compute PCR Digest */ ++ switch (args->tpm2_bank) ++ { ++ case TPM_ALG_SHA1: ++ pcr_digest_len = TPM_SHA1_DIGEST_SIZE; ++ hash_spec = GRUB_MD_SHA1; ++ break; ++ case TPM_ALG_SHA256: ++ pcr_digest_len = TPM_SHA256_DIGEST_SIZE; ++ hash_spec = GRUB_MD_SHA256; ++ break; ++ default: ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ pcr_digest = grub_malloc (pcr_digest_len); ++ if (!pcr_digest) ++ { ++ fprintf (stderr, _("Failed to allocate PCR digest buffer.\n")); ++ return GRUB_ERR_OUT_OF_MEMORY; ++ } ++ ++ pcr_concat_len = pcr_digest_len * args->tpm2_pcr_count; ++ pcr_concat = grub_malloc (pcr_concat_len); ++ if (!pcr_concat) ++ { ++ err = GRUB_ERR_OUT_OF_MEMORY; ++ fprintf (stderr, _("Failed to allocate PCR concatenation buffer.\n")); ++ goto exit1; ++ } ++ ++ pcr_cursor = pcr_concat; ++ for (i = 0; i < args->tpm2_pcr_count; i++) ++ { ++ if (pcr_values.digests[i].size != pcr_digest_len) ++ { ++ fprintf (stderr, ++ _("Bad PCR value size: expected %lu bytes but got %u bytes.\n"), ++ pcr_digest_len, pcr_values.digests[i].size); ++ goto exit2; ++ } ++ ++ grub_memcpy (pcr_cursor, pcr_values.digests[i].buffer, pcr_digest_len); ++ pcr_cursor += pcr_digest_len; ++ } ++ ++ grub_crypto_hash (hash_spec, pcr_digest, pcr_concat, pcr_concat_len); ++ ++ /* Start Trial Session */ ++ nonce.size = TPM_SHA256_DIGEST_SIZE; ++ symmetric.algorithm = TPM_ALG_NULL; ++ ++ rc = TPM2_StartAuthSession (TPM_RH_NULL, TPM_RH_NULL, 0, &nonce, &salt, ++ TPM_SE_TRIAL, &symmetric, TPM_ALG_SHA256, ++ &session, NULL, 0); ++ if (rc != TPM_RC_SUCCESS) ++ { ++ fprintf (stderr, ++ _("Failed to start trial policy session (TPM error: 0x%x).\n"), ++ rc); ++ err = GRUB_ERR_BAD_DEVICE; ++ goto exit2; ++ } ++ ++ /* PCR Policy */ ++ memcpy (pcr_digest_in.buffer, pcr_digest, TPM_SHA256_DIGEST_SIZE); ++ ++ rc = TPM2_PolicyPCR (session, NULL, &pcr_digest_in, &pcr_sel, NULL); ++ if (rc != TPM_RC_SUCCESS) ++ { ++ fprintf (stderr, _("Failed to submit PCR policy (TPM error: 0x%x).\n"), ++ rc); ++ err = GRUB_ERR_BAD_DEVICE; ++ goto exit3; ++ } ++ ++ /* Retrieve Policy Digest */ ++ rc = TPM2_PolicyGetDigest (session, NULL, &policy_digest, NULL); ++ if (rc != TPM_RC_SUCCESS) ++ { ++ fprintf (stderr, _("Failed to get policy digest (TPM error: 0x%x).\n"), ++ rc); ++ err = GRUB_ERR_BAD_DEVICE; ++ goto exit3; ++ } ++ ++ /* Epilogue */ ++ *digest = policy_digest; ++ err = GRUB_ERR_NONE; ++ ++exit3: ++ TPM2_FlushContext (session); ++ ++exit2: ++ grub_free (pcr_concat); ++ ++exit1: ++ grub_free (pcr_digest); ++ ++ return err; ++} ++ ++static grub_err_t ++grub_protect_tpm2_get_srk (struct grub_protect_args *args, TPM_HANDLE *srk) ++{ ++ TPM_RC rc; ++ TPM2B_PUBLIC public; ++ TPMS_AUTH_COMMAND authCommand = { 0 }; ++ TPM2B_SENSITIVE_CREATE inSensitive = { 0 }; ++ TPM2B_PUBLIC inPublic = { 0 }; ++ TPM2B_DATA outsideInfo = { 0 }; ++ TPML_PCR_SELECTION creationPcr = { 0 }; ++ TPM2B_PUBLIC outPublic = { 0 }; ++ TPM2B_CREATION_DATA creationData = { 0 }; ++ TPM2B_DIGEST creationHash = { 0 }; ++ TPMT_TK_CREATION creationTicket = { 0 }; ++ TPM2B_NAME srkName = { 0 }; ++ TPM_HANDLE srkHandle; ++ ++ /* Find SRK */ ++ rc = TPM2_ReadPublic (args->tpm2_srk, NULL, &public); ++ if (rc == TPM_RC_SUCCESS) ++ { ++ if (args->tpm2_persist) ++ fprintf (stderr, ++ _("Warning: --tpm2-persist was specified but the SRK already " ++ "exists on the TPM. Continuing anyway...\n")); ++ ++ *srk = TPM2_SRK_HANDLE; ++ return GRUB_ERR_NONE; ++ } ++ ++ /* The handle exists but its public area could not be read. */ ++ if ((rc & ~TPM_RC_N_MASK) != TPM_RC_HANDLE) ++ { ++ fprintf (stderr, ++ _("The SRK exists on the TPM but its public area cannot be read " ++ "(TPM error: 0x%x).\n"), rc); ++ return GRUB_ERR_BAD_DEVICE; ++ } ++ ++ /* Create SRK */ ++ authCommand.sessionHandle = TPM_RS_PW; ++ inPublic.publicArea.type = args->tpm2_asymmetric; ++ inPublic.publicArea.nameAlg = TPM_ALG_SHA256; ++ inPublic.publicArea.objectAttributes.restricted = 1; ++ inPublic.publicArea.objectAttributes.userWithAuth = 1; ++ inPublic.publicArea.objectAttributes.decrypt = 1; ++ inPublic.publicArea.objectAttributes.fixedTPM = 1; ++ inPublic.publicArea.objectAttributes.fixedParent = 1; ++ inPublic.publicArea.objectAttributes.sensitiveDataOrigin = 1; ++ inPublic.publicArea.objectAttributes.noDA = 1; ++ ++ switch (args->tpm2_asymmetric) ++ { ++ case TPM_ALG_RSA: ++ inPublic.publicArea.parameters.rsaDetail.symmetric.algorithm = TPM_ALG_AES; ++ inPublic.publicArea.parameters.rsaDetail.symmetric.keyBits.aes = 128; ++ inPublic.publicArea.parameters.rsaDetail.symmetric.mode.aes = TPM_ALG_CFB; ++ inPublic.publicArea.parameters.rsaDetail.scheme.scheme = TPM_ALG_NULL; ++ inPublic.publicArea.parameters.rsaDetail.keyBits = 2048; ++ inPublic.publicArea.parameters.rsaDetail.exponent = 0; ++ break; ++ ++ case TPM_ALG_ECC: ++ inPublic.publicArea.parameters.eccDetail.symmetric.algorithm = TPM_ALG_AES; ++ inPublic.publicArea.parameters.eccDetail.symmetric.keyBits.aes = 128; ++ inPublic.publicArea.parameters.eccDetail.symmetric.mode.aes = TPM_ALG_CFB; ++ inPublic.publicArea.parameters.eccDetail.scheme.scheme = TPM_ALG_NULL; ++ inPublic.publicArea.parameters.eccDetail.curveID = TPM_ECC_NIST_P256; ++ inPublic.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL; ++ break; ++ ++ default: ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ rc = TPM2_CreatePrimary (TPM_RH_OWNER, &authCommand, &inSensitive, &inPublic, ++ &outsideInfo, &creationPcr, &srkHandle, &outPublic, ++ &creationData, &creationHash, &creationTicket, ++ &srkName, NULL); ++ if (rc != TPM_RC_SUCCESS) ++ { ++ fprintf (stderr, _("Failed to create SRK (TPM error: 0x%x).\n"), rc); ++ return GRUB_ERR_BAD_DEVICE; ++ } ++ ++ /* Persist SRK */ ++ if (args->tpm2_persist) ++ { ++ rc = TPM2_EvictControl (TPM_RH_OWNER, srkHandle, args->tpm2_srk, ++ &authCommand, NULL); ++ if (rc == TPM_RC_SUCCESS) ++ { ++ TPM2_FlushContext (srkHandle); ++ srkHandle = args->tpm2_srk; ++ } ++ else ++ fprintf (stderr, ++ _("Warning: Failed to persist SRK (TPM error: 0x%x\n). " ++ "Continuing anyway...\n"), rc); ++ } ++ ++ /* Epilogue */ ++ *srk = srkHandle; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_protect_tpm2_seal (TPM2B_DIGEST *policyDigest, TPM_HANDLE srk, ++ grub_uint8_t *clearText, grub_size_t clearTextLength, ++ TPM2_SEALED_KEY *sealed_key) ++{ ++ TPM_RC rc; ++ TPMS_AUTH_COMMAND authCommand = { 0 }; ++ TPM2B_SENSITIVE_CREATE inSensitive = { 0 }; ++ TPM2B_PUBLIC inPublic = { 0 }; ++ TPM2B_DATA outsideInfo = { 0 }; ++ TPML_PCR_SELECTION pcr_sel = { 0 }; ++ TPM2B_PRIVATE outPrivate = { 0 }; ++ TPM2B_PUBLIC outPublic = { 0 }; ++ ++ /* Seal Data */ ++ authCommand.sessionHandle = TPM_RS_PW; ++ ++ inSensitive.sensitive.data.size = clearTextLength; ++ memcpy(inSensitive.sensitive.data.buffer, clearText, clearTextLength); ++ ++ inPublic.publicArea.type = TPM_ALG_KEYEDHASH; ++ inPublic.publicArea.nameAlg = TPM_ALG_SHA256; ++ inPublic.publicArea.parameters.keyedHashDetail.scheme.scheme = TPM_ALG_NULL; ++ inPublic.publicArea.authPolicy = *policyDigest; ++ ++ rc = TPM2_Create (srk, &authCommand, &inSensitive, &inPublic, &outsideInfo, ++ &pcr_sel, &outPrivate, &outPublic, NULL, NULL, NULL, NULL); ++ if (rc != TPM_RC_SUCCESS) ++ { ++ fprintf (stderr, _("Failed to seal key (TPM error: 0x%x).\n"), rc); ++ return GRUB_ERR_BAD_DEVICE; ++ } ++ ++ /* Epilogue */ ++ sealed_key->public = outPublic; ++ sealed_key->private = outPrivate; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_protect_tpm2_export_sealed_key (const char *filepath, ++ TPM2_SEALED_KEY *sealed_key) ++{ ++ grub_err_t err; ++ struct grub_tpm2_buffer buf; ++ ++ grub_tpm2_buffer_init (&buf); ++ grub_tpm2_mu_TPM2B_PUBLIC_Marshal (&buf, &sealed_key->public); ++ grub_tpm2_mu_TPM2B_Marshal (&buf, sealed_key->private.size, ++ sealed_key->private.buffer); ++ if (buf.error) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ err = grub_protect_write_file (filepath, buf.data, buf.size); ++ if (err) ++ fprintf (stderr, _("Could not write sealed key file (Error: %u).\n"), ++ errno); ++ ++ return err; ++} ++ ++static grub_err_t ++grub_protect_tpm2_add (struct grub_protect_args *args) ++{ ++ grub_err_t err; ++ grub_uint8_t *key; ++ grub_size_t key_size; ++ TPM_HANDLE srk; ++ TPM2B_DIGEST policy_digest; ++ TPM2_SEALED_KEY sealed_key; ++ char *grub_drive = NULL; ++ ++ grub_protect_get_grub_drive_for_file (args->tpm2_outfile, &grub_drive); ++ ++ err = grub_protect_tpm2_open_device (args->tpm2_device); ++ if (err) ++ return err; ++ ++ err = grub_protect_read_file (args->tpm2_keyfile, (void **)&key, &key_size); ++ if (err) ++ goto exit1; ++ ++ if (key_size > TPM_MAX_SYM_DATA) ++ { ++ fprintf (stderr, ++ _("Input key is too long, maximum allowed size is %u bytes.\n"), ++ TPM_MAX_SYM_DATA); ++ return GRUB_ERR_OUT_OF_RANGE; ++ } ++ ++ err = grub_protect_tpm2_get_srk (args, &srk); ++ if (err) ++ goto exit2; ++ ++ err = grub_protect_tpm2_get_policy_digest (args, &policy_digest); ++ if (err) ++ goto exit3; ++ ++ err = grub_protect_tpm2_seal (&policy_digest, srk, key, key_size, ++ &sealed_key); ++ if (err) ++ goto exit3; ++ ++ err = grub_protect_tpm2_export_sealed_key (args->tpm2_outfile, &sealed_key); ++ if (err) ++ goto exit3; ++ ++ if (grub_drive) ++ { ++ printf (_("GRUB drive for the sealed key file: %s\n"), grub_drive); ++ grub_free (grub_drive); ++ } ++ else ++ { ++ fprintf (stderr, ++ _("Warning: Could not determine GRUB drive for sealed key " ++ "file.\n")); ++ err = GRUB_ERR_NONE; ++ } ++ ++exit3: ++ TPM2_FlushContext (srk); ++ ++exit2: ++ grub_free (key); ++ ++exit1: ++ grub_protect_tpm2_close_device (); ++ ++ return err; ++} ++ ++static grub_err_t ++grub_protect_tpm2_remove (struct grub_protect_args *args) ++{ ++ TPM_RC rc; ++ TPM2B_PUBLIC public; ++ TPMS_AUTH_COMMAND authCommand = { 0 }; ++ grub_err_t err; ++ ++ if (!args->tpm2_evict) ++ { ++ printf (_("--tpm2-evict not specified, nothing to do.\n")); ++ return GRUB_ERR_NONE; ++ } ++ ++ err = grub_protect_tpm2_open_device (args->tpm2_device); ++ if (err) ++ return err; ++ ++ /* Find SRK */ ++ rc = TPM2_ReadPublic (args->tpm2_srk, NULL, &public); ++ if (rc != TPM_RC_SUCCESS) ++ { ++ fprintf (stderr, _("SRK with handle 0x%x not found.\n"), args->tpm2_srk); ++ err = GRUB_ERR_BAD_ARGUMENT; ++ goto exit1; ++ } ++ ++ /* Evict SRK */ ++ authCommand.sessionHandle = TPM_RS_PW; ++ ++ rc = TPM2_EvictControl (TPM_RH_OWNER, args->tpm2_srk, args->tpm2_srk, ++ &authCommand, NULL); ++ if (rc != TPM_RC_SUCCESS) ++ { ++ fprintf (stderr, ++ _("Failed to evict SRK with handle 0x%x (TPM Error: 0x%x).\n"), ++ args->tpm2_srk, rc); ++ err = GRUB_ERR_BAD_DEVICE; ++ goto exit2; ++ } ++ ++ err = GRUB_ERR_NONE; ++ ++exit2: ++ TPM2_FlushContext (args->tpm2_srk); ++ ++exit1: ++ grub_protect_tpm2_close_device (); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_protect_tpm2_run (struct grub_protect_args *args) ++{ ++ switch (args->action) ++ { ++ case GRUB_PROTECT_ACTION_ADD: ++ return grub_protect_tpm2_add (args); ++ ++ case GRUB_PROTECT_ACTION_REMOVE: ++ return grub_protect_tpm2_remove (args); ++ ++ default: ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++} ++ ++static grub_err_t ++grub_protect_tpm2_args_verify (struct grub_protect_args *args) ++{ ++ switch (args->action) ++ { ++ case GRUB_PROTECT_ACTION_ADD: ++ if (args->args & GRUB_PROTECT_ARG_TPM2_EVICT) ++ { ++ fprintf (stderr, ++ _("--tpm2-evict is invalid when --action is 'add'.\n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ if (!args->tpm2_keyfile) ++ { ++ fprintf (stderr, _("--tpm2-keyfile must be specified.\n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ if (!args->tpm2_outfile) ++ { ++ fprintf (stderr, _("--tpm2-outfile must be specified.\n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ if (!args->tpm2_device) ++ args->tpm2_device = "/dev/tpm0"; ++ ++ if (!args->tpm2_pcr_count) ++ { ++ args->tpm2_pcrs[0] = 7; ++ args->tpm2_pcr_count = 1; ++ } ++ ++ if (!args->tpm2_srk) ++ args->tpm2_srk = TPM2_SRK_HANDLE; ++ ++ if (!args->tpm2_asymmetric) ++ args->tpm2_asymmetric = TPM_ALG_RSA; ++ ++ if (!args->tpm2_bank) ++ args->tpm2_bank = TPM_ALG_SHA256; ++ ++ break; ++ ++ case GRUB_PROTECT_ACTION_REMOVE: ++ if (args->args & GRUB_PROTECT_ARG_TPM2_ASYMMETRIC) ++ { ++ fprintf (stderr, ++ _("--tpm2-asymmetric is invalid when --action is 'remove'.\n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ if (args->args & GRUB_PROTECT_ARG_TPM2_BANK) ++ { ++ fprintf (stderr, ++ _("--tpm2-bank is invalid when --action is 'remove'.\n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ if (args->args & GRUB_PROTECT_ARG_TPM2_KEYFILE) ++ { ++ fprintf (stderr, ++ _("--tpm2-keyfile is invalid when --action is 'remove'.\n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ if (args->args & GRUB_PROTECT_ARG_TPM2_OUTFILE) ++ { ++ fprintf (stderr, ++ _("--tpm2-outfile is invalid when --action is 'remove'.\n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ if (args->args & GRUB_PROTECT_ARG_TPM2_PCRS) ++ { ++ fprintf (stderr, ++ _("--tpm2-pcrs is invalid when --action is 'remove'.\n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ if (args->args & GRUB_PROTECT_ARG_TPM2_PERSIST) ++ { ++ fprintf (stderr, ++ _("--tpm2-persist is invalid when --action is 'remove'.\n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ if (!args->tpm2_device) ++ args->tpm2_device = "/dev/tpm0"; ++ ++ if (!args->tpm2_srk) ++ args->tpm2_srk = TPM2_SRK_HANDLE; ++ ++ break; ++ ++ default: ++ fprintf (stderr, ++ _("The TPM2 key protector only supports the following actions: " ++ "add, remove.\n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static error_t ++grub_protect_argp_parser (int key, char *arg, struct argp_state *state) ++{ ++ grub_err_t err; ++ struct grub_protect_args *args = state->input; ++ ++ switch (key) ++ { ++ case GRUB_PROTECT_OPT_ACTION: ++ if (args->args & GRUB_PROTECT_ARG_ACTION) ++ { ++ fprintf (stderr, _("--action|-a can only be specified once.\n")); ++ return EINVAL; ++ } ++ ++ if (grub_strcmp (arg, "add") == 0) ++ args->action = GRUB_PROTECT_ACTION_ADD; ++ else if (grub_strcmp (arg, "remove") == 0) ++ args->action = GRUB_PROTECT_ACTION_REMOVE; ++ else ++ { ++ fprintf (stderr, _("'%s' is not a valid action.\n"), arg); ++ return EINVAL; ++ } ++ ++ args->args |= GRUB_PROTECT_ARG_ACTION; ++ break; ++ ++ case GRUB_PROTECT_OPT_PROTECTOR: ++ if (args->args & GRUB_PROTECT_ARG_PROTECTOR) ++ { ++ fprintf (stderr, _("--protector|-p can only be specified once.\n")); ++ return EINVAL; ++ } ++ ++ if (grub_strcmp (arg, "tpm2") == 0) ++ args->protector = GRUB_PROTECT_TYPE_TPM2; ++ else ++ { ++ fprintf (stderr, _("'%s' is not a valid protector.\n"), arg); ++ return EINVAL; ++ } ++ ++ args->args |= GRUB_PROTECT_ARG_PROTECTOR; ++ break; ++ ++ case GRUB_PROTECT_OPT_TPM2_DEVICE: ++ if (args->args & GRUB_PROTECT_ARG_TPM2_DEVICE) ++ { ++ fprintf (stderr, _("--tpm2-device can only be specified once.\n")); ++ return EINVAL; ++ } ++ ++ args->tpm2_device = xstrdup(arg); ++ args->args |= GRUB_PROTECT_ARG_TPM2_DEVICE; ++ break; ++ ++ case GRUB_PROTECT_OPT_TPM2_PCRS: ++ if (args->args & GRUB_PROTECT_ARG_TPM2_PCRS) ++ { ++ fprintf (stderr, _("--tpm2-pcrs can only be specified once.\n")); ++ return EINVAL; ++ } ++ ++ err = grub_tpm2_protector_parse_pcrs (arg, args->tpm2_pcrs, ++ &args->tpm2_pcr_count); ++ if (err) ++ { ++ if (grub_errno) ++ grub_print_error (); ++ return EINVAL; ++ } ++ ++ args->args |= GRUB_PROTECT_ARG_TPM2_PCRS; ++ break; ++ ++ case GRUB_PROTECT_OPT_TPM2_SRK: ++ if (args->args & GRUB_PROTECT_ARG_TPM2_SRK) ++ { ++ fprintf (stderr, _("--tpm2-srk can only be specified once.\n")); ++ return EINVAL; ++ } ++ ++ err = grub_tpm2_protector_parse_tpm_handle (arg, &args->tpm2_srk); ++ if (err) ++ { ++ if (grub_errno) ++ grub_print_error (); ++ return EINVAL; ++ } ++ ++ args->args |= GRUB_PROTECT_ARG_TPM2_SRK; ++ break; ++ ++ case GRUB_PROTECT_OPT_TPM2_ASYMMETRIC: ++ if (args->args & GRUB_PROTECT_ARG_TPM2_ASYMMETRIC) ++ { ++ fprintf (stderr, _("--tpm2-asymmetric can only be specified once.\n")); ++ return EINVAL; ++ } ++ ++ err = grub_tpm2_protector_parse_asymmetric (arg, &args->tpm2_asymmetric); ++ if (err) ++ { ++ if (grub_errno) ++ grub_print_error (); ++ return EINVAL; ++ } ++ ++ args->args |= GRUB_PROTECT_ARG_TPM2_ASYMMETRIC; ++ break; ++ ++ case GRUB_PROTECT_OPT_TPM2_BANK: ++ if (args->args & GRUB_PROTECT_ARG_TPM2_BANK) ++ { ++ fprintf (stderr, _("--tpm2-bank can only be specified once.\n")); ++ return EINVAL; ++ } ++ ++ err = grub_tpm2_protector_parse_bank (arg, &args->tpm2_bank); ++ if (err) ++ { ++ if (grub_errno) ++ grub_print_error (); ++ return EINVAL; ++ } ++ ++ args->args |= GRUB_PROTECT_ARG_TPM2_BANK; ++ break; ++ ++ case GRUB_PROTECT_OPT_TPM2_KEYFILE: ++ if (args->args & GRUB_PROTECT_ARG_TPM2_KEYFILE) ++ { ++ fprintf (stderr, _("--tpm2-keyfile can only be specified once.\n")); ++ return EINVAL; ++ } ++ ++ args->tpm2_keyfile = xstrdup(arg); ++ args->args |= GRUB_PROTECT_ARG_TPM2_KEYFILE; ++ break; ++ ++ case GRUB_PROTECT_OPT_TPM2_OUTFILE: ++ if (args->args & GRUB_PROTECT_ARG_TPM2_OUTFILE) ++ { ++ fprintf (stderr, _("--tpm2-outfile can only be specified once.\n")); ++ return EINVAL; ++ } ++ ++ args->tpm2_outfile = xstrdup(arg); ++ args->args |= GRUB_PROTECT_ARG_TPM2_OUTFILE; ++ break; ++ ++ case GRUB_PROTECT_OPT_TPM2_PERSIST: ++ if (args->args & GRUB_PROTECT_ARG_TPM2_PERSIST) ++ { ++ fprintf (stderr, _("--tpm2-persist can only be specified once.\n")); ++ return EINVAL; ++ } ++ ++ args->tpm2_persist = 1; ++ args->args |= GRUB_PROTECT_ARG_TPM2_PERSIST; ++ break; ++ ++ case GRUB_PROTECT_OPT_TPM2_EVICT: ++ if (args->args & GRUB_PROTECT_ARG_TPM2_EVICT) ++ { ++ fprintf (stderr, _("--tpm2-evict can only be specified once.\n")); ++ return EINVAL; ++ } ++ ++ args->tpm2_evict = 1; ++ args->args |= GRUB_PROTECT_ARG_TPM2_EVICT; ++ break; ++ ++ default: ++ return ARGP_ERR_UNKNOWN; ++ } ++ ++ return 0; ++} ++ ++static grub_err_t ++grub_protect_args_verify (struct grub_protect_args *args) ++{ ++ if (args->action == GRUB_PROTECT_ACTION_ERROR) ++ { ++ fprintf (stderr, "--action is mandatory.\n"); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ /* At the moment, the only configurable key protector is the TPM2 one, so it ++ * is the only key protector supported by this tool. */ ++ if (args->protector != GRUB_PROTECT_TYPE_TPM2) ++ { ++ fprintf (stderr, ++ _("--protector is mandatory and only 'tpm2' is currently " ++ "supported.\n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ switch (args->protector) ++ { ++ case GRUB_PROTECT_TYPE_TPM2: ++ return grub_protect_tpm2_args_verify (args); ++ default: ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_protect_dispatch (struct grub_protect_args *args) ++{ ++ switch (args->protector) ++ { ++ case GRUB_PROTECT_TYPE_TPM2: ++ return grub_protect_tpm2_run (args); ++ default: ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++} ++ ++static void ++grub_protect_init (int *argc, char **argv[]) ++{ ++ grub_util_host_init (argc, argv); ++ ++ grub_util_biosdisk_init (NULL); ++ ++ grub_init_all (); ++ grub_gcry_init_all (); ++ ++ grub_lvm_fini (); ++ grub_mdraid09_fini (); ++ grub_mdraid1x_fini (); ++ grub_diskfilter_fini (); ++ grub_diskfilter_init (); ++ grub_mdraid09_init (); ++ grub_mdraid1x_init (); ++ grub_lvm_init (); ++} ++ ++static void ++grub_protect_fini (void) ++{ ++ grub_gcry_fini_all (); ++ grub_fini_all (); ++ grub_util_biosdisk_fini (); ++} ++ ++static struct argp grub_protect_argp = ++{ ++ .options = grub_protect_options, ++ .parser = grub_protect_argp_parser, ++ .args_doc = NULL, ++ .doc = ++ N_("Protect a cleartext key using a GRUB key protector that can retrieve " ++ "the key during boot to unlock fully-encrypted disks automatically."), ++ .children = NULL, ++ .help_filter = NULL, ++ .argp_domain = NULL ++}; ++ ++int ++main (int argc, char *argv[]) ++{ ++ grub_err_t err; ++ struct grub_protect_args args = { 0 }; ++ ++ if (argp_parse (&grub_protect_argp, argc, argv, 0, 0, &args) != 0) ++ { ++ fprintf (stderr, _("Could not parse arguments.\n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ grub_protect_init (&argc, &argv); ++ ++ err = grub_protect_args_verify (&args); ++ if (err) ++ goto exit; ++ ++ err = grub_protect_dispatch (&args); ++ if (err) ++ goto exit; ++ ++exit: ++ grub_protect_fini (); ++ ++ return err; ++} +-- +2.34.1 + diff --git a/0014-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch b/0014-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch new file mode 100644 index 0000000..1ee376a --- /dev/null +++ b/0014-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch @@ -0,0 +1,46 @@ +From 9b6026ba4eb26eadc7ddb8df1c49f648efe257c5 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 28 Jun 2021 14:25:17 +1000 +Subject: [PATCH 14/32] video/readers/jpeg: Refuse to handle multiple start of + streams + +An invalid file could contain multiple start of stream blocks, which +would cause us to reallocate and leak our bitmap. Refuse to handle +multiple start of streams. + +Additionally, fix a grub_error() call formatting. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/video/readers/jpeg.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index caa211f06d..1df1171d78 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -677,6 +677,9 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) + if (data->file->offset != data_offset) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos"); + ++ if (*data->bitmap) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: too many start of scan blocks"); ++ + if (grub_video_bitmap_create (data->bitmap, data->image_width, + data->image_height, + GRUB_VIDEO_BLIT_FORMAT_RGB_888)) +@@ -699,8 +702,8 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data) + nc1 = (data->image_width + hb - 1) >> (3 + data->log_hs); + + if (data->bitmap_ptr == NULL) +- return grub_error(GRUB_ERR_BAD_FILE_TYPE, +- "jpeg: attempted to decode data before start of stream"); ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: attempted to decode data before start of stream"); + + for (; data->r1 < nr1 && (!data->dri || rst); + data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3) +-- +2.34.1 + diff --git a/0015-test_asn1-test-module-for-libtasn1.patch b/0015-test_asn1-test-module-for-libtasn1.patch new file mode 100644 index 0000000..4c459c0 --- /dev/null +++ b/0015-test_asn1-test-module-for-libtasn1.patch @@ -0,0 +1,1447 @@ +From 5fcbd6e61cd5390e3e0d0f65eb622761d23bab4e Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Wed, 10 Jun 2020 17:48:42 +1000 +Subject: [PATCH 15/23] test_asn1: test module for libtasn1 + +Import tests from libtasn1 that don't use functionality we don't +import. I have put them here rather than in the libtasn1 directory +because: + + - They need much more significant changes to run in the grub + context. + + - I don't expect they will need to be changed when updating + libtasn1: I expect the old tests will usually continue to pass on + new versions. + +This doesn't test the full decoder but that will be exercised in +test suites for coming patch sets. + +Signed-off-by: Daniel Axtens +--- + Makefile.util.def | 6 + + grub-core/Makefile.core.def | 13 ++ + .../tests/CVE-2018-1000654-1_asn1_tab.h | 32 +++ + .../tests/CVE-2018-1000654-2_asn1_tab.h | 36 +++ + .../libtasn1_wrap/tests/CVE-2018-1000654.c | 61 +++++ + .../lib/libtasn1_wrap/tests/Test_overflow.c | 138 ++++++++++++ + .../lib/libtasn1_wrap/tests/Test_simple.c | 207 +++++++++++++++++ + .../lib/libtasn1_wrap/tests/Test_strings.c | 150 +++++++++++++ + .../libtasn1_wrap/tests/object-id-decoding.c | 116 ++++++++++ + .../libtasn1_wrap/tests/object-id-encoding.c | 120 ++++++++++ + .../lib/libtasn1_wrap/tests/octet-string.c | 211 ++++++++++++++++++ + .../lib/libtasn1_wrap/tests/reproducers.c | 81 +++++++ + grub-core/lib/libtasn1_wrap/wrap_tests.c | 75 +++++++ + grub-core/lib/libtasn1_wrap/wrap_tests.h | 38 ++++ + tests/test_asn1.in | 12 + + 15 files changed, 1296 insertions(+) + create mode 100644 grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h + create mode 100644 grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h + create mode 100644 grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c + create mode 100644 grub-core/lib/libtasn1_wrap/tests/Test_overflow.c + create mode 100644 grub-core/lib/libtasn1_wrap/tests/Test_simple.c + create mode 100644 grub-core/lib/libtasn1_wrap/tests/Test_strings.c + create mode 100644 grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c + create mode 100644 grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c + create mode 100644 grub-core/lib/libtasn1_wrap/tests/octet-string.c + create mode 100644 grub-core/lib/libtasn1_wrap/tests/reproducers.c + create mode 100644 grub-core/lib/libtasn1_wrap/wrap_tests.c + create mode 100644 grub-core/lib/libtasn1_wrap/wrap_tests.h + create mode 100644 tests/test_asn1.in + +diff --git a/Makefile.util.def b/Makefile.util.def +index ac2b6aab1..ef5c818e0 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -1272,6 +1272,12 @@ script = { + common = tests/syslinux_test.in; + }; + ++script = { ++ testcase; ++ name = test_asn1; ++ common = tests/test_asn1.in; ++}; ++ + program = { + testcase; + name = example_unit_test; +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index f0df8ed94..6a3ff4265 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2590,3 +2590,16 @@ module = { + // -Wno-type-limits comes from libtasn1's configure.ac + cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB) -I$(srcdir)/lib/libtasn1/lib -Wno-type-limits'; + }; ++ ++module = { ++ name = test_asn1; ++ common = lib/libtasn1_wrap/tests/CVE-2018-1000654.c; ++ common = lib/libtasn1_wrap/tests/object-id-decoding.c; ++ common = lib/libtasn1_wrap/tests/object-id-encoding.c; ++ common = lib/libtasn1_wrap/tests/octet-string.c; ++ common = lib/libtasn1_wrap/tests/reproducers.c; ++ common = lib/libtasn1_wrap/tests/Test_overflow.c; ++ common = lib/libtasn1_wrap/tests/Test_simple.c; ++ common = lib/libtasn1_wrap/tests/Test_strings.c; ++ common = lib/libtasn1_wrap/wrap_tests.c; ++}; +diff --git a/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h +new file mode 100644 +index 000000000..1e7d3d64f +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h +@@ -0,0 +1,32 @@ ++#if HAVE_CONFIG_H ++# include "config.h" ++#endif ++ ++#include ++ ++const asn1_static_node CVE_2018_1000654_1_asn1_tab[] = { ++ { "TEST_TREE", 536875024, NULL }, ++ { NULL, 1610612748, NULL }, ++ { "iso", 1073741825, "1"}, ++ { "identified-organization", 1073741825, "3"}, ++ { "dod", 1073741825, "6"}, ++ { "internet", 1073741825, "1"}, ++ { "security", 1073741825, "5"}, ++ { "mechanisms", 1073741825, "5"}, ++ { "pkix", 1073741825, "7"}, ++ { "id-mod", 1073741825, "0"}, ++ { "id-pkix1-implicit-88", 1, "2"}, ++ { "id-xnyTest", 1879048204, NULL }, ++ { NULL, 1073741825, "id-ix"}, ++ { NULL, 1073741825, "29"}, ++ { NULL, 1, "1"}, ++ { "id-ix", 1880096780, "OBJECR"}, ++ { NULL, 1073741825, "id-ix"}, ++ { NULL, 1073741825, "29"}, ++ { NULL, 1, "2"}, ++ { "id-xnyTest", 805306380, NULL }, ++ { NULL, 1073741825, "id-ix"}, ++ { NULL, 1073741825, "29"}, ++ { NULL, 1, "1"}, ++ { NULL, 0, NULL } ++}; +diff --git a/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h +new file mode 100644 +index 000000000..e2561e5ec +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h +@@ -0,0 +1,36 @@ ++#if HAVE_CONFIG_H ++# include "config.h" ++#endif ++ ++#include ++ ++const asn1_static_node CVE_2018_1000654_2_asn1_tab[] = { ++ { "TEST_TREE", 536875024, NULL }, ++ { NULL, 1610612748, NULL }, ++ { "iso", 1073741825, "1"}, ++ { "identified-organization", 1073741825, "3"}, ++ { "dod", 1073741825, "6"}, ++ { "internet", 1073741825, "1"}, ++ { "security", 1073741825, "5"}, ++ { "mechanisms", 1073741825, "5"}, ++ { "pkix", 1073741825, "7"}, ++ { "id-mod", 1073741825, "0"}, ++ { "id-pkix1-implicit-88", 1, "2"}, ++ { "id-oneTest", 1879048204, NULL }, ++ { NULL, 1073741825, "id-two"}, ++ { NULL, 1073741825, "9"}, ++ { NULL, 1, "1"}, ++ { "id-two", 1879048204, NULL }, ++ { NULL, 1073741825, "id-three"}, ++ { NULL, 1073741825, "2"}, ++ { NULL, 1, "2"}, ++ { "id-three", 1879048204, NULL }, ++ { NULL, 1073741825, "id-four"}, ++ { NULL, 1073741825, "3"}, ++ { NULL, 1, "3"}, ++ { "id-four", 805306380, NULL }, ++ { NULL, 1073741825, "id-two"}, ++ { NULL, 1073741825, "3"}, ++ { NULL, 1, "3"}, ++ { NULL, 0, NULL } ++}; +diff --git a/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c +new file mode 100644 +index 000000000..534e30452 +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c +@@ -0,0 +1,61 @@ ++/* ++ * Copyright (C) 2002-2018 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * This program 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. ++ * ++ * This program 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 this program. If not, see . ++ * ++ */ ++ ++/****************************************************************/ ++/* Description: reproducer for CVE-2018-1000654 */ ++/****************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include "../wrap_tests.h" ++ ++#include "CVE-2018-1000654-1_asn1_tab.h" ++#include "CVE-2018-1000654-2_asn1_tab.h" ++ ++void ++test_CVE_2018_1000654 (void) ++{ ++ int result; ++ asn1_node definitions = NULL; ++ char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; ++ ++ result = asn1_array2tree (CVE_2018_1000654_1_asn1_tab, &definitions, errorDescription); ++ if (result != ASN1_RECURSION) ++ { ++ grub_fatal ("Error: %s\nErrorDescription = %s\n\n", ++ asn1_strerror (result), errorDescription); ++ return; ++ } ++ ++ asn1_delete_structure (&definitions); ++ ++ result = asn1_array2tree (CVE_2018_1000654_2_asn1_tab, &definitions, errorDescription); ++ if (result != ASN1_RECURSION) ++ { ++ grub_fatal ("Error: %s\nErrorDescription = %s\n\n", ++ asn1_strerror (result), errorDescription); ++ return; ++ } ++ ++ asn1_delete_structure (&definitions); ++} +diff --git a/grub-core/lib/libtasn1_wrap/tests/Test_overflow.c b/grub-core/lib/libtasn1_wrap/tests/Test_overflow.c +new file mode 100644 +index 000000000..f48aea0ef +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/Test_overflow.c +@@ -0,0 +1,138 @@ ++/* ++ * Copyright (C) 2012-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * This program 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. ++ * ++ * This program 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 this program. If not, see . ++ * ++ */ ++ ++/* Written by Simon Josefsson */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "../wrap_tests.h" ++ ++void ++test_overflow(void) ++{ ++ /* Test that values larger than long are rejected. This has worked ++ fine with all versions of libtasn1. */ ++ ++ { ++ unsigned char der[] = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"; ++ long l; ++ int len; ++ ++ l = asn1_get_length_der (der, sizeof der, &len); ++ ++ if (l != -2L) ++ { ++ grub_fatal ("ERROR: asn1_get_length_der bignum (l %ld len %d)\n", l, len); ++ return; ++ } ++ } ++ ++ /* Test that values larger than int but smaller than long are ++ rejected. This limitation was introduced with libtasn1 2.12. */ ++#if (GRUB_LONG_MAX > GRUB_INT_MAX) ++ { ++ unsigned long num = ((long) GRUB_UINT_MAX) << 2; ++ unsigned char der[20]; ++ int der_len; ++ long l; ++ int len; ++ ++ asn1_length_der (num, der, &der_len); ++ ++ l = asn1_get_length_der (der, der_len, &len); ++ ++ if (l != -2L) ++ { ++ grub_fatal ("ERROR: asn1_get_length_der intnum (l %ld len %d)\n", l, ++ len); ++ return; ++ } ++ } ++#endif ++ ++ /* Test that values larger than would fit in the input string are ++ rejected. This problem was fixed in libtasn1 2.12. */ ++ { ++ unsigned long num = 64; ++ unsigned char der[20]; ++ int der_len; ++ long l; ++ int len; ++ ++ asn1_length_der (num, der, &der_len); ++ ++ der_len = sizeof (der); ++ l = asn1_get_length_der (der, der_len, &len); ++ ++ if (l != -4L) ++ { ++ grub_fatal ("ERROR: asn1_get_length_der overflow-small (l %ld len %d)\n", ++ l, len); ++ return; ++ } ++ } ++ ++ /* Test that values larger than would fit in the input string are ++ rejected. This problem was fixed in libtasn1 2.12. */ ++ { ++ unsigned long num = 1073741824; ++ unsigned char der[20]; ++ int der_len; ++ long l; ++ int len; ++ ++ asn1_length_der (num, der, &der_len); ++ ++ der_len = sizeof (der); ++ l = asn1_get_length_der (der, der_len, &len); ++ ++ if (l != -4L) ++ { ++ grub_fatal ("ERROR: asn1_get_length_der overflow-large1 (l %ld len %d)\n", ++ l, len); ++ return; ++ } ++ } ++ ++ /* Test that values larger than would fit in the input string are ++ rejected. This problem was fixed in libtasn1 2.12. */ ++ { ++ unsigned long num = 2147483649; ++ unsigned char der[20]; ++ int der_len; ++ long l; ++ int len; ++ ++ asn1_length_der (num, der, &der_len); ++ ++ der_len = sizeof (der); ++ l = asn1_get_length_der (der, der_len, &len); ++ ++ if (l != -2L) ++ { ++ grub_fatal ("ERROR: asn1_get_length_der overflow-large2 (l %ld len %d)\n", ++ l, len); ++ return; ++ } ++ } ++} +diff --git a/grub-core/lib/libtasn1_wrap/tests/Test_simple.c b/grub-core/lib/libtasn1_wrap/tests/Test_simple.c +new file mode 100644 +index 000000000..9f01006dd +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/Test_simple.c +@@ -0,0 +1,207 @@ ++/* ++ * Copyright (C) 2011-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * This program 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. ++ * ++ * This program 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 this program. If not, see . ++ * ++ * Written by Simon Josefsson ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include "../wrap_tests.h" ++ ++struct tv ++{ ++ int bitlen; ++ const char *bitstr; ++ int derlen; ++ const char *der; ++}; ++ ++static const struct tv tv[] = { ++ {0, "", 2, "\x01\x00"}, ++ {1, "\x00", 3, "\x02\x07\x00"}, ++ {2, "\x00", 3, "\x02\x06\x00"}, ++ {3, "\x00", 3, "\x02\x05\x00"}, ++ {4, "\x00", 3, "\x02\x04\x00"}, ++ {5, "\x00", 3, "\x02\x03\x00"}, ++ {6, "\x00", 3, "\x02\x02\x00"}, ++ {7, "\x00", 3, "\x02\x01\x00"}, ++ {8, "\x00\x00", 3, "\x02\x00\x00"}, ++ {9, "\x00\x00", 4, "\x03\x07\x00\x00"}, ++ {10, "\x00\x00", 4, "\x03\x06\x00\x00"}, ++ {11, "\x00\x00", 4, "\x03\x05\x00\x00"}, ++ {12, "\x00\x00", 4, "\x03\x04\x00\x00"}, ++ {13, "\x00\x00", 4, "\x03\x03\x00\x00"}, ++ {14, "\x00\x00", 4, "\x03\x02\x00\x00"}, ++ {15, "\x00\x00", 4, "\x03\x01\x00\x00"}, ++ {16, "\x00\x00", 4, "\x03\x00\x00\x00"}, ++ {17, "\x00\x00\x00", 5, "\x04\x07\x00\x00\x00"}, ++ {18, "\x00\x00\x00", 5, "\x04\x06\x00\x00\x00"}, ++ {19, "\x00\x00\x00", 5, "\x04\x05\x00\x00\x00"}, ++ {1, "\xFF", 3, "\x02\x07\x80"}, ++ {2, "\xFF", 3, "\x02\x06\xc0"}, ++ {3, "\xFF", 3, "\x02\x05\xe0"}, ++ {4, "\xFF", 3, "\x02\x04\xf0"}, ++ {5, "\xFF", 3, "\x02\x03\xf8"}, ++ {6, "\xFF", 3, "\x02\x02\xfc"}, ++ {7, "\xFF", 3, "\x02\x01\xfe"}, ++ {8, "\xFF\xFF", 3, "\x02\x00\xff"}, ++ {9, "\xFF\xFF", 4, "\x03\x07\xff\x80"}, ++ {10, "\xFF\xFF", 4, "\x03\x06\xff\xc0"}, ++ {11, "\xFF\xFF", 4, "\x03\x05\xff\xe0"}, ++ {12, "\xFF\xFF", 4, "\x03\x04\xff\xf0"}, ++ {13, "\xFF\xFF", 4, "\x03\x03\xff\xf8"}, ++ {14, "\xFF\xFF", 4, "\x03\x02\xff\xfc"}, ++ {15, "\xFF\xFF", 4, "\x03\x01\xff\xfe"}, ++ {16, "\xFF\xFF", 4, "\x03\x00\xff\xff"}, ++ {17, "\xFF\xFF\xFF", 5, "\x04\x07\xff\xff\x80"}, ++ {18, "\xFF\xFF\xFF", 5, "\x04\x06\xff\xff\xc0"}, ++ {19, "\xFF\xFF\xFF", 5, "\x04\x05\xff\xff\xe0"}, ++}; ++ ++void ++test_simple (void) ++{ ++ int result; ++ unsigned char der[100]; ++ unsigned char str[100]; ++ int der_len = sizeof (der); ++ int str_size = sizeof (str); ++ int ret_len, bit_len; ++ grub_size_t i; ++ ++ /* Dummy test */ ++ ++ asn1_bit_der (NULL, 0, der, &der_len); ++ result = asn1_get_bit_der (der, 0, &ret_len, str, str_size, &bit_len); ++ if (result != ASN1_GENERIC_ERROR) ++ { ++ grub_fatal ("asn1_get_bit_der zero\n"); ++ return; ++ } ++ ++ /* Encode short strings with increasing bit lengths */ ++ ++ for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++) ++ { ++ /* Encode */ ++ ++ asn1_bit_der ((const unsigned char *) tv[i].bitstr, tv[i].bitlen, ++ der, &der_len); ++ ++#if 0 ++ { ++ size_t j; ++ for (j = 0; j < der_len; j++) ++ printf ("\\x%02x", der[j]); ++ printf ("\n"); ++ } ++#endif ++ ++ if (der_len != tv[i].derlen || grub_memcmp (der, tv[i].der, der_len) != 0) ++ { ++ grub_fatal ("asn1_bit_der iter %lu\n", (unsigned long) i); ++ return; ++ } ++ ++ /* Decode it */ ++ ++ result = asn1_get_bit_der (der, der_len, &ret_len, str, ++ str_size, &bit_len); ++ if (result != ASN1_SUCCESS || ret_len != tv[i].derlen ++ || bit_len != tv[i].bitlen) ++ { ++ grub_fatal ("asn1_get_bit_der iter %lu, err: %d\n", (unsigned long) i, result); ++ return; ++ } ++ } ++ ++ ++ /* Decode sample from "A Layman's Guide to a Subset of ASN.1, BER, ++ and DER" section 5.4 "BIT STRING": "The BER encoding of the BIT ++ STRING value "011011100101110111" can be any of the following, ++ among others, depending on the choice of padding bits, the form ++ of length octets [...]". ++ */ ++ ++ /* 03 04 06 6e 5d c0 DER encoding */ ++ ++ grub_memcpy (der, "\x04\x06\x6e\x5d\xc0", 5); ++ der_len = 5; ++ ++ result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len); ++ if (result != ASN1_SUCCESS || ret_len != 5 ++ || bit_len != 18 || grub_memcmp (str, "\x6e\x5d\xc0", 3) != 0) ++ { ++ grub_fatal ("asn1_get_bit_der example\n"); ++ return; ++ } ++ ++ der_len = sizeof (der); ++ asn1_bit_der (str, bit_len, der, &der_len); ++ if (der_len != 5 || grub_memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0) ++ { ++ grub_fatal ("asn1_bit_der example roundtrip\n"); ++ return; ++ } ++ ++ /* 03 04 06 6e 5d e0 padded with "100000" */ ++ ++ grub_memcpy (der, "\x04\x06\x6e\x5d\xe0", 5); ++ der_len = 5; ++ ++ result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len); ++ if (result != ASN1_SUCCESS || ret_len != 5 ++ || bit_len != 18 || grub_memcmp (str, "\x6e\x5d\xe0", 3) != 0) ++ { ++ grub_fatal ("asn1_get_bit_der example padded\n"); ++ return; ++ } ++ ++ der_len = sizeof (der); ++ asn1_bit_der (str, bit_len, der, &der_len); ++ if (der_len != 5 || grub_memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0) ++ { ++ grub_fatal ("asn1_bit_der example roundtrip\n"); ++ return; ++ } ++ ++ /* 03 81 04 06 6e 5d c0 long form of length octets */ ++ ++ grub_memcpy (der, "\x81\x04\x06\x6e\x5d\xc0", 6); ++ der_len = 6; ++ ++ result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len); ++ ++ if (result != ASN1_SUCCESS || ret_len != 6 ++ || bit_len != 18 || grub_memcmp (str, "\x6e\x5d\xc0", 3) != 0) ++ { ++ grub_fatal ("asn1_get_bit_der example long form\n"); ++ return; ++ } ++ ++ der_len = sizeof (der); ++ asn1_bit_der (str, bit_len, der, &der_len); ++ if (der_len != 5 || grub_memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0) ++ { ++ grub_fatal ("asn1_bit_der example roundtrip\n"); ++ return; ++ } ++} +diff --git a/grub-core/lib/libtasn1_wrap/tests/Test_strings.c b/grub-core/lib/libtasn1_wrap/tests/Test_strings.c +new file mode 100644 +index 000000000..dbe1474b2 +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/Test_strings.c +@@ -0,0 +1,150 @@ ++/* ++ * Copyright (C) 2012-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * This program 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. ++ * ++ * This program 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 this program. If not, see . ++ * ++ * Written by Simon Josefsson ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include "../wrap_tests.h" ++ ++struct tv ++{ ++ unsigned int etype; ++ unsigned int str_len; ++ const void *str; ++ unsigned int der_len; ++ const void *der; ++}; ++ ++static const struct tv tv[] = { ++ {ASN1_ETYPE_IA5_STRING, 20, ++ "\x63\x73\x63\x61\x40\x70\x61\x73\x73\x70\x6f\x72\x74\x2e\x67\x6f\x76\x2e\x67\x72", ++ 22, ++ "\x16\x14\x63\x73\x63\x61\x40\x70\x61\x73\x73\x70\x6f\x72\x74\x2e\x67\x6f\x76\x2e\x67\x72"}, ++ {ASN1_ETYPE_PRINTABLE_STRING, 5, "\x4e\x69\x6b\x6f\x73", ++ 7, "\x13\x05\x4e\x69\x6b\x6f\x73"}, ++ {ASN1_ETYPE_UTF8_STRING, 12, "Αττική", ++ 14, "\x0c\x0c\xce\x91\xcf\x84\xcf\x84\xce\xb9\xce\xba\xce\xae"}, ++ {ASN1_ETYPE_TELETEX_STRING, 15, ++ "\x53\x69\x6d\x6f\x6e\x20\x4a\x6f\x73\x65\x66\x73\x73\x6f\x6e", ++ 17, ++ "\x14\x0f\x53\x69\x6d\x6f\x6e\x20\x4a\x6f\x73\x65\x66\x73\x73\x6f\x6e"}, ++ {ASN1_ETYPE_OCTET_STRING, 36, ++ "\x30\x22\x80\x0F\x32\x30\x31\x31\x30\x38\x32\x31\x30\x38\x30\x30\x30\x36\x5A\x81\x0F\x32\x30\x31\x31\x30\x38\x32\x33\x32\x30\x35\x39\x35\x39\x5A", ++ 38, ++ "\x04\x24\x30\x22\x80\x0F\x32\x30\x31\x31\x30\x38\x32\x31\x30\x38\x30\x30\x30\x36\x5A\x81\x0F\x32\x30\x31\x31\x30\x38\x32\x33\x32\x30\x35\x39\x35\x39\x5A"} ++}; ++ ++#define SSTR(x) sizeof(x)-1,x ++static const struct tv ber[] = { ++ {ASN1_ETYPE_OCTET_STRING, ++ SSTR("\xa0\xa0"), ++ SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x00\x00")}, ++ {ASN1_ETYPE_OCTET_STRING, ++ SSTR("\xa0\xa0\xb0\xb0\xb0"), ++ SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x04\x82\x00\x03\xb0\xb0\xb0\x00\x00")}, ++ {ASN1_ETYPE_OCTET_STRING, ++ SSTR("\xa0\xa0\xb0\xb0\xb0\xa1\xa1"), ++ SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x04\x82\x00\x03\xb0\xb0\xb0\x24\x80\x04\x82\x00\x02\xa1\xa1\x00\x00\x00\x00")}, ++ {ASN1_ETYPE_OCTET_STRING, ++ SSTR("\xa0\xa0\xb0\xb0\xb0\xa1\xa1\xc1"), ++ SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x04\x82\x00\x03\xb0\xb0\xb0\x24\x80\x04\x82\x00\x02\xa1\xa1\x04\x82\x00\x01\xc1\x00\x00\x00\x00")}, ++}; ++ ++void ++test_strings () ++{ ++ int ret; ++ unsigned char tl[ASN1_MAX_TL_SIZE]; ++ unsigned int tl_len, der_len, str_len; ++ const unsigned char *str; ++ unsigned char *b; ++ unsigned int i; ++ ++ /* Dummy test */ ++ ++ for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++) ++ { ++ /* Encode */ ++ tl_len = sizeof (tl); ++ ret = asn1_encode_simple_der (tv[i].etype, tv[i].str, tv[i].str_len, ++ tl, &tl_len); ++ if (ret != ASN1_SUCCESS) ++ { ++ grub_fatal ("Encoding error in %u: %s\n", i, ++ asn1_strerror (ret)); ++ return; ++ } ++ der_len = tl_len + tv[i].str_len; ++ ++ if (der_len != tv[i].der_len || grub_memcmp (tl, tv[i].der, tl_len) != 0) ++ { ++ grub_fatal ( ++ "DER encoding differs in %u! (size: %u, expected: %u)\n", ++ i, der_len, tv[i].der_len); ++ return; ++ } ++ ++ /* decoding */ ++ ret = ++ asn1_decode_simple_der (tv[i].etype, tv[i].der, tv[i].der_len, &str, ++ &str_len); ++ if (ret != ASN1_SUCCESS) ++ { ++ grub_fatal ("Decoding error in %u: %s\n", i, ++ asn1_strerror (ret)); ++ return; ++ } ++ ++ if (str_len != tv[i].str_len || grub_memcmp (str, tv[i].str, str_len) != 0) ++ { ++ grub_fatal ( ++ "DER decoded data differ in %u! (size: %u, expected: %u)\n", ++ i, der_len, tv[i].str_len); ++ return; ++ } ++ } ++ ++ /* BER decoding */ ++ for (i = 0; i < sizeof (ber) / sizeof (ber[0]); i++) ++ { ++ /* decoding */ ++ ret = ++ asn1_decode_simple_ber (ber[i].etype, ber[i].der, ber[i].der_len, &b, ++ &str_len, NULL); ++ if (ret != ASN1_SUCCESS) ++ { ++ grub_fatal ("BER decoding error in %u: %s\n", i, ++ asn1_strerror (ret)); ++ return; ++ } ++ ++ if (str_len != ber[i].str_len || grub_memcmp (b, ber[i].str, str_len) != 0) ++ { ++ grub_fatal ( ++ "BER decoded data differ in %u! (size: %u, expected: %u)\n", ++ i, str_len, ber[i].str_len); ++ return; ++ } ++ grub_free(b); ++ } ++} +diff --git a/grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c b/grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c +new file mode 100644 +index 000000000..d367bbfb5 +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c +@@ -0,0 +1,116 @@ ++/* ++ * Copyright (C) 2016 Red Hat, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * This program 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. ++ * ++ * This program 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 this program. If not, see . ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include "../wrap_tests.h" ++ ++struct tv ++{ ++ int der_len; ++ const unsigned char *der; ++ const char *oid; ++ int expected_error; ++}; ++ ++static const struct tv tv[] = { ++ {.der_len = 5, ++ .der = (void *) "\x06\x03\x80\x37\x03", ++ .oid = "2.999.3", ++ .expected_error = ASN1_DER_ERROR /* leading 0x80 */ ++ }, ++ {.der_len = 12, ++ .der = (void *) "\x06\x0a\x2b\x06\x01\x80\x01\x92\x08\x09\x05\x01", ++ .oid = "1.3.6.1.4.1.2312.9.5.1", ++ .expected_error = ASN1_DER_ERROR /* leading 0x80 */ ++ }, ++ {.der_len = 6, ++ .der = (void *) "\x06\x04\x01\x02\x03\x04", ++ .oid = "0.1.2.3.4", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 5, ++ .der = (void *) "\x06\x03\x51\x02\x03", ++ .oid = "2.1.2.3", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 5, ++ .der = (void *) "\x06\x03\x88\x37\x03", ++ .oid = "2.999.3", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 12, ++ .der = (void *) "\x06\x0a\x2b\x06\x01\x04\x01\x92\x08\x09\x05\x01", ++ .oid = "1.3.6.1.4.1.2312.9.5.1", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 19, ++ .der = (void *) "\x06\x11\xfa\x80\x00\x00\x00\x0e\x01\x0e\xfa\x80\x00\x00\x00\x0e\x63\x6f\x6d", ++ .oid = "2.1998768.0.0.14.1.14.1998848.0.0.14.99.111.109", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 19, ++ .der = ++ (void *) ++ "\x06\x11\x2b\x06\x01\x04\x01\x92\x08\x09\x02\xaa\xda\xbe\xbe\xfa\x72\x01\x07", ++ .oid = "1.3.6.1.4.1.2312.9.2.1467399257458.1.7", ++ .expected_error = ASN1_SUCCESS}, ++}; ++ ++void ++test_object_id_decoding (void) ++{ ++ char str[128]; ++ int ret, ret_len; ++ grub_size_t i; ++ ++ for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++) ++ { ++ /* decode */ ++ ret = ++ asn1_get_object_id_der (tv[i].der+1, ++ tv[i].der_len-1, &ret_len, str, ++ sizeof (str)); ++ if (ret != tv[i].expected_error) ++ { ++ grub_fatal ( ++ "%d: asn1_get_object_id_der iter %lu: got '%s' expected %d\n", ++ __LINE__, (unsigned long) i, asn1_strerror(ret), tv[i].expected_error); ++ return; ++ } ++ ++ if (tv[i].expected_error != ASN1_SUCCESS) ++ continue; ++ ++ if (ret_len != tv[i].der_len-1) ++ { ++ grub_fatal ( ++ "%d: iter %lu: error in DER, length returned is %d, had %d\n", ++ __LINE__, (unsigned long)i, ret_len, tv[i].der_len-1); ++ return; ++ } ++ ++ if (grub_strcmp (tv[i].oid, str) != 0) ++ { ++ grub_fatal ( ++ "%d: strcmp iter %lu: got invalid OID: %s, expected: %s\n", ++ __LINE__, (unsigned long) i, str, tv[i].oid); ++ return; ++ } ++ ++ } ++} +diff --git a/grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c b/grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c +new file mode 100644 +index 000000000..3a83b58c5 +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c +@@ -0,0 +1,120 @@ ++/* ++ * Copyright (C) 2019 Nikos Mavrogiannopoulos ++ * ++ * This file is part of LIBTASN1. ++ * ++ * This program 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. ++ * ++ * This program 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 this program. If not, see . ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include "../wrap_tests.h" ++ ++struct tv ++{ ++ int der_len; ++ const unsigned char *der; ++ const char *oid; ++ int expected_error; ++}; ++ ++static const struct tv tv[] = { ++ {.der_len = 0, ++ .der = (void *) "", ++ .oid = "5.999.3", ++ .expected_error = ASN1_VALUE_NOT_VALID /* cannot start with 5 */ ++ }, ++ {.der_len = 0, ++ .der = (void *) "", ++ .oid = "0.48.9", ++ .expected_error = ASN1_VALUE_NOT_VALID /* second field cannot be 48 */ ++ }, ++ {.der_len = 0, ++ .der = (void *) "", ++ .oid = "1.40.9", ++ .expected_error = ASN1_VALUE_NOT_VALID /* second field cannot be 40 */ ++ }, ++ {.der_len = 4, ++ .der = (void *) "\x06\x02\x4f\x63", ++ .oid = "1.39.99", ++ .expected_error = ASN1_SUCCESS, ++ }, ++ {.der_len = 6, ++ .der = (void *) "\x06\x04\x01\x02\x03\x04", ++ .oid = "0.1.2.3.4", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 5, ++ .der = (void *) "\x06\x03\x51\x02\x03", ++ .oid = "2.1.2.3", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 5, ++ .der = (void *) "\x06\x03\x88\x37\x03", ++ .oid = "2.999.3", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 12, ++ .der = (void *) "\x06\x0a\x2b\x06\x01\x04\x01\x92\x08\x09\x05\x01", ++ .oid = "1.3.6.1.4.1.2312.9.5.1", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 19, ++ .der = (void *) "\x06\x11\xfa\x80\x00\x00\x00\x0e\x01\x0e\xfa\x80\x00\x00\x00\x0e\x63\x6f\x6d", ++ .oid = "2.1998768.0.0.14.1.14.1998848.0.0.14.99.111.109", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 19, ++ .der = ++ (void *) ++ "\x06\x11\x2b\x06\x01\x04\x01\x92\x08\x09\x02\xaa\xda\xbe\xbe\xfa\x72\x01\x07", ++ .oid = "1.3.6.1.4.1.2312.9.2.1467399257458.1.7", ++ .expected_error = ASN1_SUCCESS}, ++}; ++ ++void ++test_object_id_encoding(void) ++{ ++ unsigned char der[128]; ++ int ret, der_len, i; ++ ++ for (i = 0; i < (int)(sizeof (tv) / sizeof (tv[0])); i++) ++ { ++ der_len = sizeof(der); ++ ret = asn1_object_id_der(tv[i].oid, der, &der_len, 0); ++ if (ret != ASN1_SUCCESS) ++ { ++ if (ret == tv[i].expected_error) ++ continue; ++ grub_fatal ( ++ "%d: iter %lu, encoding of OID failed: %s\n", ++ __LINE__, (unsigned long) i, asn1_strerror(ret)); ++ return; ++ } ++ else if (ret != tv[i].expected_error) ++ { ++ grub_fatal ( ++ "%d: iter %lu, encoding of OID %s succeeded when expecting failure\n", ++ __LINE__, (unsigned long) i, tv[i].oid); ++ return; ++ } ++ ++ if (der_len != tv[i].der_len || grub_memcmp(der, tv[i].der, der_len) != 0) ++ { ++ grub_fatal ( ++ "%d: iter %lu, re-encoding of OID %s resulted to different string (%d vs %d bytes)\n", ++ __LINE__, (unsigned long) i, tv[i].oid, der_len, tv[i].der_len); ++ ++ return; ++ } ++ } ++} +diff --git a/grub-core/lib/libtasn1_wrap/tests/octet-string.c b/grub-core/lib/libtasn1_wrap/tests/octet-string.c +new file mode 100644 +index 000000000..d8a049e8d +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/octet-string.c +@@ -0,0 +1,211 @@ ++/* ++ * Copyright (C) 2011-2020 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * This program 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. ++ * ++ * This program 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 this program. If not, see . ++ * ++ * Written by Simon Josefsson and Nikos Mavrogiannopoulos ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include "../wrap_tests.h" ++ ++ ++struct tv ++{ ++ const char *name; ++ int der_len; ++ const unsigned char *der_str; ++ int len; ++ const unsigned char *string; ++ int expected_error; ++ int ber; ++}; ++ ++static const struct tv tv[] = { ++ {.name = "primitive octet strings", ++ .der_len = 10, ++ .der_str = ++ (void*)"\x04\x08\x01\x23\x45\x67\x89\xab\xcd\xef", ++ .len = 8, ++ .string = ++ (void*)"\x01\x23\x45\x67\x89\xab\xcd\xef", ++ .ber = 0}, ++ {.der_len = 22, ++ .der_str = ++ (void*)"\x04\x14\x13\x00\xd9\xa8\x47\xf7\xf2\x1c\xf4\xb0\xec\x5f\xc1\x73\xe5\x1b\x25\xc2\x62\x27", ++ .len = 20, ++ .string = ++ (void*)"\x13\x00\xD9\xA8\x47\xF7\xF2\x1C\xF4\xB0\xEC\x5F\xC1\x73\xE5\x1B\x25\xC2\x62\x27"}, ++ ++ {.name = "long type of length", ++ .der_len = 23, ++ .der_str = ++ (void*)"\x04\x81\x14\x13\x00\xd9\xa8\x47\xf7\xf2\x1c\xf4\xb0\xec\x5f\xc1\x73\xe5\x1b\x25\xc2\x62\x27", ++ .len = 20, ++ .string = ++ (void*)"\x13\x00\xD9\xA8\x47\xF7\xF2\x1C\xF4\xB0\xEC\x5F\xC1\x73\xE5\x1B\x25\xC2\x62\x27", ++ .ber = 1}, ++ {.der_len = 11, ++ .der_str = ++ (void*)"\x04\x81\x08\x01\x23\x45\x67\x89\xab\xcd\xef", ++ .len = 8, ++ .string = ++ (void*)"\x01\x23\x45\x67\x89\xab\xcd\xef", ++ .ber = 1}, ++ ++ {.name = "constructed - indefinite", ++ .der_len = 11, ++ .der_str = (void*)"\x24\x80\x04\x05\x01\x02\x03\x04\x05\x00\x00", ++ .len = 5, ++ .string = (void*)"\x01\x02\x03\x04\x05", ++ .ber = 1, ++ }, ++ ++ {.name = "constructed - definite - concat", ++ .der_len = 12, ++ .der_str = (void*)"\x24\x0a\x04\x04\x0a\x0b\x0c\x0d\x04\x02\x0e\x0f", ++ .len = 6, ++ .string = (void*)"\x0a\x0b\x0c\x0d\x0e\x0f", ++ .ber = 1, ++ }, ++ {.name = "constructed - definite - recursive", ++ .der_len = 15, ++ .der_str = (void*)"\x24\x0d\x04\x04\x0a\x0b\x0c\x0d\x24\x05\x04\x00\x04\x01\x0f", ++ .len = 5, ++ .string = (void*)"\x0a\x0b\x0c\x0d\x0f", ++ .ber = 1, ++ }, ++ {.name = "constructed - definite - single", ++ .der_len = 7, ++ .der_str = (void*)"\x24\x05\x04\x03\x01\x02\x03", ++ .len = 3, ++ .string = (void*)"\x01\x02\x03", ++ .ber = 1, ++ }, ++ ++ /* a large amount of recursive indefinite encoding */ ++ {.name = "a large amount of recursive indefinite encoding", ++ .der_len = 29325, ++ .der_str = (void*)"\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80", ++ .len = 0, ++ .ber = 1, ++ .expected_error = ASN1_DER_ERROR ++ } ++}; ++ ++void ++test_octet_string (void) ++{ ++ unsigned char str[100]; ++ unsigned char der[100]; ++ int der_len = sizeof (der); ++ int str_size = sizeof (str); ++ unsigned char *tmp = NULL; ++ int ret, ret_len; ++ grub_size_t i; ++ ++ for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++) ++ { ++ /* Decode */ ++ ++ if (tv[i].ber == 0) ++ { ++ str_size = sizeof (str); ++ ret = ++ asn1_get_octet_der (tv[i].der_str + 1, ++ tv[i].der_len - 1, &ret_len, str, ++ sizeof (str), &str_size); ++ if (ret != tv[i].expected_error) ++ { ++ grub_fatal ( ++ "%d: asn1_get_octet_der: %s: got %d expected %d\n", ++ __LINE__, tv[i].name, ret, ++ tv[i].expected_error); ++ return; ++ } ++ if (tv[i].expected_error) ++ continue; ++ ++ if (ret_len != tv[i].der_len - 1) ++ { ++ grub_fatal ( ++ "%d: error in DER, length returned is %d, had %d\n", ++ __LINE__, ret_len, tv[i].der_len - 1); ++ return; ++ } ++ ++ if (str_size != tv[i].len ++ || grub_memcmp (tv[i].string, str, tv[i].len) != 0) ++ { ++ grub_fatal ( ++ "%d: memcmp: %s: got invalid decoding\n", ++ __LINE__, tv[i].name); ++ ++ return; ++ } ++ ++ /* Encode */ ++ der_len = sizeof (der); ++ asn1_octet_der (str, str_size, der, &der_len); ++ ++ if (der_len != tv[i].der_len - 1 ++ || grub_memcmp (tv[i].der_str + 1, der, tv[i].der_len - 1) != 0) ++ { ++ grub_fatal ( ++ "encoding: %s: got invalid encoding\n", ++ tv[i].name); ++ return; ++ } ++ } ++ ++ ret = ++ asn1_decode_simple_ber (ASN1_ETYPE_OCTET_STRING, ++ tv[i].der_str, tv[i].der_len, ++ &tmp, (unsigned int*)&str_size, (unsigned int*)&der_len); ++ if (ret != tv[i].expected_error) ++ { ++ grub_fatal ( ++ "%d: asn1_decode_simple_ber: %s: got %s expected %s\n", ++ __LINE__, tv[i].name, asn1_strerror(ret), asn1_strerror(tv[i].expected_error)); ++ return; ++ } ++ if (tv[i].expected_error) ++ continue; ++ ++ if (der_len != tv[i].der_len) ++ { ++ grub_fatal ( ++ "%d: error: %s: DER, length returned is %d, had %d\n", ++ __LINE__, tv[i].name, der_len, tv[i].der_len); ++ return; ++ } ++ ++ if (str_size != tv[i].len || grub_memcmp (tv[i].string, tmp, tv[i].len) != 0) ++ { ++ grub_fatal ( ++ "%d: memcmp: %s: got invalid decoding\n", ++ __LINE__, tv[i].name); ++ return; ++ } ++ grub_free (tmp); ++ tmp = NULL; ++ ++ } ++} +diff --git a/grub-core/lib/libtasn1_wrap/tests/reproducers.c b/grub-core/lib/libtasn1_wrap/tests/reproducers.c +new file mode 100644 +index 000000000..dc7268d4c +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/reproducers.c +@@ -0,0 +1,81 @@ ++/* ++ * Copyright (C) 2019 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * This program 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. ++ * ++ * This program 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 this program. If not, see . ++ * ++ */ ++ ++/****************************************************************/ ++/* Description: run reproducers for several fixed issues */ ++/****************************************************************/ ++ ++#include ++#include ++#include ++#include "../wrap_tests.h" ++ ++#define CONST_DOWN (1U<<29) ++ ++/* produces endless loop (fixed by d4b624b2): ++ * The following translates into a single node with all pointers ++ * (right,left,down) set to NULL. */ ++const asn1_static_node endless_asn1_tab[] = { ++ { "TEST_TREE", 536875024, NULL }, ++ { NULL, 0, NULL } ++}; ++ ++/* produces memory leak (fixed by f16d1ff9): ++ * 152 bytes in 1 blocks are definitely lost in loss record 1 of 1 ++ * at 0x4837B65: calloc (vg_replace_malloc.c:762) ++ * by 0x4851C0D: _asn1_add_static_node (parser_aux.c:71) ++ * by 0x4853AAC: asn1_array2tree (structure.c:200) ++ * by 0x10923B: main (single_node.c:67) ++ */ ++const asn1_static_node tab[] = { ++{ "a", CONST_DOWN, "" }, ++{ "b", 0, "" }, ++{ "c", 0, "" }, ++{ NULL, 0, NULL } ++}; ++ ++void ++test_reproducers (void) ++{ ++ int result; ++ asn1_node definitions = NULL; ++ char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; ++ ++ result = asn1_array2tree (endless_asn1_tab, &definitions, errorDescription); ++ if (result != ASN1_SUCCESS) ++ { ++ grub_fatal ("Error: %s\nErrorDescription = %s\n\n", ++ asn1_strerror (result), errorDescription); ++ return; ++ } ++ ++ asn1_delete_structure (&definitions); ++ ++ definitions = NULL; ++ result = asn1_array2tree (tab, &definitions, errorDescription); ++ if (result != ASN1_SUCCESS) ++ { ++ grub_fatal ("Error: %s\nErrorDescription = %s\n\n", ++ asn1_strerror (result), errorDescription); ++ return; ++ } ++ ++ asn1_delete_structure (&definitions); ++} +diff --git a/grub-core/lib/libtasn1_wrap/wrap_tests.c b/grub-core/lib/libtasn1_wrap/wrap_tests.c +new file mode 100644 +index 000000000..75fcd21f0 +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/wrap_tests.c +@@ -0,0 +1,75 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 IBM Corporation ++ * ++ * 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 . ++ */ ++ ++#include ++#include ++#include ++#include "wrap_tests.h" ++ ++/* ++ * libtasn1 tests - from which this is derived - are provided under GPL3+. ++ */ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static grub_command_t cmd; ++ ++static grub_err_t ++grub_cmd_asn1test (grub_command_t cmdd __attribute__((unused)), ++ int argc __attribute__((unused)), ++ char **args __attribute__((unused))) ++{ ++ grub_printf ("test_CVE_2018_1000654\n"); ++ test_CVE_2018_1000654 (); ++ ++ grub_printf ("test_object_id_decoding\n"); ++ test_object_id_decoding (); ++ ++ grub_printf ("test_object_id_encoding\n"); ++ test_object_id_encoding (); ++ ++ grub_printf ("test_octet_string\n"); ++ test_octet_string (); ++ ++ grub_printf ("test_overflow\n"); ++ test_overflow (); ++ ++ grub_printf ("test_reproducers\n"); ++ test_overflow (); ++ ++ grub_printf ("test_simple\n"); ++ test_simple (); ++ ++ grub_printf ("test_strings\n"); ++ test_strings (); ++ ++ grub_printf ("ASN.1 self-tests passed\n"); ++ ++ return GRUB_ERR_NONE; ++} ++ ++ ++GRUB_MOD_INIT(test_asn1) ++{ ++ cmd = grub_register_command ("test_asn1", grub_cmd_asn1test, NULL, ++ "Run self-tests for the ASN.1 parser."); ++} ++ ++GRUB_MOD_FINI(test_asn1) ++{ ++ grub_unregister_command (cmd); ++} +diff --git a/grub-core/lib/libtasn1_wrap/wrap_tests.h b/grub-core/lib/libtasn1_wrap/wrap_tests.h +new file mode 100644 +index 000000000..555e56dd2 +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/wrap_tests.h +@@ -0,0 +1,38 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 IBM Corporation ++ * ++ * 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 . ++ */ ++ ++#ifndef LIBTASN1_WRAP_TESTS_H ++#define LIBTASN1_WRAP_TESTS_H ++ ++void test_CVE_2018_1000654 (void); ++ ++void test_object_id_encoding (void); ++ ++void test_object_id_decoding (void); ++ ++void test_octet_string (void); ++ ++void test_overflow (void); ++ ++void test_reproducers (void); ++ ++void test_simple (void); ++ ++void test_strings (void); ++ ++#endif +diff --git a/tests/test_asn1.in b/tests/test_asn1.in +new file mode 100644 +index 000000000..8173c5c27 +--- /dev/null ++++ b/tests/test_asn1.in +@@ -0,0 +1,12 @@ ++#! @BUILD_SHEBANG@ ++set -e ++ ++. "@builddir@/grub-core/modinfo.sh" ++ ++out=`echo test_asn1 | @builddir@/grub-shell` ++ ++if [ "$(echo "$out" | tail -n 1)" != "ASN.1 self-tests passed" ]; then ++ echo "ASN.1 test failure: $out" ++ exit 1 ++fi ++ +-- +2.31.1 + diff --git a/0015-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch b/0015-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch new file mode 100644 index 0000000..a33bb4a --- /dev/null +++ b/0015-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch @@ -0,0 +1,77 @@ +From 9a6e9ad21eb2f414dce6eaedd41e146a28142101 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Wed, 7 Jul 2021 15:38:19 +1000 +Subject: [PATCH 15/32] video/readers/jpeg: Block int underflow -> wild pointer + write + +Certain 1 px wide images caused a wild pointer write in +grub_jpeg_ycrcb_to_rgb(). This was caused because in grub_jpeg_decode_data(), +we have the following loop: + +for (; data->r1 < nr1 && (!data->dri || rst); + data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3) + +We did not check if vb * width >= hb * nc1. + +On a 64-bit platform, if that turns out to be negative, it will underflow, +be interpreted as unsigned 64-bit, then be added to the 64-bit pointer, so +we see data->bitmap_ptr jump, e.g.: + +0x6180_0000_0480 to +0x6181_0000_0498 + ^ + ~--- carry has occurred and this pointer is now far away from + any object. + +On a 32-bit platform, it will decrement the pointer, creating a pointer +that won't crash but will overwrite random data. + +Catch the underflow and error out. + +Fixes: CVE-2021-3697 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/video/readers/jpeg.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index 1df1171d78..97a533b24f 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -693,6 +694,7 @@ static grub_err_t + grub_jpeg_decode_data (struct grub_jpeg_data *data) + { + unsigned c1, vb, hb, nr1, nc1; ++ unsigned stride_a, stride_b, stride; + int rst = data->dri; + grub_err_t err = GRUB_ERR_NONE; + +@@ -705,8 +707,14 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: attempted to decode data before start of stream"); + ++ if (grub_mul(vb, data->image_width, &stride_a) || ++ grub_mul(hb, nc1, &stride_b) || ++ grub_sub(stride_a, stride_b, &stride)) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: cannot decode image with these dimensions"); ++ + for (; data->r1 < nr1 && (!data->dri || rst); +- data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3) ++ data->r1++, data->bitmap_ptr += stride * 3) + for (c1 = 0; c1 < nc1 && (!data->dri || rst); + c1++, rst--, data->bitmap_ptr += hb * 3) + { +-- +2.34.1 + diff --git a/0016-grub-install-support-embedding-x509-certificates.patch b/0016-grub-install-support-embedding-x509-certificates.patch new file mode 100644 index 0000000..4b1910f --- /dev/null +++ b/0016-grub-install-support-embedding-x509-certificates.patch @@ -0,0 +1,257 @@ +From a0e17ba00ac128759d40e2bfc751716f45542ac0 Mon Sep 17 00:00:00 2001 +From: Alastair D'Silva +Date: Mon, 6 Jul 2020 13:33:04 +1000 +Subject: [PATCH 16/23] grub-install: support embedding x509 certificates + +To support verification of appended signatures, we need a way to +embed the necessary public keys. Existing appended signature schemes +in the Linux kernel use X.509 certificates, so allow certificates to +be embedded in the grub core image in the same way as PGP keys. + +Signed-off-by: Alastair D'Silva +Signed-off-by: Daniel Axtens +--- + grub-core/commands/pgp.c | 2 +- + include/grub/kernel.h | 3 ++- + include/grub/util/install.h | 7 +++++-- + util/grub-install-common.c | 22 +++++++++++++++++++- + util/grub-mkimage.c | 15 ++++++++++++-- + util/mkimage.c | 41 ++++++++++++++++++++++++++++++++++--- + 6 files changed, 80 insertions(+), 10 deletions(-) + +diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c +index 355a43844..b81ac0ae4 100644 +--- a/grub-core/commands/pgp.c ++++ b/grub-core/commands/pgp.c +@@ -944,7 +944,7 @@ GRUB_MOD_INIT(pgp) + grub_memset (&pseudo_file, 0, sizeof (pseudo_file)); + + /* Not an ELF module, skip. */ +- if (header->type != OBJ_TYPE_PUBKEY) ++ if (header->type != OBJ_TYPE_GPG_PUBKEY) + continue; + + pseudo_file.fs = &pseudo_fs; +diff --git a/include/grub/kernel.h b/include/grub/kernel.h +index abbca5ea3..d3aafc884 100644 +--- a/include/grub/kernel.h ++++ b/include/grub/kernel.h +@@ -28,7 +28,8 @@ enum + OBJ_TYPE_MEMDISK, + OBJ_TYPE_CONFIG, + OBJ_TYPE_PREFIX, +- OBJ_TYPE_PUBKEY, ++ OBJ_TYPE_GPG_PUBKEY, ++ OBJ_TYPE_X509_PUBKEY, + OBJ_TYPE_DTB, + OBJ_TYPE_DISABLE_SHIM_LOCK + }; +diff --git a/include/grub/util/install.h b/include/grub/util/install.h +index 0b2e8a06d..c241a2a40 100644 +--- a/include/grub/util/install.h ++++ b/include/grub/util/install.h +@@ -67,6 +67,8 @@ + N_("SBAT metadata"), 0 }, \ + { "disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, \ + N_("disable shim_lock verifier"), 0 }, \ ++ { "x509key", 'x', N_("FILE"), 0, \ ++ N_("embed FILE as an x509 certificate for signature checking"), 0}, \ + { "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,\ + "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), \ + 1}, \ +@@ -189,8 +191,9 @@ void + grub_install_generate_image (const char *dir, const char *prefix, + FILE *out, + const char *outname, char *mods[], +- char *memdisk_path, char **pubkey_paths, +- size_t npubkeys, ++ char *memdisk_path, ++ char **pubkey_paths, size_t npubkeys, ++ char **x509key_paths, size_t nx509keys, + char *config_path, + const struct grub_install_image_target_desc *image_target, + int note, size_t appsig_size, +diff --git a/util/grub-install-common.c b/util/grub-install-common.c +index 954df20eb..44296afa0 100644 +--- a/util/grub-install-common.c ++++ b/util/grub-install-common.c +@@ -460,6 +460,8 @@ static char **pubkeys; + static size_t npubkeys; + static char *sbat; + static int disable_shim_lock; ++static char **x509keys; ++static size_t nx509keys; + static grub_compression_t compression; + static size_t appsig_size; + +@@ -501,6 +503,12 @@ grub_install_parse (int key, char *arg) + case GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK: + disable_shim_lock = 1; + return 1; ++ case 'x': ++ x509keys = xrealloc (x509keys, ++ sizeof (x509keys[0]) ++ * (nx509keys + 1)); ++ x509keys[nx509keys++] = xstrdup (arg); ++ return 1; + + case GRUB_INSTALL_OPTIONS_VERBOSITY: + verbosity++; +@@ -627,6 +635,9 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, + for (pk = pubkeys; pk < pubkeys + npubkeys; pk++) + slen += 20 + grub_strlen (*pk); + ++ for (pk = x509keys; pk < x509keys + nx509keys; pk++) ++ slen += 10 + grub_strlen (*pk); ++ + for (md = modules.entries; *md; md++) + { + slen += 10 + grub_strlen (*md); +@@ -655,6 +666,14 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, + *p++ = ' '; + } + ++ for (pk = x509keys; pk < x509keys + nx509keys; pk++) ++ { ++ p = grub_stpcpy (p, "--x509 '"); ++ p = grub_stpcpy (p, *pk); ++ *p++ = '\''; ++ *p++ = ' '; ++ } ++ + for (md = modules.entries; *md; md++) + { + *p++ = '\''; +@@ -683,7 +702,8 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, + + grub_install_generate_image (dir, prefix, fp, outname, + modules.entries, memdisk_path, +- pubkeys, npubkeys, config_path, tgt, ++ pubkeys, npubkeys, x509keys, nx509keys, ++ config_path, tgt, + note, appsig_size, compression, dtb, sbat, + disable_shim_lock); + while (dc--) +diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c +index d01eaeb84..7d61ef3ea 100644 +--- a/util/grub-mkimage.c ++++ b/util/grub-mkimage.c +@@ -75,7 +75,8 @@ static struct argp_option options[] = { + /* TRANSLATORS: "embed" is a verb (command description). "*/ + {"config", 'c', N_("FILE"), 0, N_("embed FILE as an early config"), 0}, + /* TRANSLATORS: "embed" is a verb (command description). "*/ +- {"pubkey", 'k', N_("FILE"), 0, N_("embed FILE as public key for signature checking"), 0}, ++ {"pubkey", 'k', N_("FILE"), 0, N_("embed FILE as public key for PGP signature checking"), 0}, ++ {"x509", 'x', N_("FILE"), 0, N_("embed FILE as an x509 certificate for appended signature checking"), 0}, + /* TRANSLATORS: NOTE is a name of segment. */ + {"note", 'n', 0, 0, N_("add NOTE segment for CHRP IEEE1275"), 0}, + {"output", 'o', N_("FILE"), 0, N_("output a generated image to FILE [default=stdout]"), 0}, +@@ -124,6 +125,8 @@ struct arguments + char *dtb; + char **pubkeys; + size_t npubkeys; ++ char **x509keys; ++ size_t nx509keys; + char *font; + char *config; + char *sbat; +@@ -206,6 +209,13 @@ argp_parser (int key, char *arg, struct argp_state *state) + arguments->pubkeys[arguments->npubkeys++] = xstrdup (arg); + break; + ++ case 'x': ++ arguments->x509keys = xrealloc (arguments->x509keys, ++ sizeof (arguments->x509keys[0]) ++ * (arguments->nx509keys + 1)); ++ arguments->x509keys[arguments->nx509keys++] = xstrdup (arg); ++ break; ++ + case 'c': + if (arguments->config) + free (arguments->config); +@@ -332,7 +342,8 @@ main (int argc, char *argv[]) + grub_install_generate_image (arguments.dir, arguments.prefix, fp, + arguments.output, arguments.modules, + arguments.memdisk, arguments.pubkeys, +- arguments.npubkeys, arguments.config, ++ arguments.npubkeys, arguments.x509keys, ++ arguments.nx509keys, arguments.config, + arguments.image_target, arguments.note, + arguments.appsig_size, + arguments.comp, arguments.dtb, +diff --git a/util/mkimage.c b/util/mkimage.c +index d2cb33883..5a8021a21 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -866,8 +866,10 @@ init_pe_section(const struct grub_install_image_target_desc *image_target, + void + grub_install_generate_image (const char *dir, const char *prefix, + FILE *out, const char *outname, char *mods[], +- char *memdisk_path, char **pubkey_paths, +- size_t npubkeys, char *config_path, ++ char *memdisk_path, ++ char **pubkey_paths, size_t npubkeys, ++ char **x509key_paths, size_t nx509keys, ++ char *config_path, + const struct grub_install_image_target_desc *image_target, + int note, size_t appsig_size, grub_compression_t comp, + const char *dtb_path, const char *sbat_path, +@@ -913,6 +915,19 @@ grub_install_generate_image (const char *dir, const char *prefix, + } + } + ++ { ++ size_t i; ++ for (i = 0; i < nx509keys; i++) ++ { ++ size_t curs; ++ curs = ALIGN_ADDR (grub_util_get_image_size (x509key_paths[i])); ++ grub_util_info ("the size of x509 public key %u is 0x%" ++ GRUB_HOST_PRIxLONG_LONG, ++ (unsigned) i, (unsigned long long) curs); ++ total_module_size += curs + sizeof (struct grub_module_header); ++ } ++ } ++ + if (memdisk_path) + { + memdisk_size = ALIGN_UP(grub_util_get_image_size (memdisk_path), 512); +@@ -1034,7 +1049,7 @@ grub_install_generate_image (const char *dir, const char *prefix, + curs = grub_util_get_image_size (pubkey_paths[i]); + + header = (struct grub_module_header *) (kernel_img + offset); +- header->type = grub_host_to_target32 (OBJ_TYPE_PUBKEY); ++ header->type = grub_host_to_target32 (OBJ_TYPE_GPG_PUBKEY); + header->size = grub_host_to_target32 (curs + sizeof (*header)); + offset += sizeof (*header); + +@@ -1043,6 +1058,26 @@ grub_install_generate_image (const char *dir, const char *prefix, + } + } + ++ { ++ size_t i; ++ for (i = 0; i < nx509keys; i++) ++ { ++ size_t curs; ++ struct grub_module_header *header; ++ ++ curs = grub_util_get_image_size (x509key_paths[i]); ++ ++ header = (struct grub_module_header *) (kernel_img + offset); ++ header->type = grub_host_to_target32 (OBJ_TYPE_X509_PUBKEY); ++ header->size = grub_host_to_target32 (curs + sizeof (*header)); ++ offset += sizeof (*header); ++ ++ grub_util_load_image (x509key_paths[i], kernel_img + offset); ++ offset += ALIGN_ADDR (curs); ++ } ++ } ++ ++ + if (memdisk_path) + { + struct grub_module_header *header; +-- +2.31.1 + diff --git a/0016-normal-charset-Fix-array-out-of-bounds-formatting-un.patch b/0016-normal-charset-Fix-array-out-of-bounds-formatting-un.patch new file mode 100644 index 0000000..91648c9 --- /dev/null +++ b/0016-normal-charset-Fix-array-out-of-bounds-formatting-un.patch @@ -0,0 +1,36 @@ +From cfe96e5c432b58726047f4d94f106f58855db1e2 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 13 Jul 2021 13:24:38 +1000 +Subject: [PATCH 16/32] normal/charset: Fix array out-of-bounds formatting + unicode for display + +In some cases attempting to display arbitrary binary strings leads +to ASAN splats reading the widthspec array out of bounds. + +Check the index. If it would be out of bounds, return a width of 1. +I don't know if that's strictly correct, but we're not really expecting +great display of arbitrary binary data, and it's certainly not worse than +an OOB read. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/normal/charset.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/grub-core/normal/charset.c b/grub-core/normal/charset.c +index 4dfcc31078..7a5a7c153c 100644 +--- a/grub-core/normal/charset.c ++++ b/grub-core/normal/charset.c +@@ -395,6 +395,8 @@ grub_unicode_estimate_width (const struct grub_unicode_glyph *c) + { + if (grub_unicode_get_comb_type (c->base)) + return 0; ++ if (((unsigned long) (c->base >> 3)) >= ARRAY_SIZE (widthspec)) ++ return 1; + if (widthspec[c->base >> 3] & (1 << (c->base & 7))) + return 2; + else +-- +2.34.1 + diff --git a/0017-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch b/0017-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch new file mode 100644 index 0000000..cb43853 --- /dev/null +++ b/0017-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch @@ -0,0 +1,643 @@ +From f948da0bef477fe9d95fbcb13eb2c4f45f1b6ea0 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 30 Jul 2020 01:35:10 +1000 +Subject: [PATCH 17/23] appended signatures: import GNUTLS's ASN.1 description + files + +In order to parse PKCS#7 messages and X.509 certificates with libtasn1, +we need some information about how they are encoded. + +We get these from GNUTLS, which has the benefit that they support the +features we need and are well tested. + +The GNUTLS license is LGPLv2.1+, which is GPLv3 compatible, allowing +us to import it without issue. + +Signed-off-by: Daniel Axtens +--- + .../commands/appendedsig/gnutls_asn1_tab.c | 121 +++++ + .../commands/appendedsig/pkix_asn1_tab.c | 484 ++++++++++++++++++ + 2 files changed, 605 insertions(+) + create mode 100644 grub-core/commands/appendedsig/gnutls_asn1_tab.c + create mode 100644 grub-core/commands/appendedsig/pkix_asn1_tab.c + +diff --git a/grub-core/commands/appendedsig/gnutls_asn1_tab.c b/grub-core/commands/appendedsig/gnutls_asn1_tab.c +new file mode 100644 +index 000000000..ddd1314e6 +--- /dev/null ++++ b/grub-core/commands/appendedsig/gnutls_asn1_tab.c +@@ -0,0 +1,121 @@ ++#include ++#include ++ ++const asn1_static_node gnutls_asn1_tab[] = { ++ { "GNUTLS", 536872976, NULL }, ++ { NULL, 1073741836, NULL }, ++ { "RSAPublicKey", 1610612741, NULL }, ++ { "modulus", 1073741827, NULL }, ++ { "publicExponent", 3, NULL }, ++ { "RSAPrivateKey", 1610612741, NULL }, ++ { "version", 1073741827, NULL }, ++ { "modulus", 1073741827, NULL }, ++ { "publicExponent", 1073741827, NULL }, ++ { "privateExponent", 1073741827, NULL }, ++ { "prime1", 1073741827, NULL }, ++ { "prime2", 1073741827, NULL }, ++ { "exponent1", 1073741827, NULL }, ++ { "exponent2", 1073741827, NULL }, ++ { "coefficient", 1073741827, NULL }, ++ { "otherPrimeInfos", 16386, "OtherPrimeInfos"}, ++ { "ProvableSeed", 1610612741, NULL }, ++ { "algorithm", 1073741836, NULL }, ++ { "seed", 7, NULL }, ++ { "OtherPrimeInfos", 1612709899, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "OtherPrimeInfo"}, ++ { "OtherPrimeInfo", 1610612741, NULL }, ++ { "prime", 1073741827, NULL }, ++ { "exponent", 1073741827, NULL }, ++ { "coefficient", 3, NULL }, ++ { "AlgorithmIdentifier", 1610612741, NULL }, ++ { "algorithm", 1073741836, NULL }, ++ { "parameters", 541081613, NULL }, ++ { "algorithm", 1, NULL }, ++ { "DigestInfo", 1610612741, NULL }, ++ { "digestAlgorithm", 1073741826, "DigestAlgorithmIdentifier"}, ++ { "digest", 7, NULL }, ++ { "DigestAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"}, ++ { "DSAPublicKey", 1073741827, NULL }, ++ { "DSAParameters", 1610612741, NULL }, ++ { "p", 1073741827, NULL }, ++ { "q", 1073741827, NULL }, ++ { "g", 3, NULL }, ++ { "DSASignatureValue", 1610612741, NULL }, ++ { "r", 1073741827, NULL }, ++ { "s", 3, NULL }, ++ { "DSAPrivateKey", 1610612741, NULL }, ++ { "version", 1073741827, NULL }, ++ { "p", 1073741827, NULL }, ++ { "q", 1073741827, NULL }, ++ { "g", 1073741827, NULL }, ++ { "Y", 1073741827, NULL }, ++ { "priv", 3, NULL }, ++ { "DHParameter", 1610612741, NULL }, ++ { "prime", 1073741827, NULL }, ++ { "base", 1073741827, NULL }, ++ { "privateValueLength", 16387, NULL }, ++ { "ECParameters", 1610612754, NULL }, ++ { "namedCurve", 12, NULL }, ++ { "ECPrivateKey", 1610612741, NULL }, ++ { "Version", 1073741827, NULL }, ++ { "privateKey", 1073741831, NULL }, ++ { "parameters", 1610637314, "ECParameters"}, ++ { NULL, 2056, "0"}, ++ { "publicKey", 536895494, NULL }, ++ { NULL, 2056, "1"}, ++ { "PrincipalName", 1610612741, NULL }, ++ { "name-type", 1610620931, NULL }, ++ { NULL, 2056, "0"}, ++ { "name-string", 536879115, NULL }, ++ { NULL, 1073743880, "1"}, ++ { NULL, 27, NULL }, ++ { "KRB5PrincipalName", 1610612741, NULL }, ++ { "realm", 1610620955, NULL }, ++ { NULL, 2056, "0"}, ++ { "principalName", 536879106, "PrincipalName"}, ++ { NULL, 2056, "1"}, ++ { "RSAPSSParameters", 1610612741, NULL }, ++ { "hashAlgorithm", 1610637314, "AlgorithmIdentifier"}, ++ { NULL, 2056, "0"}, ++ { "maskGenAlgorithm", 1610637314, "AlgorithmIdentifier"}, ++ { NULL, 2056, "1"}, ++ { "saltLength", 1610653699, NULL }, ++ { NULL, 1073741833, "20"}, ++ { NULL, 2056, "2"}, ++ { "trailerField", 536911875, NULL }, ++ { NULL, 1073741833, "1"}, ++ { NULL, 2056, "3"}, ++ { "GOSTParameters", 1610612741, NULL }, ++ { "publicKeyParamSet", 1073741836, NULL }, ++ { "digestParamSet", 16396, NULL }, ++ { "GOSTParametersOld", 1610612741, NULL }, ++ { "publicKeyParamSet", 1073741836, NULL }, ++ { "digestParamSet", 1073741836, NULL }, ++ { "encryptionParamSet", 16396, NULL }, ++ { "GOSTPrivateKey", 1073741831, NULL }, ++ { "GOSTPrivateKeyOld", 1073741827, NULL }, ++ { "IssuerSignTool", 1610612741, NULL }, ++ { "signTool", 1073741858, NULL }, ++ { "cATool", 1073741858, NULL }, ++ { "signToolCert", 1073741858, NULL }, ++ { "cAToolCert", 34, NULL }, ++ { "Gost28147-89-EncryptedKey", 1610612741, NULL }, ++ { "encryptedKey", 1073741831, NULL }, ++ { "maskKey", 1610637319, NULL }, ++ { NULL, 4104, "0"}, ++ { "macKey", 7, NULL }, ++ { "SubjectPublicKeyInfo", 1610612741, NULL }, ++ { "algorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "subjectPublicKey", 6, NULL }, ++ { "GostR3410-TransportParameters", 1610612741, NULL }, ++ { "encryptionParamSet", 1073741836, NULL }, ++ { "ephemeralPublicKey", 1610637314, "SubjectPublicKeyInfo"}, ++ { NULL, 4104, "0"}, ++ { "ukm", 7, NULL }, ++ { "GostR3410-KeyTransport", 536870917, NULL }, ++ { "sessionEncryptedKey", 1073741826, "Gost28147-89-EncryptedKey"}, ++ { "transportParameters", 536895490, "GostR3410-TransportParameters"}, ++ { NULL, 4104, "0"}, ++ { NULL, 0, NULL } ++}; +diff --git a/grub-core/commands/appendedsig/pkix_asn1_tab.c b/grub-core/commands/appendedsig/pkix_asn1_tab.c +new file mode 100644 +index 000000000..adef69d95 +--- /dev/null ++++ b/grub-core/commands/appendedsig/pkix_asn1_tab.c +@@ -0,0 +1,484 @@ ++#include ++#include ++ ++const asn1_static_node pkix_asn1_tab[] = { ++ { "PKIX1", 536875024, NULL }, ++ { NULL, 1073741836, NULL }, ++ { "PrivateKeyUsagePeriod", 1610612741, NULL }, ++ { "notBefore", 1610637349, NULL }, ++ { NULL, 4104, "0"}, ++ { "notAfter", 536895525, NULL }, ++ { NULL, 4104, "1"}, ++ { "AuthorityKeyIdentifier", 1610612741, NULL }, ++ { "keyIdentifier", 1610637319, NULL }, ++ { NULL, 4104, "0"}, ++ { "authorityCertIssuer", 1610637314, "GeneralNames"}, ++ { NULL, 4104, "1"}, ++ { "authorityCertSerialNumber", 536895490, "CertificateSerialNumber"}, ++ { NULL, 4104, "2"}, ++ { "SubjectKeyIdentifier", 1073741831, NULL }, ++ { "KeyUsage", 1073741830, NULL }, ++ { "DirectoryString", 1610612754, NULL }, ++ { "teletexString", 1612709918, NULL }, ++ { "MAX", 524298, "1"}, ++ { "printableString", 1612709919, NULL }, ++ { "MAX", 524298, "1"}, ++ { "universalString", 1612709920, NULL }, ++ { "MAX", 524298, "1"}, ++ { "utf8String", 1612709922, NULL }, ++ { "MAX", 524298, "1"}, ++ { "bmpString", 1612709921, NULL }, ++ { "MAX", 524298, "1"}, ++ { "ia5String", 538968093, NULL }, ++ { "MAX", 524298, "1"}, ++ { "SubjectAltName", 1073741826, "GeneralNames"}, ++ { "GeneralNames", 1612709899, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "GeneralName"}, ++ { "GeneralName", 1610612754, NULL }, ++ { "otherName", 1610620930, "AnotherName"}, ++ { NULL, 4104, "0"}, ++ { "rfc822Name", 1610620957, NULL }, ++ { NULL, 4104, "1"}, ++ { "dNSName", 1610620957, NULL }, ++ { NULL, 4104, "2"}, ++ { "x400Address", 1610620941, NULL }, ++ { NULL, 4104, "3"}, ++ { "directoryName", 1610620939, NULL }, ++ { NULL, 1073743880, "4"}, ++ { NULL, 2, "RelativeDistinguishedName"}, ++ { "ediPartyName", 1610620941, NULL }, ++ { NULL, 4104, "5"}, ++ { "uniformResourceIdentifier", 1610620957, NULL }, ++ { NULL, 4104, "6"}, ++ { "iPAddress", 1610620935, NULL }, ++ { NULL, 4104, "7"}, ++ { "registeredID", 536879116, NULL }, ++ { NULL, 4104, "8"}, ++ { "AnotherName", 1610612741, NULL }, ++ { "type-id", 1073741836, NULL }, ++ { "value", 541073421, NULL }, ++ { NULL, 1073743880, "0"}, ++ { "type-id", 1, NULL }, ++ { "IssuerAltName", 1073741826, "GeneralNames"}, ++ { "BasicConstraints", 1610612741, NULL }, ++ { "cA", 1610645508, NULL }, ++ { NULL, 131081, NULL }, ++ { "pathLenConstraint", 537411587, NULL }, ++ { "0", 10, "MAX"}, ++ { "CRLDistributionPoints", 1612709899, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "DistributionPoint"}, ++ { "DistributionPoint", 1610612741, NULL }, ++ { "distributionPoint", 1610637314, "DistributionPointName"}, ++ { NULL, 2056, "0"}, ++ { "reasons", 1610637314, "ReasonFlags"}, ++ { NULL, 4104, "1"}, ++ { "cRLIssuer", 536895490, "GeneralNames"}, ++ { NULL, 4104, "2"}, ++ { "DistributionPointName", 1610612754, NULL }, ++ { "fullName", 1610620930, "GeneralNames"}, ++ { NULL, 4104, "0"}, ++ { "nameRelativeToCRLIssuer", 536879106, "RelativeDistinguishedName"}, ++ { NULL, 4104, "1"}, ++ { "ReasonFlags", 1073741830, NULL }, ++ { "ExtKeyUsageSyntax", 1612709899, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 12, NULL }, ++ { "AuthorityInfoAccessSyntax", 1612709899, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "AccessDescription"}, ++ { "AccessDescription", 1610612741, NULL }, ++ { "accessMethod", 1073741836, NULL }, ++ { "accessLocation", 2, "GeneralName"}, ++ { "Attribute", 1610612741, NULL }, ++ { "type", 1073741836, NULL }, ++ { "values", 536870927, NULL }, ++ { NULL, 13, NULL }, ++ { "AttributeTypeAndValue", 1610612741, NULL }, ++ { "type", 1073741836, NULL }, ++ { "value", 13, NULL }, ++ { "Name", 1610612754, NULL }, ++ { "rdnSequence", 536870923, NULL }, ++ { NULL, 2, "RelativeDistinguishedName"}, ++ { "DistinguishedName", 1610612747, NULL }, ++ { NULL, 2, "RelativeDistinguishedName"}, ++ { "RelativeDistinguishedName", 1612709903, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "AttributeTypeAndValue"}, ++ { "Certificate", 1610612741, NULL }, ++ { "tbsCertificate", 1073741826, "TBSCertificate"}, ++ { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "signature", 6, NULL }, ++ { "TBSCertificate", 1610612741, NULL }, ++ { "version", 1610653699, NULL }, ++ { NULL, 1073741833, "0"}, ++ { NULL, 2056, "0"}, ++ { "serialNumber", 1073741826, "CertificateSerialNumber"}, ++ { "signature", 1073741826, "AlgorithmIdentifier"}, ++ { "issuer", 1073741826, "Name"}, ++ { "validity", 1073741826, "Validity"}, ++ { "subject", 1073741826, "Name"}, ++ { "subjectPublicKeyInfo", 1073741826, "SubjectPublicKeyInfo"}, ++ { "issuerUniqueID", 1610637314, "UniqueIdentifier"}, ++ { NULL, 4104, "1"}, ++ { "subjectUniqueID", 1610637314, "UniqueIdentifier"}, ++ { NULL, 4104, "2"}, ++ { "extensions", 536895490, "Extensions"}, ++ { NULL, 2056, "3"}, ++ { "CertificateSerialNumber", 1073741827, NULL }, ++ { "Validity", 1610612741, NULL }, ++ { "notBefore", 1073741826, "Time"}, ++ { "notAfter", 2, "Time"}, ++ { "Time", 1610612754, NULL }, ++ { "utcTime", 1073741860, NULL }, ++ { "generalTime", 37, NULL }, ++ { "UniqueIdentifier", 1073741830, NULL }, ++ { "SubjectPublicKeyInfo", 1610612741, NULL }, ++ { "algorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "subjectPublicKey", 6, NULL }, ++ { "Extensions", 1612709899, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "Extension"}, ++ { "Extension", 1610612741, NULL }, ++ { "extnID", 1073741836, NULL }, ++ { "critical", 1610645508, NULL }, ++ { NULL, 131081, NULL }, ++ { "extnValue", 7, NULL }, ++ { "CertificateList", 1610612741, NULL }, ++ { "tbsCertList", 1073741826, "TBSCertList"}, ++ { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "signature", 6, NULL }, ++ { "TBSCertList", 1610612741, NULL }, ++ { "version", 1073758211, NULL }, ++ { "signature", 1073741826, "AlgorithmIdentifier"}, ++ { "issuer", 1073741826, "Name"}, ++ { "thisUpdate", 1073741826, "Time"}, ++ { "nextUpdate", 1073758210, "Time"}, ++ { "revokedCertificates", 1610629131, NULL }, ++ { NULL, 536870917, NULL }, ++ { "userCertificate", 1073741826, "CertificateSerialNumber"}, ++ { "revocationDate", 1073741826, "Time"}, ++ { "crlEntryExtensions", 16386, "Extensions"}, ++ { "crlExtensions", 536895490, "Extensions"}, ++ { NULL, 2056, "0"}, ++ { "AlgorithmIdentifier", 1610612741, NULL }, ++ { "algorithm", 1073741836, NULL }, ++ { "parameters", 541081613, NULL }, ++ { "algorithm", 1, NULL }, ++ { "Dss-Sig-Value", 1610612741, NULL }, ++ { "r", 1073741827, NULL }, ++ { "s", 3, NULL }, ++ { "Dss-Parms", 1610612741, NULL }, ++ { "p", 1073741827, NULL }, ++ { "q", 1073741827, NULL }, ++ { "g", 3, NULL }, ++ { "pkcs-7-ContentInfo", 1610612741, NULL }, ++ { "contentType", 1073741836, NULL }, ++ { "content", 541073421, NULL }, ++ { NULL, 1073743880, "0"}, ++ { "contentType", 1, NULL }, ++ { "pkcs-7-DigestInfo", 1610612741, NULL }, ++ { "digestAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "digest", 7, NULL }, ++ { "pkcs-7-SignedData", 1610612741, NULL }, ++ { "version", 1073741827, NULL }, ++ { "digestAlgorithms", 1073741826, "pkcs-7-DigestAlgorithmIdentifiers"}, ++ { "encapContentInfo", 1073741826, "pkcs-7-EncapsulatedContentInfo"}, ++ { "certificates", 1610637314, "pkcs-7-CertificateSet"}, ++ { NULL, 4104, "0"}, ++ { "crls", 1610637314, "pkcs-7-CertificateRevocationLists"}, ++ { NULL, 4104, "1"}, ++ { "signerInfos", 2, "pkcs-7-SignerInfos"}, ++ { "pkcs-7-DigestAlgorithmIdentifiers", 1610612751, NULL }, ++ { NULL, 2, "AlgorithmIdentifier"}, ++ { "pkcs-7-EncapsulatedContentInfo", 1610612741, NULL }, ++ { "eContentType", 1073741836, NULL }, ++ { "eContent", 536895501, NULL }, ++ { NULL, 2056, "0"}, ++ { "pkcs-7-CertificateRevocationLists", 1610612751, NULL }, ++ { NULL, 13, NULL }, ++ { "pkcs-7-CertificateChoices", 1610612754, NULL }, ++ { "certificate", 13, NULL }, ++ { "pkcs-7-CertificateSet", 1610612751, NULL }, ++ { NULL, 2, "pkcs-7-CertificateChoices"}, ++ { "IssuerAndSerialNumber", 1610612741, NULL }, ++ { "issuer", 1073741826, "Name"}, ++ { "serialNumber", 2, "CertificateSerialNumber"}, ++ { "pkcs-7-SignerInfo", 1610612741, NULL }, ++ { "version", 1073741827, NULL }, ++ { "sid", 1073741826, "SignerIdentifier"}, ++ { "digestAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "signedAttrs", 1610637314, "SignedAttributes"}, ++ { NULL, 4104, "0"}, ++ { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "signature", 1073741831, NULL }, ++ { "unsignedAttrs", 536895490, "SignedAttributes"}, ++ { NULL, 4104, "1"}, ++ { "SignedAttributes", 1612709903, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "Attribute"}, ++ { "SignerIdentifier", 1610612754, NULL }, ++ { "issuerAndSerialNumber", 1073741826, "IssuerAndSerialNumber"}, ++ { "subjectKeyIdentifier", 536879111, NULL }, ++ { NULL, 4104, "0"}, ++ { "pkcs-7-SignerInfos", 1610612751, NULL }, ++ { NULL, 2, "pkcs-7-SignerInfo"}, ++ { "pkcs-10-CertificationRequestInfo", 1610612741, NULL }, ++ { "version", 1073741827, NULL }, ++ { "subject", 1073741826, "Name"}, ++ { "subjectPKInfo", 1073741826, "SubjectPublicKeyInfo"}, ++ { "attributes", 536879106, "Attributes"}, ++ { NULL, 4104, "0"}, ++ { "Attributes", 1610612751, NULL }, ++ { NULL, 2, "Attribute"}, ++ { "pkcs-10-CertificationRequest", 1610612741, NULL }, ++ { "certificationRequestInfo", 1073741826, "pkcs-10-CertificationRequestInfo"}, ++ { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "signature", 6, NULL }, ++ { "pkcs-9-at-challengePassword", 1879048204, NULL }, ++ { "iso", 1073741825, "1"}, ++ { "member-body", 1073741825, "2"}, ++ { "us", 1073741825, "840"}, ++ { "rsadsi", 1073741825, "113549"}, ++ { "pkcs", 1073741825, "1"}, ++ { NULL, 1073741825, "9"}, ++ { NULL, 1, "7"}, ++ { "pkcs-9-challengePassword", 1610612754, NULL }, ++ { "printableString", 1073741855, NULL }, ++ { "utf8String", 34, NULL }, ++ { "pkcs-9-localKeyId", 1073741831, NULL }, ++ { "pkcs-8-PrivateKeyInfo", 1610612741, NULL }, ++ { "version", 1073741827, NULL }, ++ { "privateKeyAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "privateKey", 1073741831, NULL }, ++ { "attributes", 536895490, "Attributes"}, ++ { NULL, 4104, "0"}, ++ { "pkcs-8-EncryptedPrivateKeyInfo", 1610612741, NULL }, ++ { "encryptionAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "encryptedData", 2, "pkcs-8-EncryptedData"}, ++ { "pkcs-8-EncryptedData", 1073741831, NULL }, ++ { "pkcs-5-des-CBC-params", 1612709895, NULL }, ++ { NULL, 1048586, "8"}, ++ { "pkcs-5-des-EDE3-CBC-params", 1612709895, NULL }, ++ { NULL, 1048586, "8"}, ++ { "pkcs-5-aes128-CBC-params", 1612709895, NULL }, ++ { NULL, 1048586, "16"}, ++ { "pkcs-5-aes192-CBC-params", 1612709895, NULL }, ++ { NULL, 1048586, "16"}, ++ { "pkcs-5-aes256-CBC-params", 1612709895, NULL }, ++ { NULL, 1048586, "16"}, ++ { "Gost28147-89-Parameters", 1610612741, NULL }, ++ { "iv", 1073741831, NULL }, ++ { "encryptionParamSet", 12, NULL }, ++ { "pkcs-5-PBE-params", 1610612741, NULL }, ++ { "salt", 1073741831, NULL }, ++ { "iterationCount", 3, NULL }, ++ { "pkcs-5-PBES2-params", 1610612741, NULL }, ++ { "keyDerivationFunc", 1073741826, "AlgorithmIdentifier"}, ++ { "encryptionScheme", 2, "AlgorithmIdentifier"}, ++ { "pkcs-5-PBKDF2-params", 1610612741, NULL }, ++ { "salt", 1610612754, NULL }, ++ { "specified", 1073741831, NULL }, ++ { "otherSource", 2, "AlgorithmIdentifier"}, ++ { "iterationCount", 1611137027, NULL }, ++ { "1", 10, "MAX"}, ++ { "keyLength", 1611153411, NULL }, ++ { "1", 10, "MAX"}, ++ { "prf", 16386, "AlgorithmIdentifier"}, ++ { "pkcs-12-PFX", 1610612741, NULL }, ++ { "version", 1610874883, NULL }, ++ { "v3", 1, "3"}, ++ { "authSafe", 1073741826, "pkcs-7-ContentInfo"}, ++ { "macData", 16386, "pkcs-12-MacData"}, ++ { "pkcs-12-PbeParams", 1610612741, NULL }, ++ { "salt", 1073741831, NULL }, ++ { "iterations", 3, NULL }, ++ { "pkcs-12-MacData", 1610612741, NULL }, ++ { "mac", 1073741826, "pkcs-7-DigestInfo"}, ++ { "macSalt", 1073741831, NULL }, ++ { "iterations", 536903683, NULL }, ++ { NULL, 9, "1"}, ++ { "pkcs-12-AuthenticatedSafe", 1610612747, NULL }, ++ { NULL, 2, "pkcs-7-ContentInfo"}, ++ { "pkcs-12-SafeContents", 1610612747, NULL }, ++ { NULL, 2, "pkcs-12-SafeBag"}, ++ { "pkcs-12-SafeBag", 1610612741, NULL }, ++ { "bagId", 1073741836, NULL }, ++ { "bagValue", 1614815245, NULL }, ++ { NULL, 1073743880, "0"}, ++ { "badId", 1, NULL }, ++ { "bagAttributes", 536887311, NULL }, ++ { NULL, 2, "Attribute"}, ++ { "pkcs-12-CertBag", 1610612741, NULL }, ++ { "certId", 1073741836, NULL }, ++ { "certValue", 541073421, NULL }, ++ { NULL, 1073743880, "0"}, ++ { "certId", 1, NULL }, ++ { "pkcs-12-CRLBag", 1610612741, NULL }, ++ { "crlId", 1073741836, NULL }, ++ { "crlValue", 541073421, NULL }, ++ { NULL, 1073743880, "0"}, ++ { "crlId", 1, NULL }, ++ { "pkcs-12-SecretBag", 1610612741, NULL }, ++ { "secretTypeId", 1073741836, NULL }, ++ { "secretValue", 541073421, NULL }, ++ { NULL, 1073743880, "0"}, ++ { "secretTypeId", 1, NULL }, ++ { "pkcs-7-Data", 1073741831, NULL }, ++ { "pkcs-7-EncryptedData", 1610612741, NULL }, ++ { "version", 1073741827, NULL }, ++ { "encryptedContentInfo", 1073741826, "pkcs-7-EncryptedContentInfo"}, ++ { "unprotectedAttrs", 536895490, "pkcs-7-UnprotectedAttributes"}, ++ { NULL, 4104, "1"}, ++ { "pkcs-7-EncryptedContentInfo", 1610612741, NULL }, ++ { "contentType", 1073741836, NULL }, ++ { "contentEncryptionAlgorithm", 1073741826, "pkcs-7-ContentEncryptionAlgorithmIdentifier"}, ++ { "encryptedContent", 536895495, NULL }, ++ { NULL, 4104, "0"}, ++ { "pkcs-7-ContentEncryptionAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"}, ++ { "pkcs-7-UnprotectedAttributes", 1612709903, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "Attribute"}, ++ { "ProxyCertInfo", 1610612741, NULL }, ++ { "pCPathLenConstraint", 1611153411, NULL }, ++ { "0", 10, "MAX"}, ++ { "proxyPolicy", 2, "ProxyPolicy"}, ++ { "ProxyPolicy", 1610612741, NULL }, ++ { "policyLanguage", 1073741836, NULL }, ++ { "policy", 16391, NULL }, ++ { "certificatePolicies", 1612709899, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "PolicyInformation"}, ++ { "PolicyInformation", 1610612741, NULL }, ++ { "policyIdentifier", 1073741836, NULL }, ++ { "policyQualifiers", 538984459, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "PolicyQualifierInfo"}, ++ { "PolicyQualifierInfo", 1610612741, NULL }, ++ { "policyQualifierId", 1073741836, NULL }, ++ { "qualifier", 541065229, NULL }, ++ { "policyQualifierId", 1, NULL }, ++ { "CPSuri", 1073741853, NULL }, ++ { "UserNotice", 1610612741, NULL }, ++ { "noticeRef", 1073758210, "NoticeReference"}, ++ { "explicitText", 16386, "DisplayText"}, ++ { "NoticeReference", 1610612741, NULL }, ++ { "organization", 1073741826, "DisplayText"}, ++ { "noticeNumbers", 536870923, NULL }, ++ { NULL, 3, NULL }, ++ { "DisplayText", 1610612754, NULL }, ++ { "ia5String", 1612709917, NULL }, ++ { "200", 524298, "1"}, ++ { "visibleString", 1612709923, NULL }, ++ { "200", 524298, "1"}, ++ { "bmpString", 1612709921, NULL }, ++ { "200", 524298, "1"}, ++ { "utf8String", 538968098, NULL }, ++ { "200", 524298, "1"}, ++ { "OCSPRequest", 1610612741, NULL }, ++ { "tbsRequest", 1073741826, "TBSRequest"}, ++ { "optionalSignature", 536895490, "Signature"}, ++ { NULL, 2056, "0"}, ++ { "TBSRequest", 1610612741, NULL }, ++ { "version", 1610653699, NULL }, ++ { NULL, 1073741833, "0"}, ++ { NULL, 2056, "0"}, ++ { "requestorName", 1610637314, "GeneralName"}, ++ { NULL, 2056, "1"}, ++ { "requestList", 1610612747, NULL }, ++ { NULL, 2, "Request"}, ++ { "requestExtensions", 536895490, "Extensions"}, ++ { NULL, 2056, "2"}, ++ { "Signature", 1610612741, NULL }, ++ { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "signature", 1073741830, NULL }, ++ { "certs", 536895499, NULL }, ++ { NULL, 1073743880, "0"}, ++ { NULL, 2, "Certificate"}, ++ { "Request", 1610612741, NULL }, ++ { "reqCert", 1073741826, "CertID"}, ++ { "singleRequestExtensions", 536895490, "Extensions"}, ++ { NULL, 2056, "0"}, ++ { "CertID", 1610612741, NULL }, ++ { "hashAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "issuerNameHash", 1073741831, NULL }, ++ { "issuerKeyHash", 1073741831, NULL }, ++ { "serialNumber", 2, "CertificateSerialNumber"}, ++ { "OCSPResponse", 1610612741, NULL }, ++ { "responseStatus", 1073741826, "OCSPResponseStatus"}, ++ { "responseBytes", 536895490, "ResponseBytes"}, ++ { NULL, 2056, "0"}, ++ { "OCSPResponseStatus", 1610874901, NULL }, ++ { "successful", 1073741825, "0"}, ++ { "malformedRequest", 1073741825, "1"}, ++ { "internalError", 1073741825, "2"}, ++ { "tryLater", 1073741825, "3"}, ++ { "sigRequired", 1073741825, "5"}, ++ { "unauthorized", 1, "6"}, ++ { "ResponseBytes", 1610612741, NULL }, ++ { "responseType", 1073741836, NULL }, ++ { "response", 7, NULL }, ++ { "BasicOCSPResponse", 1610612741, NULL }, ++ { "tbsResponseData", 1073741826, "ResponseData"}, ++ { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "signature", 1073741830, NULL }, ++ { "certs", 536895499, NULL }, ++ { NULL, 1073743880, "0"}, ++ { NULL, 2, "Certificate"}, ++ { "ResponseData", 1610612741, NULL }, ++ { "version", 1610653699, NULL }, ++ { NULL, 1073741833, "0"}, ++ { NULL, 2056, "0"}, ++ { "responderID", 1073741826, "ResponderID"}, ++ { "producedAt", 1073741861, NULL }, ++ { "responses", 1610612747, NULL }, ++ { NULL, 2, "SingleResponse"}, ++ { "responseExtensions", 536895490, "Extensions"}, ++ { NULL, 2056, "1"}, ++ { "ResponderID", 1610612754, NULL }, ++ { "byName", 1610620939, NULL }, ++ { NULL, 1073743880, "1"}, ++ { NULL, 2, "RelativeDistinguishedName"}, ++ { "byKey", 536879111, NULL }, ++ { NULL, 2056, "2"}, ++ { "SingleResponse", 1610612741, NULL }, ++ { "certID", 1073741826, "CertID"}, ++ { "certStatus", 1073741826, "CertStatus"}, ++ { "thisUpdate", 1073741861, NULL }, ++ { "nextUpdate", 1610637349, NULL }, ++ { NULL, 2056, "0"}, ++ { "singleExtensions", 536895490, "Extensions"}, ++ { NULL, 2056, "1"}, ++ { "CertStatus", 1610612754, NULL }, ++ { "good", 1610620948, NULL }, ++ { NULL, 4104, "0"}, ++ { "revoked", 1610620930, "RevokedInfo"}, ++ { NULL, 4104, "1"}, ++ { "unknown", 536879106, "UnknownInfo"}, ++ { NULL, 4104, "2"}, ++ { "RevokedInfo", 1610612741, NULL }, ++ { "revocationTime", 1073741861, NULL }, ++ { "revocationReason", 537157653, NULL }, ++ { NULL, 1073743880, "0"}, ++ { "unspecified", 1, "0"}, ++ { "UnknownInfo", 1073741844, NULL }, ++ { "NameConstraints", 1610612741, NULL }, ++ { "permittedSubtrees", 1610637314, "GeneralSubtrees"}, ++ { NULL, 4104, "0"}, ++ { "excludedSubtrees", 536895490, "GeneralSubtrees"}, ++ { NULL, 4104, "1"}, ++ { "GeneralSubtrees", 1612709899, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "GeneralSubtree"}, ++ { "GeneralSubtree", 1610612741, NULL }, ++ { "base", 1073741826, "GeneralName"}, ++ { "minimum", 1610653699, NULL }, ++ { NULL, 1073741833, "0"}, ++ { NULL, 4104, "0"}, ++ { "maximum", 536895491, NULL }, ++ { NULL, 4104, "1"}, ++ { "TlsFeatures", 536870923, NULL }, ++ { NULL, 3, NULL }, ++ { NULL, 0, NULL } ++}; +-- +2.31.1 + diff --git a/0017-net-ip-Do-IP-fragment-maths-safely.patch b/0017-net-ip-Do-IP-fragment-maths-safely.patch new file mode 100644 index 0000000..9c508a9 --- /dev/null +++ b/0017-net-ip-Do-IP-fragment-maths-safely.patch @@ -0,0 +1,54 @@ +From 5c79af15504c599b58a2f3e591850876dfdb5fa2 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 20 Dec 2021 19:41:21 +1100 +Subject: [PATCH 17/32] net/ip: Do IP fragment maths safely + +We can receive packets with invalid IP fragmentation information. This +can lead to rsm->total_len underflowing and becoming very large. + +Then, in grub_netbuff_alloc(), we add to this very large number, which can +cause it to overflow and wrap back around to a small positive number. +The allocation then succeeds, but the resulting buffer is too small and +subsequent operations can write past the end of the buffer. + +Catch the underflow here. + +Fixes: CVE-2022-28733 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/net/ip.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c +index 01410798b3..937be87678 100644 +--- a/grub-core/net/ip.c ++++ b/grub-core/net/ip.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include + + struct iphdr { +@@ -551,7 +552,14 @@ grub_net_recv_ip4_packets (struct grub_net_buff *nb, + { + rsm->total_len = (8 * (grub_be_to_cpu16 (iph->frags) & OFFSET_MASK) + + (nb->tail - nb->data)); +- rsm->total_len -= ((iph->verhdrlen & 0xf) * sizeof (grub_uint32_t)); ++ ++ if (grub_sub (rsm->total_len, (iph->verhdrlen & 0xf) * sizeof (grub_uint32_t), ++ &rsm->total_len)) ++ { ++ grub_dprintf ("net", "IP reassembly size underflow\n"); ++ return GRUB_ERR_NONE; ++ } ++ + rsm->asm_netbuff = grub_netbuff_alloc (rsm->total_len); + if (!rsm->asm_netbuff) + { +-- +2.34.1 + diff --git a/0018-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch b/0018-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch new file mode 100644 index 0000000..cf364e1 --- /dev/null +++ b/0018-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch @@ -0,0 +1,1891 @@ +From 7a583c9b29ffa6ac32e93b6b20054c0290521e82 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 30 Jul 2020 01:33:46 +1000 +Subject: [PATCH 18/23] appended signatures: parse PKCS#7 signedData and X.509 + certificates + +This code allows us to parse: + + - PKCS#7 signedData messages. Only a single signerInfo is supported, + which is all that the Linux sign-file utility supports creating + out-of-the-box. Only RSA, SHA-256 and SHA-512 are supported. + Any certificate embedded in the PKCS#7 message will be ignored. + + - X.509 certificates: at least enough to verify the signatures on the + PKCS#7 messages. We expect that the certificates embedded in grub will + be leaf certificates, not CA certificates. The parser enforces this. + + - X.509 certificates support the Extended Key Usage extension and handle + it by verifying that the certificate has a single purpose, that is code + signing. This is required because Red Hat certificates have both Key + Usage and Extended Key Usage extensions present. + +Signed-off-by: Javier Martinez Canillas # EKU support +Signed-off-by: Daniel Axtens + +--- + +v3 changes: + - fixes for libtasn1-4.18.0 + +v2 changes: + + - Handle the Extended Key Usage extension + - Fix 2 leaks in x509 cert parsing + - Improve x509 parser function name + - Constify the data parameter in parser signatures + - Support multiple signers in a pkcs7 message. Accept any passing sig. + - Allow padding after a pkcs7 message in an appended signature, required + to support my model for signers separated in time. + - Fix a test that used GRUB_ERR_NONE rather than ASN1_SUCCESS. They're + both 0 so no harm was done, but better to be correct. + - Various code and comment cleanups. + +Thanks to Nayna Jain and Stefan Berger for their reviews. +--- + grub-core/commands/appendedsig/appendedsig.h | 118 ++ + grub-core/commands/appendedsig/asn1util.c | 103 ++ + grub-core/commands/appendedsig/pkcs7.c | 509 +++++++++ + grub-core/commands/appendedsig/x509.c | 1079 ++++++++++++++++++ + 4 files changed, 1809 insertions(+) + create mode 100644 grub-core/commands/appendedsig/appendedsig.h + create mode 100644 grub-core/commands/appendedsig/asn1util.c + create mode 100644 grub-core/commands/appendedsig/pkcs7.c + create mode 100644 grub-core/commands/appendedsig/x509.c + +diff --git a/grub-core/commands/appendedsig/appendedsig.h b/grub-core/commands/appendedsig/appendedsig.h +new file mode 100644 +index 000000000..327d68ddb +--- /dev/null ++++ b/grub-core/commands/appendedsig/appendedsig.h +@@ -0,0 +1,118 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 IBM Corporation. ++ * ++ * 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 . ++ */ ++ ++#include ++#include ++ ++extern asn1_node _gnutls_gnutls_asn; ++extern asn1_node _gnutls_pkix_asn; ++ ++#define MAX_OID_LEN 32 ++ ++/* ++ * One or more x509 certificates. ++ * ++ * We do limited parsing: extracting only the serial, CN and RSA public key. ++ */ ++struct x509_certificate ++{ ++ struct x509_certificate *next; ++ ++ grub_uint8_t *serial; ++ grub_size_t serial_len; ++ ++ char *subject; ++ grub_size_t subject_len; ++ ++ /* We only support RSA public keys. This encodes [modulus, publicExponent] */ ++ gcry_mpi_t mpis[2]; ++}; ++ ++/* ++ * A PKCS#7 signedData signerInfo. ++ */ ++struct pkcs7_signerInfo ++{ ++ const gcry_md_spec_t *hash; ++ gcry_mpi_t sig_mpi; ++}; ++ ++/* ++ * A PKCS#7 signedData message. ++ * ++ * We make no attempt to match intelligently, so we don't save any info about ++ * the signer. ++ */ ++struct pkcs7_signedData ++{ ++ int signerInfo_count; ++ struct pkcs7_signerInfo *signerInfos; ++}; ++ ++ ++/* Do libtasn1 init */ ++int asn1_init (void); ++ ++/* ++ * Import a DER-encoded certificate at 'data', of size 'size'. ++ * ++ * Place the results into 'results', which must be already allocated. ++ */ ++grub_err_t ++parse_x509_certificate (const void *data, grub_size_t size, ++ struct x509_certificate *results); ++ ++/* ++ * Release all the storage associated with the x509 certificate. ++ * If the caller dynamically allocated the certificate, it must free it. ++ * The caller is also responsible for maintenance of the linked list. ++ */ ++void certificate_release (struct x509_certificate *cert); ++ ++/* ++ * Parse a PKCS#7 message, which must be a signedData message. ++ * ++ * The message must be in 'sigbuf' and of size 'data_size'. The result is ++ * placed in 'msg', which must already be allocated. ++ */ ++grub_err_t ++parse_pkcs7_signedData (const void *sigbuf, grub_size_t data_size, ++ struct pkcs7_signedData *msg); ++ ++/* ++ * Release all the storage associated with the PKCS#7 message. ++ * If the caller dynamically allocated the message, it must free it. ++ */ ++void pkcs7_signedData_release (struct pkcs7_signedData *msg); ++ ++/* ++ * Read a value from an ASN1 node, allocating memory to store it. ++ * ++ * It will work for anything where the size libtasn1 returns is right: ++ * - Integers ++ * - Octet strings ++ * - DER encoding of other structures ++ * It will _not_ work for things where libtasn1 size requires adjustment: ++ * - Strings that require an extra NULL byte at the end ++ * - Bit strings because libtasn1 returns the length in bits, not bytes. ++ * ++ * If the function returns a non-NULL value, the caller must free it. ++ */ ++void *grub_asn1_allocate_and_read (asn1_node node, const char *name, ++ const char *friendly_name, ++ int *content_size); +diff --git a/grub-core/commands/appendedsig/asn1util.c b/grub-core/commands/appendedsig/asn1util.c +new file mode 100644 +index 000000000..e116f8c75 +--- /dev/null ++++ b/grub-core/commands/appendedsig/asn1util.c +@@ -0,0 +1,103 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 IBM Corporation. ++ * ++ * 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 . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "appendedsig.h" ++ ++asn1_node _gnutls_gnutls_asn = NULL; ++asn1_node _gnutls_pkix_asn = NULL; ++ ++extern const asn1_static_node gnutls_asn1_tab[]; ++extern const asn1_static_node pkix_asn1_tab[]; ++ ++/* ++ * Read a value from an ASN1 node, allocating memory to store it. ++ * ++ * It will work for anything where the size libtasn1 returns is right: ++ * - Integers ++ * - Octet strings ++ * - DER encoding of other structures ++ * It will _not_ work for things where libtasn1 size requires adjustment: ++ * - Strings that require an extra NULL byte at the end ++ * - Bit strings because libtasn1 returns the length in bits, not bytes. ++ * ++ * If the function returns a non-NULL value, the caller must free it. ++ */ ++void * ++grub_asn1_allocate_and_read (asn1_node node, const char *name, ++ const char *friendly_name, int *content_size) ++{ ++ int result; ++ grub_uint8_t *tmpstr = NULL; ++ int tmpstr_size = 0; ++ ++ result = asn1_read_value (node, name, NULL, &tmpstr_size); ++ if (result != ASN1_MEM_ERROR) ++ { ++ grub_snprintf (grub_errmsg, sizeof (grub_errmsg), ++ _ ++ ("Reading size of %s did not return expected status: %s"), ++ friendly_name, asn1_strerror (result)); ++ grub_errno = GRUB_ERR_BAD_FILE_TYPE; ++ return NULL; ++ } ++ ++ tmpstr = grub_malloc (tmpstr_size); ++ if (tmpstr == NULL) ++ { ++ grub_snprintf (grub_errmsg, sizeof (grub_errmsg), ++ "Could not allocate memory to store %s", friendly_name); ++ grub_errno = GRUB_ERR_OUT_OF_MEMORY; ++ return NULL; ++ } ++ ++ result = asn1_read_value (node, name, tmpstr, &tmpstr_size); ++ if (result != ASN1_SUCCESS) ++ { ++ grub_free (tmpstr); ++ grub_snprintf (grub_errmsg, sizeof (grub_errmsg), ++ "Error reading %s: %s", ++ friendly_name, asn1_strerror (result)); ++ grub_errno = GRUB_ERR_BAD_FILE_TYPE; ++ return NULL; ++ } ++ ++ *content_size = tmpstr_size; ++ ++ return tmpstr; ++} ++ ++int ++asn1_init (void) ++{ ++ int res; ++ res = asn1_array2tree (gnutls_asn1_tab, &_gnutls_gnutls_asn, NULL); ++ if (res != ASN1_SUCCESS) ++ { ++ return res; ++ } ++ res = asn1_array2tree (pkix_asn1_tab, &_gnutls_pkix_asn, NULL); ++ return res; ++} +diff --git a/grub-core/commands/appendedsig/pkcs7.c b/grub-core/commands/appendedsig/pkcs7.c +new file mode 100644 +index 000000000..845f58a53 +--- /dev/null ++++ b/grub-core/commands/appendedsig/pkcs7.c +@@ -0,0 +1,509 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 IBM Corporation. ++ * ++ * 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 . ++ */ ++ ++#include "appendedsig.h" ++#include ++#include ++#include ++#include ++ ++static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; ++ ++/* ++ * RFC 5652 s 5.1 ++ */ ++const char *signedData_oid = "1.2.840.113549.1.7.2"; ++ ++/* ++ * RFC 4055 s 2.1 ++ */ ++const char *sha256_oid = "2.16.840.1.101.3.4.2.1"; ++const char *sha512_oid = "2.16.840.1.101.3.4.2.3"; ++ ++static grub_err_t ++process_content (grub_uint8_t * content, int size, ++ struct pkcs7_signedData *msg) ++{ ++ int res; ++ asn1_node signed_part; ++ grub_err_t err = GRUB_ERR_NONE; ++ char algo_oid[MAX_OID_LEN]; ++ int algo_oid_size = sizeof (algo_oid); ++ int algo_count; ++ int signer_count; ++ int i; ++ char version; ++ int version_size = sizeof (version); ++ grub_uint8_t *result_buf; ++ int result_size = 0; ++ int crls_size = 0; ++ gcry_error_t gcry_err; ++ bool sha256_in_da, sha256_in_si, sha512_in_da, sha512_in_si; ++ char *da_path; ++ char *si_sig_path; ++ char *si_da_path; ++ ++ res = asn1_create_element (_gnutls_pkix_asn, "PKIX1.pkcs-7-SignedData", ++ &signed_part); ++ if (res != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for PKCS#7 signed part."); ++ } ++ ++ res = asn1_der_decoding2 (&signed_part, content, &size, ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ if (res != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error reading PKCS#7 signed data: %s", asn1_error); ++ goto cleanup_signed_part; ++ } ++ ++ /* SignedData ::= SEQUENCE { ++ * version CMSVersion, ++ * digestAlgorithms DigestAlgorithmIdentifiers, ++ * encapContentInfo EncapsulatedContentInfo, ++ * certificates [0] IMPLICIT CertificateSet OPTIONAL, ++ * crls [1] IMPLICIT RevocationInfoChoices OPTIONAL, ++ * signerInfos SignerInfos } ++ */ ++ ++ /* version per the algo in 5.1, must be 1 */ ++ res = asn1_read_value (signed_part, "version", &version, &version_size); ++ if (res != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error reading signedData version: %s", ++ asn1_strerror (res)); ++ goto cleanup_signed_part; ++ } ++ ++ if (version != 1) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Unexpected signature version v%d, only v1 supported", ++ version); ++ goto cleanup_signed_part; ++ } ++ ++ /* ++ * digestAlgorithms DigestAlgorithmIdentifiers ++ * ++ * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier ++ * DigestAlgorithmIdentifer is an X.509 AlgorithmIdentifier (10.1.1) ++ * ++ * RFC 4055 s 2.1: ++ * sha256Identifier AlgorithmIdentifier ::= { id-sha256, NULL } ++ * sha512Identifier AlgorithmIdentifier ::= { id-sha512, NULL } ++ * ++ * We only support 1 element in the set, and we do not check parameters atm. ++ */ ++ res = ++ asn1_number_of_elements (signed_part, "digestAlgorithms", &algo_count); ++ if (res != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error counting number of digest algorithms: %s", ++ asn1_strerror (res)); ++ goto cleanup_signed_part; ++ } ++ ++ if (algo_count <= 0) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "A minimum of 1 digest algorithm is required"); ++ goto cleanup_signed_part; ++ } ++ ++ if (algo_count > 2) ++ { ++ err = ++ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ "A maximum of 2 digest algorithms are supported"); ++ goto cleanup_signed_part; ++ } ++ ++ sha256_in_da = false; ++ sha512_in_da = false; ++ ++ for (i = 0; i < algo_count; i++) ++ { ++ da_path = grub_xasprintf ("digestAlgorithms.?%d.algorithm", i + 1); ++ if (!da_path) ++ { ++ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not allocate path for digest algorithm parsing path"); ++ goto cleanup_signed_part; ++ } ++ ++ algo_oid_size = sizeof (algo_oid); ++ res = asn1_read_value (signed_part, da_path, algo_oid, &algo_oid_size); ++ if (res != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error reading digest algorithm: %s", ++ asn1_strerror (res)); ++ grub_free (da_path); ++ goto cleanup_signed_part; ++ } ++ ++ if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0) ++ { ++ if (!sha512_in_da) ++ { ++ sha512_in_da = true; ++ } ++ else ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "SHA-512 specified twice in digest algorithm list"); ++ grub_free (da_path); ++ goto cleanup_signed_part; ++ } ++ } ++ else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 0) ++ { ++ if (!sha256_in_da) ++ { ++ sha256_in_da = true; ++ } ++ else ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "SHA-256 specified twice in digest algorithm list"); ++ grub_free (da_path); ++ goto cleanup_signed_part; ++ } ++ } ++ else ++ { ++ err = ++ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ "Only SHA-256 and SHA-512 hashes are supported, found OID %s", ++ algo_oid); ++ grub_free (da_path); ++ goto cleanup_signed_part; ++ } ++ ++ grub_free (da_path); ++ } ++ ++ /* at this point, at least one of sha{256,512}_in_da must be true */ ++ ++ /* ++ * We ignore the certificates, but we don't permit CRLs. ++ * A CRL entry might be revoking the certificate we're using, and we have ++ * no way of dealing with that at the moment. ++ */ ++ res = asn1_read_value (signed_part, "crls", NULL, &crls_size); ++ if (res != ASN1_ELEMENT_NOT_FOUND) ++ { ++ err = ++ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ "PKCS#7 messages with embedded CRLs are not supported"); ++ goto cleanup_signed_part; ++ } ++ ++ /* read the signatures */ ++ ++ res = asn1_number_of_elements (signed_part, "signerInfos", &signer_count); ++ if (res != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error counting number of signers: %s", ++ asn1_strerror (res)); ++ goto cleanup_signed_part; ++ } ++ ++ if (signer_count <= 0) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "A minimum of 1 signer is required"); ++ goto cleanup_signed_part; ++ } ++ ++ msg->signerInfos = grub_calloc (signer_count, ++ sizeof (struct pkcs7_signerInfo)); ++ if (!msg->signerInfos) ++ { ++ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not allocate space for %d signers", ++ signer_count); ++ goto cleanup_signed_part; ++ } ++ ++ msg->signerInfo_count = 0; ++ for (i = 0; i < signer_count; i++) ++ { ++ si_da_path = ++ grub_xasprintf ("signerInfos.?%d.digestAlgorithm.algorithm", i + 1); ++ if (!si_da_path) ++ { ++ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not allocate path for signer %d's digest algorithm parsing path", ++ i); ++ goto cleanup_signerInfos; ++ } ++ ++ algo_oid_size = sizeof (algo_oid); ++ res = ++ asn1_read_value (signed_part, si_da_path, algo_oid, &algo_oid_size); ++ if (res != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error reading signer %d's digest algorithm: %s", ++ i, asn1_strerror (res)); ++ grub_free (si_da_path); ++ goto cleanup_signerInfos; ++ } ++ ++ grub_free (si_da_path); ++ ++ if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0) ++ { ++ if (!sha512_in_da) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Signer %d claims a SHA-512 signature which was not specified in the outer DigestAlgorithms", ++ i); ++ goto cleanup_signerInfos; ++ } ++ else ++ { ++ sha512_in_si = true; ++ msg->signerInfos[i].hash = ++ grub_crypto_lookup_md_by_name ("sha512"); ++ } ++ } ++ else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 0) ++ { ++ if (!sha256_in_da) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Signer %d claims a SHA-256 signature which was not specified in the outer DigestAlgorithms", ++ i); ++ goto cleanup_signerInfos; ++ } ++ else ++ { ++ sha256_in_si = true; ++ msg->signerInfos[i].hash = ++ grub_crypto_lookup_md_by_name ("sha256"); ++ } ++ } ++ else ++ { ++ err = ++ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ "Only SHA-256 and SHA-512 hashes are supported, found OID %s", ++ algo_oid); ++ goto cleanup_signerInfos; ++ } ++ ++ if (!msg->signerInfos[i].hash) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Hash algorithm for signer %d (OID %s) not loaded", i, ++ algo_oid); ++ goto cleanup_signerInfos; ++ } ++ ++ si_sig_path = grub_xasprintf ("signerInfos.?%d.signature", i + 1); ++ if (!si_sig_path) ++ { ++ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not allocate path for signer %d's signature parsing path", ++ i); ++ goto cleanup_signerInfos; ++ } ++ ++ result_buf = ++ grub_asn1_allocate_and_read (signed_part, si_sig_path, ++ "signature data", &result_size); ++ if (!result_buf) ++ { ++ err = grub_errno; ++ grub_free (si_sig_path); ++ goto cleanup_signerInfos; ++ } ++ grub_free (si_sig_path); ++ ++ gcry_err = ++ gcry_mpi_scan (&(msg->signerInfos[i].sig_mpi), GCRYMPI_FMT_USG, ++ result_buf, result_size, NULL); ++ if (gcry_err != GPG_ERR_NO_ERROR) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error loading signature %d into MPI structure: %d", ++ i, gcry_err); ++ grub_free (result_buf); ++ goto cleanup_signerInfos; ++ } ++ ++ grub_free (result_buf); ++ ++ /* use msg->signerInfo_count to track fully populated signerInfos so we ++ know how many we need to clean up */ ++ msg->signerInfo_count++; ++ } ++ ++ /* Final consistency check of signerInfo.*.digestAlgorithm vs ++ digestAlgorithms.*.algorithm. An algorithm must be present in both ++ digestAlgorithms and signerInfo or in neither. We have already checked ++ for an algorithm in signerInfo that is not in digestAlgorithms, here we ++ check for algorithms in digestAlgorithms but not in signerInfos. */ ++ if (sha512_in_da && !sha512_in_si) ++ { ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "SHA-512 specified in DigestAlgorithms but did not appear in SignerInfos"); ++ goto cleanup_signerInfos; ++ } ++ ++ if (sha256_in_da && !sha256_in_si) ++ { ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "SHA-256 specified in DigestAlgorithms but did not appear in SignerInfos"); ++ goto cleanup_signerInfos; ++ } ++ ++ asn1_delete_structure (&signed_part); ++ return GRUB_ERR_NONE; ++ ++cleanup_signerInfos: ++ for (i = 0; i < msg->signerInfo_count; i++) ++ gcry_mpi_release (msg->signerInfos[i].sig_mpi); ++ grub_free (msg->signerInfos); ++cleanup_signed_part: ++ asn1_delete_structure (&signed_part); ++ return err; ++} ++ ++grub_err_t ++parse_pkcs7_signedData (const void *sigbuf, grub_size_t data_size, ++ struct pkcs7_signedData *msg) ++{ ++ int res; ++ asn1_node content_info; ++ grub_err_t err = GRUB_ERR_NONE; ++ char content_oid[MAX_OID_LEN]; ++ grub_uint8_t *content; ++ int content_size; ++ int content_oid_size = sizeof (content_oid); ++ int size; ++ ++ if (data_size > GRUB_INT_MAX) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ "Cannot parse a PKCS#7 message where data size > INT_MAX"); ++ size = (int) data_size; ++ ++ res = asn1_create_element (_gnutls_pkix_asn, ++ "PKIX1.pkcs-7-ContentInfo", &content_info); ++ if (res != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for PKCS#7 data: %s", ++ asn1_strerror (res)); ++ } ++ ++ res = asn1_der_decoding2 (&content_info, sigbuf, &size, ++ ASN1_DECODE_FLAG_STRICT_DER | ++ ASN1_DECODE_FLAG_ALLOW_PADDING, asn1_error); ++ if (res != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error decoding PKCS#7 message DER: %s", asn1_error); ++ goto cleanup; ++ } ++ ++ /* ++ * ContentInfo ::= SEQUENCE { ++ * contentType ContentType, ++ * content [0] EXPLICIT ANY DEFINED BY contentType } ++ * ++ * ContentType ::= OBJECT IDENTIFIER ++ */ ++ res = ++ asn1_read_value (content_info, "contentType", content_oid, ++ &content_oid_size); ++ if (res != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error reading PKCS#7 content type: %s", ++ asn1_strerror (res)); ++ goto cleanup; ++ } ++ ++ /* OID for SignedData defined in 5.1 */ ++ if (grub_strncmp (signedData_oid, content_oid, content_oid_size) != 0) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Unexpected content type in PKCS#7 message: OID %s", ++ content_oid); ++ goto cleanup; ++ } ++ ++ content = ++ grub_asn1_allocate_and_read (content_info, "content", ++ "PKCS#7 message content", &content_size); ++ if (!content) ++ { ++ err = grub_errno; ++ goto cleanup; ++ } ++ ++ err = process_content (content, content_size, msg); ++ grub_free (content); ++ ++cleanup: ++ asn1_delete_structure (&content_info); ++ return err; ++} ++ ++/* ++ * Release all the storage associated with the PKCS#7 message. ++ * If the caller dynamically allocated the message, it must free it. ++ */ ++void ++pkcs7_signedData_release (struct pkcs7_signedData *msg) ++{ ++ grub_ssize_t i; ++ for (i = 0; i < msg->signerInfo_count; i++) ++ { ++ gcry_mpi_release (msg->signerInfos[i].sig_mpi); ++ } ++ grub_free (msg->signerInfos); ++} +diff --git a/grub-core/commands/appendedsig/x509.c b/grub-core/commands/appendedsig/x509.c +new file mode 100644 +index 000000000..70480aa73 +--- /dev/null ++++ b/grub-core/commands/appendedsig/x509.c +@@ -0,0 +1,1079 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 IBM Corporation. ++ * ++ * 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 . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "appendedsig.h" ++ ++static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; ++ ++/* ++ * RFC 3279 2.3.1 RSA Keys ++ */ ++const char *rsaEncryption_oid = "1.2.840.113549.1.1.1"; ++ ++/* ++ * RFC 5280 Appendix A ++ */ ++const char *commonName_oid = "2.5.4.3"; ++ ++/* ++ * RFC 5280 4.2.1.3 Key Usage ++ */ ++const char *keyUsage_oid = "2.5.29.15"; ++ ++const grub_uint8_t digitalSignatureUsage = 0x80; ++ ++/* ++ * RFC 5280 4.2.1.9 Basic Constraints ++ */ ++const char *basicConstraints_oid = "2.5.29.19"; ++ ++/* ++ * RFC 5280 4.2.1.12 Extended Key Usage ++ */ ++const char *extendedKeyUsage_oid = "2.5.29.37"; ++const char *codeSigningUsage_oid = "1.3.6.1.5.5.7.3.3"; ++ ++/* ++ * RFC 3279 2.3.1 ++ * ++ * The RSA public key MUST be encoded using the ASN.1 type RSAPublicKey: ++ * ++ * RSAPublicKey ::= SEQUENCE { ++ * modulus INTEGER, -- n ++ * publicExponent INTEGER } -- e ++ * ++ * where modulus is the modulus n, and publicExponent is the public ++ * exponent e. ++ */ ++static grub_err_t ++grub_parse_rsa_pubkey (grub_uint8_t *der, int dersize, ++ struct x509_certificate *certificate) ++{ ++ int result; ++ asn1_node spk = NULL; ++ grub_uint8_t *m_data, *e_data; ++ int m_size, e_size; ++ grub_err_t err = GRUB_ERR_NONE; ++ gcry_error_t gcry_err; ++ ++ result = ++ asn1_create_element (_gnutls_gnutls_asn, "GNUTLS.RSAPublicKey", &spk); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Cannot create storage for public key ASN.1 data"); ++ } ++ ++ result = asn1_der_decoding2 (&spk, der, &dersize, ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Cannot decode certificate public key DER: %s", ++ asn1_error); ++ goto cleanup; ++ } ++ ++ m_data = ++ grub_asn1_allocate_and_read (spk, "modulus", "RSA modulus", &m_size); ++ if (!m_data) ++ { ++ err = grub_errno; ++ goto cleanup; ++ } ++ ++ e_data = ++ grub_asn1_allocate_and_read (spk, "publicExponent", "RSA public exponent", ++ &e_size); ++ if (!e_data) ++ { ++ err = grub_errno; ++ goto cleanup_m_data; ++ } ++ ++ /* ++ * convert m, e to mpi ++ * ++ * nscanned is not set for FMT_USG, it's only set for FMT_PGP, ++ * so we can't verify it ++ */ ++ gcry_err = ++ gcry_mpi_scan (&certificate->mpis[0], GCRYMPI_FMT_USG, m_data, m_size, ++ NULL); ++ if (gcry_err != GPG_ERR_NO_ERROR) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error loading RSA modulus into MPI structure: %d", ++ gcry_err); ++ goto cleanup_e_data; ++ } ++ ++ gcry_err = ++ gcry_mpi_scan (&certificate->mpis[1], GCRYMPI_FMT_USG, e_data, e_size, ++ NULL); ++ if (gcry_err != GPG_ERR_NO_ERROR) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error loading RSA exponent into MPI structure: %d", ++ gcry_err); ++ goto cleanup_m_mpi; ++ } ++ ++ grub_free (e_data); ++ grub_free (m_data); ++ asn1_delete_structure (&spk); ++ return GRUB_ERR_NONE; ++ ++cleanup_m_mpi: ++ gcry_mpi_release (certificate->mpis[0]); ++cleanup_e_data: ++ grub_free (e_data); ++cleanup_m_data: ++ grub_free (m_data); ++cleanup: ++ asn1_delete_structure (&spk); ++ return err; ++} ++ ++ ++/* ++ * RFC 5280: ++ * SubjectPublicKeyInfo ::= SEQUENCE { ++ * algorithm AlgorithmIdentifier, ++ * subjectPublicKey BIT STRING } ++ * ++ * AlgorithmIdentifiers come from RFC 3279, we are not strictly compilant as we ++ * only support RSA Encryption. ++ */ ++ ++static grub_err_t ++grub_x509_read_subject_public_key (asn1_node asn, ++ struct x509_certificate *results) ++{ ++ int result; ++ grub_err_t err; ++ const char *algo_name = ++ "tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm"; ++ const char *params_name = ++ "tbsCertificate.subjectPublicKeyInfo.algorithm.parameters"; ++ const char *pk_name = ++ "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey"; ++ char algo_oid[MAX_OID_LEN]; ++ int algo_size = sizeof (algo_oid); ++ char params_value[2]; ++ int params_size = sizeof (params_value); ++ grub_uint8_t *key_data = NULL; ++ int key_size = 0; ++ unsigned int key_type; ++ ++ /* algorithm: see notes for rsaEncryption_oid */ ++ result = asn1_read_value (asn, algo_name, algo_oid, &algo_size); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading x509 public key algorithm: %s", ++ asn1_strerror (result)); ++ } ++ ++ if (grub_strncmp (algo_oid, rsaEncryption_oid, sizeof (rsaEncryption_oid)) ++ != 0) ++ { ++ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ "Unsupported x509 public key algorithm: %s", ++ algo_oid); ++ } ++ ++ /* ++ * RFC 3279 2.3.1 ++ * The rsaEncryption OID is intended to be used in the algorithm field ++ * of a value of type AlgorithmIdentifier. The parameters field MUST ++ * have ASN.1 type NULL for this algorithm identifier. ++ */ ++ result = asn1_read_value (asn, params_name, params_value, ¶ms_size); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading x509 public key parameters: %s", ++ asn1_strerror (result)); ++ } ++ ++ if (params_value[0] != ASN1_TAG_NULL) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Invalid x509 public key parameters: expected NULL"); ++ } ++ ++ /* ++ * RFC 3279 2.3.1: The DER encoded RSAPublicKey is the value of the BIT ++ * STRING subjectPublicKey. ++ */ ++ result = asn1_read_value_type (asn, pk_name, NULL, &key_size, &key_type); ++ if (result != ASN1_MEM_ERROR) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading size of x509 public key: %s", ++ asn1_strerror (result)); ++ } ++ if (key_type != ASN1_ETYPE_BIT_STRING) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Unexpected ASN.1 type when reading x509 public key: %x", ++ key_type); ++ } ++ ++ /* length is in bits */ ++ key_size = (key_size + 7) / 8; ++ ++ key_data = grub_malloc (key_size); ++ if (!key_data) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Out of memory for x509 public key"); ++ } ++ ++ result = asn1_read_value (asn, pk_name, key_data, &key_size); ++ if (result != ASN1_SUCCESS) ++ { ++ grub_free (key_data); ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading public key data"); ++ } ++ key_size = (key_size + 7) / 8; ++ ++ err = grub_parse_rsa_pubkey (key_data, key_size, results); ++ grub_free (key_data); ++ ++ return err; ++} ++ ++/* Decode a string as defined in Appendix A */ ++static grub_err_t ++decode_string (char *der, int der_size, char **string, ++ grub_size_t *string_size) ++{ ++ asn1_node strasn; ++ int result; ++ char *choice; ++ int choice_size = 0; ++ int tmp_size = 0; ++ grub_err_t err = GRUB_ERR_NONE; ++ ++ result = ++ asn1_create_element (_gnutls_pkix_asn, "PKIX1.DirectoryString", &strasn); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for certificate: %s", ++ asn1_strerror (result)); ++ } ++ ++ result = asn1_der_decoding2 (&strasn, der, &der_size, ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Could not parse DER for DirectoryString: %s", ++ asn1_error); ++ goto cleanup; ++ } ++ ++ choice = ++ grub_asn1_allocate_and_read (strasn, "", "DirectoryString choice", ++ &choice_size); ++ if (!choice) ++ { ++ err = grub_errno; ++ goto cleanup; ++ } ++ ++ if (grub_strncmp ("utf8String", choice, choice_size) == 0) ++ { ++ result = asn1_read_value (strasn, "utf8String", NULL, &tmp_size); ++ if (result != ASN1_MEM_ERROR) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading size of UTF-8 string: %s", ++ asn1_strerror (result)); ++ goto cleanup_choice; ++ } ++ } ++ else if (grub_strncmp ("printableString", choice, choice_size) == 0) ++ { ++ result = asn1_read_value (strasn, "printableString", NULL, &tmp_size); ++ if (result != ASN1_MEM_ERROR) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading size of UTF-8 string: %s", ++ asn1_strerror (result)); ++ goto cleanup_choice; ++ } ++ } ++ else ++ { ++ err = ++ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ "Only UTF-8 and printable DirectoryStrings are supported, got %s", ++ choice); ++ goto cleanup_choice; ++ } ++ ++ /* read size does not include trailing null */ ++ tmp_size++; ++ ++ *string = grub_malloc (tmp_size); ++ if (!*string) ++ { ++ err = ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Cannot allocate memory for DirectoryString contents"); ++ goto cleanup_choice; ++ } ++ ++ result = asn1_read_value (strasn, choice, *string, &tmp_size); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading out %s in DirectoryString: %s", ++ choice, asn1_strerror (result)); ++ grub_free (*string); ++ goto cleanup_choice; ++ } ++ *string_size = tmp_size + 1; ++ (*string)[tmp_size] = '\0'; ++ ++cleanup_choice: ++ grub_free (choice); ++cleanup: ++ asn1_delete_structure (&strasn); ++ return err; ++} ++ ++/* ++ * TBSCertificate ::= SEQUENCE { ++ * version [0] EXPLICIT Version DEFAULT v1, ++ * ... ++ * ++ * Version ::= INTEGER { v1(0), v2(1), v3(2) } ++ */ ++static grub_err_t ++check_version (asn1_node certificate) ++{ ++ int rc; ++ const char *name = "tbsCertificate.version"; ++ grub_uint8_t version; ++ int len = sizeof (version); ++ ++ rc = asn1_read_value (certificate, name, &version, &len); ++ ++ /* require version 3 */ ++ if (rc != ASN1_SUCCESS || len != 1) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading certificate version"); ++ ++ if (version != 0x02) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Invalid x509 certificate version, expected v3 (0x02), got 0x%02x", ++ version); ++ ++ return GRUB_ERR_NONE; ++} ++ ++/* ++ * This is an X.501 Name, which is complex. ++ * ++ * For simplicity, we extract only the CN. ++ */ ++static grub_err_t ++read_name (asn1_node asn, const char *name_path, char **name, ++ grub_size_t *name_size) ++{ ++ int seq_components, set_components; ++ int result; ++ int i, j; ++ char *top_path, *set_path, *type_path, *val_path; ++ char type[MAX_OID_LEN]; ++ int type_len = sizeof (type); ++ int string_size = 0; ++ char *string_der; ++ grub_err_t err; ++ ++ *name = NULL; ++ ++ top_path = grub_xasprintf ("%s.rdnSequence", name_path); ++ if (!top_path) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not allocate memory for %s name parsing path", ++ name_path); ++ ++ result = asn1_number_of_elements (asn, top_path, &seq_components); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error counting name components: %s", ++ asn1_strerror (result)); ++ goto cleanup; ++ } ++ ++ for (i = 1; i <= seq_components; i++) ++ { ++ set_path = grub_xasprintf ("%s.?%d", top_path, i); ++ if (!set_path) ++ { ++ err = ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not allocate memory for %s name set parsing path", ++ name_path); ++ goto cleanup_set; ++ } ++ /* this brings us, hopefully, to a set */ ++ result = asn1_number_of_elements (asn, set_path, &set_components); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error counting name sub-components components (element %d): %s", ++ i, asn1_strerror (result)); ++ goto cleanup_set; ++ } ++ for (j = 1; j <= set_components; j++) ++ { ++ type_path = grub_xasprintf ("%s.?%d.?%d.type", top_path, i, j); ++ if (!type_path) ++ { ++ err = ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not allocate memory for %s name component type path", ++ name_path); ++ goto cleanup_set; ++ } ++ type_len = sizeof (type); ++ result = asn1_read_value (asn, type_path, type, &type_len); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading %s name component type: %s", ++ name_path, asn1_strerror (result)); ++ goto cleanup_type; ++ } ++ ++ if (grub_strncmp (type, commonName_oid, type_len) != 0) ++ { ++ grub_free (type_path); ++ continue; ++ } ++ ++ val_path = grub_xasprintf ("%s.?%d.?%d.value", top_path, i, j); ++ if (!val_path) ++ { ++ err = ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not allocate memory for %s name component value path", ++ name_path); ++ goto cleanup_set; ++ } ++ ++ string_der = ++ grub_asn1_allocate_and_read (asn, val_path, name_path, ++ &string_size); ++ if (!string_der) ++ { ++ err = grub_errno; ++ goto cleanup_val_path; ++ } ++ ++ err = decode_string (string_der, string_size, name, name_size); ++ if (err) ++ goto cleanup_string; ++ ++ grub_free (string_der); ++ grub_free (type_path); ++ grub_free (val_path); ++ break; ++ } ++ grub_free (set_path); ++ ++ if (*name) ++ break; ++ } ++ ++ grub_free (top_path); ++ ++ return GRUB_ERR_NONE; ++ ++cleanup_string: ++ grub_free (string_der); ++cleanup_val_path: ++ grub_free (val_path); ++cleanup_type: ++ grub_free (type_path); ++cleanup_set: ++ grub_free (set_path); ++cleanup: ++ grub_free (top_path); ++ return err; ++} ++ ++/* ++ * Verify the Key Usage extension. ++ * We only permit the Digital signature usage. ++ */ ++static grub_err_t ++verify_key_usage (grub_uint8_t *value, int value_size) ++{ ++ asn1_node usageasn; ++ int result; ++ grub_err_t err = GRUB_ERR_NONE; ++ grub_uint8_t usage = 0xff; ++ int usage_size = sizeof (usage_size); ++ ++ result = ++ asn1_create_element (_gnutls_pkix_asn, "PKIX1.KeyUsage", &usageasn); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for key usage"); ++ } ++ ++ result = asn1_der_decoding2 (&usageasn, value, &value_size, ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error parsing DER for Key Usage: %s", asn1_error); ++ goto cleanup; ++ } ++ ++ result = asn1_read_value (usageasn, "", &usage, &usage_size); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading Key Usage value: %s", ++ asn1_strerror (result)); ++ goto cleanup; ++ } ++ ++ if (usage != digitalSignatureUsage) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected Key Usage value: %x", ++ usage); ++ goto cleanup; ++ } ++ ++cleanup: ++ asn1_delete_structure (&usageasn); ++ return err; ++} ++ ++/* ++ * BasicConstraints ::= SEQUENCE { ++ * cA BOOLEAN DEFAULT FALSE, ++ * pathLenConstraint INTEGER (0..MAX) OPTIONAL } ++ */ ++static grub_err_t ++verify_basic_constraints (grub_uint8_t *value, int value_size) ++{ ++ asn1_node basicasn; ++ int result; ++ grub_err_t err = GRUB_ERR_NONE; ++ char cA[6]; /* FALSE or TRUE */ ++ int cA_size = sizeof (cA); ++ ++ result = ++ asn1_create_element (_gnutls_pkix_asn, "PKIX1.BasicConstraints", ++ &basicasn); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for Basic Constraints"); ++ } ++ ++ result = asn1_der_decoding2 (&basicasn, value, &value_size, ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error parsing DER for Basic Constraints: %s", ++ asn1_error); ++ goto cleanup; ++ } ++ ++ result = asn1_read_value (basicasn, "cA", cA, &cA_size); ++ if (result == ASN1_ELEMENT_NOT_FOUND) ++ { ++ /* Not present, default is False, so this is OK */ ++ err = GRUB_ERR_NONE; ++ goto cleanup; ++ } ++ else if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading Basic Constraints cA value: %s", ++ asn1_strerror (result)); ++ goto cleanup; ++ } ++ ++ /* The certificate must not be a CA certificate */ ++ if (grub_strncmp ("FALSE", cA, cA_size) != 0) ++ { ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected CA value: %s", ++ cA); ++ goto cleanup; ++ } ++ ++cleanup: ++ asn1_delete_structure (&basicasn); ++ return err; ++} ++ ++/* ++ * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId ++ * ++ * KeyPurposeId ::= OBJECT IDENTIFIER ++ */ ++static grub_err_t ++verify_extended_key_usage (grub_uint8_t *value, int value_size) ++{ ++ asn1_node extendedasn; ++ int result, count; ++ grub_err_t err = GRUB_ERR_NONE; ++ char usage[MAX_OID_LEN]; ++ int usage_size = sizeof (usage); ++ ++ result = ++ asn1_create_element (_gnutls_pkix_asn, "PKIX1.ExtKeyUsageSyntax", ++ &extendedasn); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for Extended Key Usage"); ++ } ++ ++ result = asn1_der_decoding2 (&extendedasn, value, &value_size, ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error parsing DER for Extended Key Usage: %s", ++ asn1_error); ++ goto cleanup; ++ } ++ ++ /* ++ * If EKUs are present, there must be exactly 1 and it must be a ++ * codeSigning usage. ++ */ ++ result = asn1_number_of_elements (extendedasn, "", &count); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error counting number of Extended Key Usages: %s", ++ asn1_strerror (result)); ++ goto cleanup; ++ } ++ ++ if (count != 1) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Unexpected number of Extended Key Usages: %d, 1 expected", ++ count); ++ goto cleanup; ++ } ++ ++ result = asn1_read_value (extendedasn, "?1", usage, &usage_size); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading Extended Key Usage: %s", ++ asn1_strerror (result)); ++ goto cleanup; ++ } ++ ++ if (grub_strncmp (codeSigningUsage_oid, usage, usage_size) != 0) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Unexpected Extended Key Usage OID, got: %s", usage); ++ goto cleanup; ++ } ++ ++cleanup: ++ asn1_delete_structure (&extendedasn); ++ return err; ++} ++ ++/* ++ * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension ++ * ++ * Extension ::= SEQUENCE { ++ * extnID OBJECT IDENTIFIER, ++ * critical BOOLEAN DEFAULT FALSE, ++ * extnValue OCTET STRING ++ * -- contains the DER encoding of an ASN.1 value ++ * -- corresponding to the extension type identified ++ * -- by extnID ++ * } ++ * ++ * A certificate must: ++ * - contain the Digital Signature usage only ++ * - not be a CA ++ * - contain no extended usages, or only a code signing extended usage ++ * - not contain any other critical extensions (RFC 5280 s 4.2) ++ */ ++static grub_err_t ++verify_extensions (asn1_node cert) ++{ ++ int result; ++ int ext, num_extensions = 0; ++ int usage_present = 0, constraints_present = 0, extended_usage_present = 0; ++ char *oid_path, *critical_path, *value_path; ++ char extnID[MAX_OID_LEN]; ++ int extnID_size; ++ grub_err_t err; ++ char critical[6]; /* we get either "TRUE" or "FALSE" */ ++ int critical_size; ++ grub_uint8_t *value; ++ int value_size; ++ ++ result = ++ asn1_number_of_elements (cert, "tbsCertificate.extensions", ++ &num_extensions); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error counting number of extensions: %s", ++ asn1_strerror (result)); ++ } ++ ++ if (num_extensions < 2) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Insufficient number of extensions for certificate, need at least 2, got %d", ++ num_extensions); ++ } ++ ++ for (ext = 1; ext <= num_extensions; ext++) ++ { ++ oid_path = grub_xasprintf ("tbsCertificate.extensions.?%d.extnID", ext); ++ ++ extnID_size = sizeof (extnID); ++ result = asn1_read_value (cert, oid_path, extnID, &extnID_size); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading extension OID: %s", ++ asn1_strerror (result)); ++ goto cleanup_oid_path; ++ } ++ ++ critical_path = ++ grub_xasprintf ("tbsCertificate.extensions.?%d.critical", ext); ++ critical_size = sizeof (critical); ++ result = ++ asn1_read_value (cert, critical_path, critical, &critical_size); ++ if (result == ASN1_ELEMENT_NOT_FOUND) ++ { ++ critical[0] = '\0'; ++ } ++ else if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading extension criticality: %s", ++ asn1_strerror (result)); ++ goto cleanup_critical_path; ++ } ++ ++ value_path = ++ grub_xasprintf ("tbsCertificate.extensions.?%d.extnValue", ext); ++ value = ++ grub_asn1_allocate_and_read (cert, value_path, ++ "certificate extension value", ++ &value_size); ++ if (!value) ++ { ++ err = grub_errno; ++ goto cleanup_value_path; ++ } ++ ++ /* ++ * Now we must see if we recognise the OID. ++ * If we have an unrecognised critical extension we MUST bail. ++ */ ++ if (grub_strncmp (keyUsage_oid, extnID, extnID_size) == 0) ++ { ++ err = verify_key_usage (value, value_size); ++ if (err != GRUB_ERR_NONE) ++ { ++ goto cleanup_value; ++ } ++ usage_present++; ++ } ++ else if (grub_strncmp (basicConstraints_oid, extnID, extnID_size) == 0) ++ { ++ err = verify_basic_constraints (value, value_size); ++ if (err != GRUB_ERR_NONE) ++ { ++ goto cleanup_value; ++ } ++ constraints_present++; ++ } ++ else if (grub_strncmp (extendedKeyUsage_oid, extnID, extnID_size) == 0) ++ { ++ err = verify_extended_key_usage (value, value_size); ++ if (err != GRUB_ERR_NONE) ++ { ++ goto cleanup_value; ++ } ++ extended_usage_present++; ++ } ++ else if (grub_strncmp ("TRUE", critical, critical_size) == 0) ++ { ++ /* ++ * per the RFC, we must not process a certificate with ++ * a critical extension we do not understand. ++ */ ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Unhandled critical x509 extension with OID %s", ++ extnID); ++ goto cleanup_value; ++ } ++ ++ grub_free (value); ++ grub_free (value_path); ++ grub_free (critical_path); ++ grub_free (oid_path); ++ } ++ ++ if (usage_present != 1) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Unexpected number of Key Usage extensions - expected 1, got %d", ++ usage_present); ++ } ++ if (constraints_present != 1) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Unexpected number of basic constraints extensions - expected 1, got %d", ++ constraints_present); ++ } ++ if (extended_usage_present > 1) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Unexpected number of Extended Key Usage extensions - expected 0 or 1, got %d", ++ extended_usage_present); ++ } ++ return GRUB_ERR_NONE; ++ ++cleanup_value: ++ grub_free (value); ++cleanup_value_path: ++ grub_free (value_path); ++cleanup_critical_path: ++ grub_free (critical_path); ++cleanup_oid_path: ++ grub_free (oid_path); ++ return err; ++} ++ ++/* ++ * Parse a certificate whose DER-encoded form is in @data, of size @data_size. ++ * Return the results in @results, which must point to an allocated x509 certificate. ++ */ ++grub_err_t ++parse_x509_certificate (const void *data, grub_size_t data_size, ++ struct x509_certificate *results) ++{ ++ int result = 0; ++ asn1_node cert; ++ grub_err_t err; ++ int size; ++ int tmp_size; ++ ++ if (data_size > GRUB_INT_MAX) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ "Cannot parse a certificate where data size > INT_MAX"); ++ size = (int) data_size; ++ ++ result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.Certificate", &cert); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for certificate: %s", ++ asn1_strerror (result)); ++ } ++ ++ result = asn1_der_decoding2 (&cert, data, &size, ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Could not parse DER for certificate: %s", asn1_error); ++ goto cleanup; ++ } ++ ++ /* ++ * TBSCertificate ::= SEQUENCE { ++ * version [0] EXPLICIT Version DEFAULT v1 ++ */ ++ err = check_version (cert); ++ if (err != GRUB_ERR_NONE) ++ { ++ goto cleanup; ++ } ++ ++ /* ++ * serialNumber CertificateSerialNumber, ++ * ++ * CertificateSerialNumber ::= INTEGER ++ */ ++ results->serial = ++ grub_asn1_allocate_and_read (cert, "tbsCertificate.serialNumber", ++ "certificate serial number", &tmp_size); ++ if (!results->serial) ++ { ++ err = grub_errno; ++ goto cleanup; ++ } ++ /* ++ * It's safe to cast the signed int to an unsigned here, we know ++ * length is non-negative ++ */ ++ results->serial_len = tmp_size; ++ ++ /* ++ * signature AlgorithmIdentifier, ++ * ++ * We don't load the signature or issuer at the moment, ++ * as we don't attempt x509 verification. ++ */ ++ ++ /* ++ * issuer Name, ++ * ++ * The RFC only requires the serial number to be unique within ++ * issuers, so to avoid ambiguity we _technically_ ought to make ++ * this available. ++ */ ++ ++ /* ++ * validity Validity, ++ * ++ * Validity ::= SEQUENCE { ++ * notBefore Time, ++ * notAfter Time } ++ * ++ * We can't validate this reasonably, we have no true time source on several ++ * platforms. For now we do not parse them. ++ */ ++ ++ /* ++ * subject Name, ++ * ++ * This is an X501 name, we parse out just the CN. ++ */ ++ err = ++ read_name (cert, "tbsCertificate.subject", &results->subject, ++ &results->subject_len); ++ if (err != GRUB_ERR_NONE) ++ goto cleanup_serial; ++ ++ /* ++ * TBSCertificate ::= SEQUENCE { ++ * ... ++ * subjectPublicKeyInfo SubjectPublicKeyInfo, ++ * ... ++ */ ++ err = grub_x509_read_subject_public_key (cert, results); ++ if (err != GRUB_ERR_NONE) ++ goto cleanup_name; ++ ++ /* ++ * TBSCertificate ::= SEQUENCE { ++ * ... ++ * extensions [3] EXPLICIT Extensions OPTIONAL ++ * -- If present, version MUST be v3 ++ * } ++ */ ++ ++ err = verify_extensions (cert); ++ if (err != GRUB_ERR_NONE) ++ goto cleanup_mpis; ++ ++ /* ++ * We do not read or check the signature on the certificate: ++ * as discussed we do not try to validate the certificate but trust ++ * it implictly. ++ */ ++ ++ asn1_delete_structure (&cert); ++ return GRUB_ERR_NONE; ++ ++cleanup_mpis: ++ gcry_mpi_release (results->mpis[0]); ++ gcry_mpi_release (results->mpis[1]); ++cleanup_name: ++ grub_free (results->subject); ++cleanup_serial: ++ grub_free (results->serial); ++cleanup: ++ asn1_delete_structure (&cert); ++ return err; ++} ++ ++/* ++ * Release all the storage associated with the x509 certificate. ++ * If the caller dynamically allocated the certificate, it must free it. ++ * The caller is also responsible for maintenance of the linked list. ++ */ ++void ++certificate_release (struct x509_certificate *cert) ++{ ++ grub_free (cert->subject); ++ grub_free (cert->serial); ++ gcry_mpi_release (cert->mpis[0]); ++ gcry_mpi_release (cert->mpis[1]); ++} +-- +2.31.1 + diff --git a/0018-net-netbuff-Block-overly-large-netbuff-allocs.patch b/0018-net-netbuff-Block-overly-large-netbuff-allocs.patch new file mode 100644 index 0000000..aa1f5a0 --- /dev/null +++ b/0018-net-netbuff-Block-overly-large-netbuff-allocs.patch @@ -0,0 +1,55 @@ +From bf949ed28a526b7ab137b8804e2ef6239c3061f2 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 8 Mar 2022 23:47:46 +1100 +Subject: [PATCH 18/32] net/netbuff: Block overly large netbuff allocs + +A netbuff shouldn't be too huge. It's bounded by MTU and TCP segment +reassembly. If we are asked to create one that is unreasonably big, refuse. + +This is a hardening measure: if we hit this code, there's a bug somewhere +else that we should catch and fix. + +This commit: + - stops the bug propagating any further. + - provides a spot to instrument in e.g. fuzzing to try to catch these bugs. + +I have put instrumentation (e.g. __builtin_trap() to force a crash) here and +have not been able to find any more crashes. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/net/netbuff.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/grub-core/net/netbuff.c b/grub-core/net/netbuff.c +index dbeeefe478..d5e9e9a0d7 100644 +--- a/grub-core/net/netbuff.c ++++ b/grub-core/net/netbuff.c +@@ -79,10 +79,23 @@ grub_netbuff_alloc (grub_size_t len) + + COMPILE_TIME_ASSERT (NETBUFF_ALIGN % sizeof (grub_properly_aligned_t) == 0); + ++ /* ++ * The largest size of a TCP packet is 64 KiB, and everything else ++ * should be a lot smaller - most MTUs are 1500 or less. Cap data ++ * size at 64 KiB + a buffer. ++ */ ++ if (len > 0xffffUL + 0x1000UL) ++ { ++ grub_error (GRUB_ERR_BUG, ++ "attempted to allocate a packet that is too big"); ++ return NULL; ++ } ++ + if (len < NETBUFFMINLEN) + len = NETBUFFMINLEN; + + len = ALIGN_UP (len, NETBUFF_ALIGN); ++ + #ifdef GRUB_MACHINE_EMU + data = grub_malloc (len + sizeof (*nb)); + #else +-- +2.34.1 + diff --git a/0019-appended-signatures-support-verifying-appended-signa.patch b/0019-appended-signatures-support-verifying-appended-signa.patch new file mode 100644 index 0000000..5d3304a --- /dev/null +++ b/0019-appended-signatures-support-verifying-appended-signa.patch @@ -0,0 +1,764 @@ +From 97104dbd207a07fa3759b23766fa60f7bb8d16b4 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 30 Jul 2020 01:35:43 +1000 +Subject: [PATCH 19/23] appended signatures: support verifying appended + signatures + +Building on the parsers and the ability to embed x509 certificates, as +well as the existing gcrypt functionality, add a module for verifying +appended signatures. + +This includes a verifier that requires that Linux kernels and grub modules +have appended signatures, and commands to manage the list of trusted +certificates for verification. + +Verification must be enabled by setting check_appended_signatures. If +GRUB is locked down when the module is loaded, verification will be +enabled and locked automatically. + +As with the PGP verifier, it is not a complete secure-boot solution: +other mechanisms, such as a password or lockdown, must be used to ensure +that a user cannot drop to the grub shell and disable verification. + +Signed-off-by: Daniel Axtens + +--- + +v2 changes: + + - Improve x509 parser function name + - Constify data parameters in function signatures + - Support multiple signers + - Use an enum rather than 0, 1 and 2 for various signature + enforcement states. + - Spin out a file reading function that was duplicated. + - Fix some code style and clarity issues. + +Thanks to Nayna Jain and Stefan Berger for their reviews. + +Revert "fixups so that you can build pkcs7 without posixly" + +This reverts commit 676a19fa8a7f9cca7a58ce2180110f609185b2bd. +--- + grub-core/Makefile.core.def | 14 + + grub-core/commands/appendedsig/appendedsig.c | 669 +++++++++++++++++++ + include/grub/file.h | 2 + + 3 files changed, 685 insertions(+) + create mode 100644 grub-core/commands/appendedsig/appendedsig.c + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 6a3ff4265..b55294e25 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -952,6 +952,20 @@ module = { + enable = i386_pc; + }; + ++module = { ++ name = appendedsig; ++ common = commands/appendedsig/appendedsig.c; ++ common = commands/appendedsig/x509.c; ++ common = commands/appendedsig/pkcs7.c; ++ common = commands/appendedsig/asn1util.c; ++ common = commands/appendedsig/gnutls_asn1_tab.c; ++ common = commands/appendedsig/pkix_asn1_tab.c; ++ ++ // posix wrapper required for gcry to get sys/types.h ++ cflags = '$(CFLAGS_POSIX)'; ++ cppflags = '-I$(srcdir)/lib/posix_wrap'; ++}; ++ + module = { + name = hdparm; + common = commands/hdparm.c; +diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c +new file mode 100644 +index 000000000..e63ad1ac6 +--- /dev/null ++++ b/grub-core/commands/appendedsig/appendedsig.c +@@ -0,0 +1,669 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020-2021 IBM Corporation. ++ * ++ * 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 . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "appendedsig.h" ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++const char magic[] = "~Module signature appended~\n"; ++ ++/* ++ * This structure is extracted from scripts/sign-file.c in the linux kernel ++ * source. It was licensed as LGPLv2.1+, which is GPLv3+ compatible. ++ */ ++struct module_signature ++{ ++ grub_uint8_t algo; /* Public-key crypto algorithm [0] */ ++ grub_uint8_t hash; /* Digest algorithm [0] */ ++ grub_uint8_t id_type; /* Key identifier type [PKEY_ID_PKCS7] */ ++ grub_uint8_t signer_len; /* Length of signer's name [0] */ ++ grub_uint8_t key_id_len; /* Length of key identifier [0] */ ++ grub_uint8_t __pad[3]; ++ grub_uint32_t sig_len; /* Length of signature data */ ++} GRUB_PACKED; ++ ++ ++/* This represents an entire, parsed, appended signature */ ++struct grub_appended_signature ++{ ++ grub_size_t signature_len; /* Length of PKCS#7 data + ++ * metadata + magic */ ++ ++ struct module_signature sig_metadata; /* Module signature metadata */ ++ struct pkcs7_signedData pkcs7; /* Parsed PKCS#7 data */ ++}; ++ ++/* Trusted certificates for verifying appended signatures */ ++struct x509_certificate *grub_trusted_key; ++ ++/* ++ * Force gcry_rsa to be a module dependency. ++ * ++ * If we use grub_crypto_pk_rsa, then then the gcry_rsa module won't be built ++ * in if you add 'appendedsig' to grub-install --modules. You would need to ++ * add 'gcry_rsa' too. That's confusing and seems suboptimal, especially when ++ * we only support RSA. ++ * ++ * Dynamic loading also causes some concerns. We can't load gcry_rsa from the ++ * the filesystem after we install the verifier - we won't be able to verify ++ * it without having it already present. We also shouldn't load it before we ++ * install the verifier, because that would mean it wouldn't be verified - an ++ * attacker could insert any code they wanted into the module. ++ * ++ * So instead, reference the internal symbol from gcry_rsa. That creates a ++ * direct dependency on gcry_rsa, so it will be built in when this module ++ * is built in. Being built in (assuming the core image is itself signed!) ++ * also resolves our concerns about loading from the filesystem. ++ */ ++extern gcry_pk_spec_t _gcry_pubkey_spec_rsa; ++ ++static enum ++{ check_sigs_no = 0, ++ check_sigs_enforce = 1, ++ check_sigs_forced = 2 ++} check_sigs = check_sigs_no; ++ ++static const char * ++grub_env_read_sec (struct grub_env_var *var __attribute__((unused)), ++ const char *val __attribute__((unused))) ++{ ++ if (check_sigs == check_sigs_forced) ++ return "forced"; ++ else if (check_sigs == check_sigs_enforce) ++ return "enforce"; ++ else ++ return "no"; ++} ++ ++static char * ++grub_env_write_sec (struct grub_env_var *var __attribute__((unused)), ++ const char *val) ++{ ++ /* Do not allow the value to be changed if set to forced */ ++ if (check_sigs == check_sigs_forced) ++ return grub_strdup ("forced"); ++ ++ if ((*val == '2') || (*val == 'f')) ++ check_sigs = check_sigs_forced; ++ else if ((*val == '1') || (*val == 'e')) ++ check_sigs = check_sigs_enforce; ++ else if ((*val == '0') || (*val == 'n')) ++ check_sigs = check_sigs_no; ++ ++ return grub_strdup (grub_env_read_sec (NULL, NULL)); ++} ++ ++static grub_err_t ++file_read_all (grub_file_t file, grub_uint8_t **buf, grub_size_t *len) ++{ ++ grub_off_t full_file_size; ++ grub_size_t file_size, total_read_size = 0; ++ grub_ssize_t read_size; ++ ++ full_file_size = grub_file_size (file); ++ if (full_file_size == GRUB_FILE_SIZE_UNKNOWN) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("Cannot read a file of unknown size into a buffer")); ++ ++ if (full_file_size > GRUB_SIZE_MAX) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("File is too large to read: %" PRIuGRUB_UINT64_T ++ " bytes"), full_file_size); ++ ++ file_size = (grub_size_t) full_file_size; ++ ++ *buf = grub_malloc (file_size); ++ if (!*buf) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ N_("Could not allocate file data buffer size %" ++ PRIuGRUB_SIZE), file_size); ++ ++ while (total_read_size < file_size) ++ { ++ read_size = ++ grub_file_read (file, *buf + total_read_size, ++ file_size - total_read_size); ++ ++ if (read_size < 0) ++ { ++ grub_free (*buf); ++ return grub_errno; ++ } ++ else if (read_size == 0) ++ { ++ grub_free (*buf); ++ return grub_error (GRUB_ERR_IO, ++ N_("Could not read full file size (%" ++ PRIuGRUB_SIZE "), only %" PRIuGRUB_SIZE ++ " bytes read"), file_size, total_read_size); ++ } ++ ++ total_read_size += read_size; ++ } ++ *len = file_size; ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++read_cert_from_file (grub_file_t f, struct x509_certificate *certificate) ++{ ++ grub_err_t err; ++ grub_uint8_t *buf; ++ grub_size_t file_size; ++ ++ err = file_read_all (f, &buf, &file_size); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ ++ err = parse_x509_certificate (buf, file_size, certificate); ++ if (err != GRUB_ERR_NONE) ++ { ++ grub_free (buf); ++ return err; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++extract_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize, ++ struct grub_appended_signature *sig) ++{ ++ grub_err_t err; ++ grub_size_t pkcs7_size; ++ grub_size_t remaining_len; ++ const grub_uint8_t *appsigdata = buf + bufsize - grub_strlen (magic); ++ ++ if (bufsize < grub_strlen (magic)) ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("File too short for signature magic")); ++ ++ if (grub_memcmp (appsigdata, (grub_uint8_t *) magic, grub_strlen (magic))) ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("Missing or invalid signature magic")); ++ ++ remaining_len = bufsize - grub_strlen (magic); ++ ++ if (remaining_len < sizeof (struct module_signature)) ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("File too short for signature metadata")); ++ ++ appsigdata -= sizeof (struct module_signature); ++ ++ /* extract the metadata */ ++ grub_memcpy (&(sig->sig_metadata), appsigdata, ++ sizeof (struct module_signature)); ++ ++ remaining_len -= sizeof (struct module_signature); ++ ++ if (sig->sig_metadata.id_type != 2) ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("Wrong signature type")); ++ ++ pkcs7_size = grub_be_to_cpu32 (sig->sig_metadata.sig_len); ++ ++ if (pkcs7_size > remaining_len) ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("File too short for PKCS#7 message")); ++ ++ grub_dprintf ("appendedsig", "sig len %" PRIuGRUB_SIZE "\n", pkcs7_size); ++ ++ sig->signature_len = ++ grub_strlen (magic) + sizeof (struct module_signature) + pkcs7_size; ++ ++ /* rewind pointer and parse pkcs7 data */ ++ appsigdata -= pkcs7_size; ++ ++ err = parse_pkcs7_signedData (appsigdata, pkcs7_size, &sig->pkcs7); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize) ++{ ++ grub_err_t err = GRUB_ERR_NONE; ++ grub_size_t datasize; ++ void *context; ++ unsigned char *hash; ++ gcry_mpi_t hashmpi; ++ gcry_err_code_t rc; ++ struct x509_certificate *pk; ++ struct grub_appended_signature sig; ++ struct pkcs7_signerInfo *si; ++ int i; ++ ++ if (!grub_trusted_key) ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("No trusted keys to verify against")); ++ ++ err = extract_appended_signature (buf, bufsize, &sig); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ ++ datasize = bufsize - sig.signature_len; ++ ++ for (i = 0; i < sig.pkcs7.signerInfo_count; i++) ++ { ++ /* This could be optimised in a couple of ways: ++ - we could only compute hashes once per hash type ++ - we could track signer information and only verify where IDs match ++ For now we do the naive O(trusted keys * pkcs7 signers) approach. ++ */ ++ si = &sig.pkcs7.signerInfos[i]; ++ context = grub_zalloc (si->hash->contextsize); ++ if (!context) ++ return grub_errno; ++ ++ si->hash->init (context); ++ si->hash->write (context, buf, datasize); ++ si->hash->final (context); ++ hash = si->hash->read (context); ++ ++ grub_dprintf ("appendedsig", ++ "data size %" PRIxGRUB_SIZE ", signer %d hash %02x%02x%02x%02x...\n", ++ datasize, i, hash[0], hash[1], hash[2], hash[3]); ++ ++ err = GRUB_ERR_BAD_SIGNATURE; ++ for (pk = grub_trusted_key; pk; pk = pk->next) ++ { ++ rc = grub_crypto_rsa_pad (&hashmpi, hash, si->hash, pk->mpis[0]); ++ if (rc) ++ { ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("Error padding hash for RSA verification: %d"), ++ rc); ++ grub_free (context); ++ goto cleanup; ++ } ++ ++ rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi, &si->sig_mpi, ++ pk->mpis, NULL, NULL); ++ gcry_mpi_release (hashmpi); ++ ++ if (rc == 0) ++ { ++ grub_dprintf ("appendedsig", ++ "verify signer %d with key '%s' succeeded\n", i, ++ pk->subject); ++ err = GRUB_ERR_NONE; ++ break; ++ } ++ ++ grub_dprintf ("appendedsig", ++ "verify signer %d with key '%s' failed with %d\n", i, ++ pk->subject, rc); ++ } ++ ++ grub_free (context); ++ ++ if (err == GRUB_ERR_NONE) ++ break; ++ } ++ ++ /* If we didn't verify, provide a neat message */ ++ if (err != GRUB_ERR_NONE) ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("Failed to verify signature against a trusted key")); ++ ++cleanup: ++ pkcs7_signedData_release (&sig.pkcs7); ++ ++ return err; ++} ++ ++static grub_err_t ++grub_cmd_verify_signature (grub_command_t cmd __attribute__((unused)), ++ int argc, char **args) ++{ ++ grub_file_t f; ++ grub_err_t err = GRUB_ERR_NONE; ++ grub_uint8_t *data; ++ grub_size_t file_size; ++ ++ if (argc < 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); ++ ++ grub_dprintf ("appendedsig", "verifying %s\n", args[0]); ++ ++ f = grub_file_open (args[0], GRUB_FILE_TYPE_VERIFY_SIGNATURE); ++ if (!f) ++ { ++ err = grub_errno; ++ goto cleanup; ++ } ++ ++ err = file_read_all (f, &data, &file_size); ++ if (err != GRUB_ERR_NONE) ++ goto cleanup; ++ ++ err = grub_verify_appended_signature (data, file_size); ++ ++ grub_free (data); ++ ++cleanup: ++ if (f) ++ grub_file_close (f); ++ return err; ++} ++ ++static grub_err_t ++grub_cmd_distrust (grub_command_t cmd __attribute__((unused)), ++ int argc, char **args) ++{ ++ unsigned long cert_num, i; ++ struct x509_certificate *cert, *prev; ++ ++ if (argc != 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("One argument expected")); ++ ++ grub_errno = GRUB_ERR_NONE; ++ cert_num = grub_strtoul (args[0], NULL, 10); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; ++ ++ if (cert_num < 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("Certificate number too small - numbers start at 1")); ++ ++ if (cert_num == 1) ++ { ++ cert = grub_trusted_key; ++ grub_trusted_key = cert->next; ++ ++ certificate_release (cert); ++ grub_free (cert); ++ return GRUB_ERR_NONE; ++ } ++ i = 2; ++ prev = grub_trusted_key; ++ cert = grub_trusted_key->next; ++ while (cert) ++ { ++ if (i == cert_num) ++ { ++ prev->next = cert->next; ++ certificate_release (cert); ++ grub_free (cert); ++ return GRUB_ERR_NONE; ++ } ++ i++; ++ prev = cert; ++ cert = cert->next; ++ } ++ ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("No certificate number %lu found - only %lu certificates in the store"), ++ cert_num, i - 1); ++} ++ ++static grub_err_t ++grub_cmd_trust (grub_command_t cmd __attribute__((unused)), ++ int argc, char **args) ++{ ++ grub_file_t certf; ++ struct x509_certificate *cert = NULL; ++ grub_err_t err; ++ ++ if (argc != 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); ++ ++ certf = grub_file_open (args[0], ++ GRUB_FILE_TYPE_CERTIFICATE_TRUST ++ | GRUB_FILE_TYPE_NO_DECOMPRESS); ++ if (!certf) ++ return grub_errno; ++ ++ ++ cert = grub_zalloc (sizeof (struct x509_certificate)); ++ if (!cert) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ N_("Could not allocate memory for certificate")); ++ ++ err = read_cert_from_file (certf, cert); ++ grub_file_close (certf); ++ if (err != GRUB_ERR_NONE) ++ { ++ grub_free (cert); ++ return err; ++ } ++ grub_dprintf ("appendedsig", "Loaded certificate with CN: %s\n", ++ cert->subject); ++ ++ cert->next = grub_trusted_key; ++ grub_trusted_key = cert; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_list (grub_command_t cmd __attribute__((unused)), ++ int argc __attribute__((unused)), ++ char **args __attribute__((unused))) ++{ ++ struct x509_certificate *cert; ++ int cert_num = 1; ++ grub_size_t i; ++ ++ for (cert = grub_trusted_key; cert; cert = cert->next) ++ { ++ grub_printf (N_("Certificate %d:\n"), cert_num); ++ ++ grub_printf (N_("\tSerial: ")); ++ for (i = 0; i < cert->serial_len - 1; i++) ++ { ++ grub_printf ("%02x:", cert->serial[i]); ++ } ++ grub_printf ("%02x\n", cert->serial[cert->serial_len - 1]); ++ ++ grub_printf ("\tCN: %s\n\n", cert->subject); ++ cert_num++; ++ ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++appendedsig_init (grub_file_t io __attribute__((unused)), ++ enum grub_file_type type, ++ void **context __attribute__((unused)), ++ enum grub_verify_flags *flags) ++{ ++ if (check_sigs == check_sigs_no) ++ { ++ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; ++ return GRUB_ERR_NONE; ++ } ++ ++ switch (type & GRUB_FILE_TYPE_MASK) ++ { ++ case GRUB_FILE_TYPE_CERTIFICATE_TRUST: ++ /* ++ * This is a certificate to add to trusted keychain. ++ * ++ * This needs to be verified or blocked. Ideally we'd write an x509 ++ * verifier, but we lack the hubris required to take this on. Instead, ++ * require that it have an appended signature. ++ */ ++ ++ /* Fall through */ ++ ++ case GRUB_FILE_TYPE_LINUX_KERNEL: ++ case GRUB_FILE_TYPE_GRUB_MODULE: ++ /* ++ * Appended signatures are only defined for ELF binaries. ++ * Out of an abundance of caution, we only verify Linux kernels and ++ * GRUB modules at this point. ++ */ ++ *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK; ++ return GRUB_ERR_NONE; ++ ++ case GRUB_FILE_TYPE_ACPI_TABLE: ++ case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE: ++ /* ++ * It is possible to use appended signature verification without ++ * lockdown - like the PGP verifier. When combined with an embedded ++ * config file in a signed grub binary, this could still be a meaningful ++ * secure-boot chain - so long as it isn't subverted by something like a ++ * rouge ACPI table or DT image. Defer them explicitly. ++ */ ++ *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH; ++ return GRUB_ERR_NONE; ++ ++ default: ++ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; ++ return GRUB_ERR_NONE; ++ } ++} ++ ++static grub_err_t ++appendedsig_write (void *ctxt __attribute__((unused)), ++ void *buf, grub_size_t size) ++{ ++ return grub_verify_appended_signature (buf, size); ++} ++ ++struct grub_file_verifier grub_appendedsig_verifier = { ++ .name = "appendedsig", ++ .init = appendedsig_init, ++ .write = appendedsig_write, ++}; ++ ++static grub_ssize_t ++pseudo_read (struct grub_file *file, char *buf, grub_size_t len) ++{ ++ grub_memcpy (buf, (grub_uint8_t *) file->data + file->offset, len); ++ return len; ++} ++ ++/* Filesystem descriptor. */ ++static struct grub_fs pseudo_fs = { ++ .name = "pseudo", ++ .fs_read = pseudo_read ++}; ++ ++static grub_command_t cmd_verify, cmd_list, cmd_distrust, cmd_trust; ++ ++GRUB_MOD_INIT (appendedsig) ++{ ++ int rc; ++ struct grub_module_header *header; ++ ++ /* If in lockdown, immediately enter forced mode */ ++ if (grub_is_lockdown () == GRUB_LOCKDOWN_ENABLED) ++ check_sigs = check_sigs_forced; ++ ++ grub_trusted_key = NULL; ++ ++ grub_register_variable_hook ("check_appended_signatures", ++ grub_env_read_sec, grub_env_write_sec); ++ grub_env_export ("check_appended_signatures"); ++ ++ rc = asn1_init (); ++ if (rc) ++ grub_fatal ("Error initing ASN.1 data structures: %d: %s\n", rc, ++ asn1_strerror (rc)); ++ ++ FOR_MODULES (header) ++ { ++ struct grub_file pseudo_file; ++ struct x509_certificate *pk = NULL; ++ grub_err_t err; ++ ++ /* Not an ELF module, skip. */ ++ if (header->type != OBJ_TYPE_X509_PUBKEY) ++ continue; ++ ++ grub_memset (&pseudo_file, 0, sizeof (pseudo_file)); ++ pseudo_file.fs = &pseudo_fs; ++ pseudo_file.size = header->size - sizeof (struct grub_module_header); ++ pseudo_file.data = (char *) header + sizeof (struct grub_module_header); ++ ++ grub_dprintf ("appendedsig", ++ "Found an x509 key, size=%" PRIuGRUB_UINT64_T "\n", ++ pseudo_file.size); ++ ++ pk = grub_zalloc (sizeof (struct x509_certificate)); ++ if (!pk) ++ { ++ grub_fatal ("Out of memory loading initial certificates"); ++ } ++ ++ err = read_cert_from_file (&pseudo_file, pk); ++ if (err != GRUB_ERR_NONE) ++ grub_fatal ("Error loading initial key: %s", grub_errmsg); ++ ++ grub_dprintf ("appendedsig", "loaded certificate CN='%s'\n", pk->subject); ++ ++ pk->next = grub_trusted_key; ++ grub_trusted_key = pk; ++ } ++ ++ cmd_trust = ++ grub_register_command ("trust_certificate", grub_cmd_trust, ++ N_("X509_CERTIFICATE"), ++ N_("Add X509_CERTIFICATE to trusted certificates.")); ++ cmd_list = ++ grub_register_command ("list_certificates", grub_cmd_list, 0, ++ N_("Show the list of trusted x509 certificates.")); ++ cmd_verify = ++ grub_register_command ("verify_appended", grub_cmd_verify_signature, ++ N_("FILE"), ++ N_("Verify FILE against the trusted x509 certificates.")); ++ cmd_distrust = ++ grub_register_command ("distrust_certificate", grub_cmd_distrust, ++ N_("CERT_NUMBER"), ++ N_("Remove CERT_NUMBER (as listed by list_certificates) from trusted certificates.")); ++ ++ grub_verifier_register (&grub_appendedsig_verifier); ++ grub_dl_set_persistent (mod); ++} ++ ++GRUB_MOD_FINI (appendedsig) ++{ ++ /* ++ * grub_dl_set_persistent should prevent this from actually running, but ++ * it does still run under emu. ++ */ ++ ++ grub_verifier_unregister (&grub_appendedsig_verifier); ++ grub_unregister_command (cmd_verify); ++ grub_unregister_command (cmd_list); ++ grub_unregister_command (cmd_trust); ++ grub_unregister_command (cmd_distrust); ++} +diff --git a/include/grub/file.h b/include/grub/file.h +index 811728a99..99b1f3855 100644 +--- a/include/grub/file.h ++++ b/include/grub/file.h +@@ -80,6 +80,8 @@ enum grub_file_type + GRUB_FILE_TYPE_PUBLIC_KEY, + /* File holding public key to add to trused keys. */ + GRUB_FILE_TYPE_PUBLIC_KEY_TRUST, ++ /* File holding x509 certificiate to add to trusted keys. */ ++ GRUB_FILE_TYPE_CERTIFICATE_TRUST, + /* File of which we intend to print a blocklist to the user. */ + GRUB_FILE_TYPE_PRINT_BLOCKLIST, + /* File we intend to use for test loading or testing speed. */ +-- +2.31.1 + diff --git a/0019-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch b/0019-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch new file mode 100644 index 0000000..ea97434 --- /dev/null +++ b/0019-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch @@ -0,0 +1,59 @@ +From cc43d9a3d77069850f993fbc4ae47c941bf284b9 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 16 Sep 2021 01:29:54 +1000 +Subject: [PATCH 19/32] net/dns: Fix double-free addresses on corrupt DNS + response + +grub_net_dns_lookup() takes as inputs a pointer to an array of addresses +("addresses") for the given name, and pointer to a number of addresses +("naddresses"). grub_net_dns_lookup() is responsible for allocating +"addresses", and the caller is responsible for freeing it if +"naddresses" > 0. + +The DNS recv_hook will sometimes set and free the addresses array, +for example if the packet is too short: + + if (ptr + 10 >= nb->tail) + { + if (!*data->naddresses) + grub_free (*data->addresses); + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + +Later on the nslookup command code unconditionally frees the "addresses" +array. Normally this is fine: the array is either populated with valid +data or is NULL. But in these sorts of error cases it is neither NULL +nor valid and we get a double-free. + +Only free "addresses" if "naddresses" > 0. + +It looks like the other use of grub_net_dns_lookup() is not affected. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/net/dns.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c +index 906ec7d678..135faac035 100644 +--- a/grub-core/net/dns.c ++++ b/grub-core/net/dns.c +@@ -667,9 +667,11 @@ grub_cmd_nslookup (struct grub_command *cmd __attribute__ ((unused)), + grub_net_addr_to_str (&addresses[i], buf); + grub_printf ("%s\n", buf); + } +- grub_free (addresses); + if (naddresses) +- return GRUB_ERR_NONE; ++ { ++ grub_free (addresses); ++ return GRUB_ERR_NONE; ++ } + return grub_error (GRUB_ERR_NET_NO_DOMAIN, N_("no DNS record found")); + } + +-- +2.34.1 + diff --git a/0020-appended-signatures-verification-tests.patch b/0020-appended-signatures-verification-tests.patch new file mode 100644 index 0000000..274ea1f --- /dev/null +++ b/0020-appended-signatures-verification-tests.patch @@ -0,0 +1,1321 @@ +From 221f2419c70cd953515562901b1e72946632cd13 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 30 Jul 2020 01:31:02 +1000 +Subject: [PATCH 20/23] appended signatures: verification tests + +These tests are run through all_functional_test and test a range +of commands and behaviours. + +Signed-off-by: Daniel Axtens + +--- + +v2 changes: + + - add a test for EKU + - add tests for files signed with multiple signers + - add a test of padded PKCS#7 messages + - use macros to reduce duplication for exposing certificate files + to the test via procfs + - more useful comments +--- + grub-core/Makefile.core.def | 6 + + grub-core/tests/appended_signature_test.c | 273 ++++++ + grub-core/tests/appended_signatures.h | 975 ++++++++++++++++++++++ + grub-core/tests/lib/functional_test.c | 1 + + 4 files changed, 1255 insertions(+) + create mode 100644 grub-core/tests/appended_signature_test.c + create mode 100644 grub-core/tests/appended_signatures.h + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index b55294e25..88eedd16d 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2161,6 +2161,12 @@ module = { + common = tests/setjmp_test.c; + }; + ++module = { ++ name = appended_signature_test; ++ common = tests/appended_signature_test.c; ++ common = tests/appended_signatures.h; ++}; ++ + module = { + name = signature_test; + common = tests/signature_test.c; +diff --git a/grub-core/tests/appended_signature_test.c b/grub-core/tests/appended_signature_test.c +new file mode 100644 +index 000000000..5365185cb +--- /dev/null ++++ b/grub-core/tests/appended_signature_test.c +@@ -0,0 +1,273 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 IBM Corporation. ++ * ++ * 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 . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "appended_signatures.h" ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++#define PROC_FILE(identifier, file_name) \ ++static char * \ ++get_ ## identifier (grub_size_t *sz) \ ++{ \ ++ char *ret; \ ++ \ ++ *sz = identifier ## _len; \ ++ ret = grub_malloc (*sz); \ ++ if (ret) \ ++ grub_memcpy (ret, identifier, *sz); \ ++ return ret; \ ++} \ ++\ ++static struct grub_procfs_entry identifier ## _entry = \ ++{ \ ++ .name = file_name, \ ++ .get_contents = get_ ## identifier \ ++}; ++ ++#define DEFINE_TEST_CASE(case_name) PROC_FILE(case_name, #case_name) ++ ++#define DO_TEST(case_name, is_valid) \ ++{ \ ++ grub_procfs_register (#case_name, &case_name ## _entry); \ ++ do_verify ("(proc)/" #case_name, is_valid); \ ++ grub_procfs_unregister (&case_name ## _entry); \ ++} ++ ++ ++DEFINE_TEST_CASE (hi_signed); ++DEFINE_TEST_CASE (hi_signed_sha256); ++DEFINE_TEST_CASE (hj_signed); ++DEFINE_TEST_CASE (short_msg); ++DEFINE_TEST_CASE (unsigned_msg); ++DEFINE_TEST_CASE (hi_signed_2nd); ++DEFINE_TEST_CASE (hi_double); ++DEFINE_TEST_CASE (hi_double_extended); ++ ++PROC_FILE (certificate_der, "certificate.der") ++PROC_FILE (certificate2_der, "certificate2.der") ++PROC_FILE (certificate_printable_der, "certificate_printable.der") ++PROC_FILE (certificate_eku_der, "certificate_eku.der") ++ ++static void ++do_verify (const char *f, int is_valid) ++{ ++ grub_command_t cmd; ++ char *args[] = { (char *) f, NULL }; ++ grub_err_t err; ++ ++ cmd = grub_command_find ("verify_appended"); ++ if (!cmd) ++ { ++ grub_test_assert (0, "can't find command `%s'", "verify_appended"); ++ return; ++ } ++ err = (cmd->func) (cmd, 1, args); ++ if (is_valid) ++ { ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "verification of %s failed: %d: %s", f, grub_errno, ++ grub_errmsg); ++ } ++ else ++ { ++ grub_test_assert (err == GRUB_ERR_BAD_SIGNATURE, ++ "verification of %s unexpectedly succeeded", f); ++ } ++ grub_errno = GRUB_ERR_NONE; ++ ++} ++ ++static void ++appended_signature_test (void) ++{ ++ grub_command_t cmd_trust, cmd_distrust; ++ char *trust_args[] = { (char *) "(proc)/certificate.der", NULL }; ++ char *trust_args2[] = { (char *) "(proc)/certificate2.der", NULL }; ++ char *trust_args_printable[] = { (char *) "(proc)/certificate_printable.der", ++ NULL }; ++ char *trust_args_eku[] = { (char *) "(proc)/certificate_eku.der", NULL }; ++ char *distrust_args[] = { (char *) "1", NULL }; ++ char *distrust2_args[] = { (char *) "2", NULL }; ++ grub_err_t err; ++ ++ grub_procfs_register ("certificate.der", &certificate_der_entry); ++ grub_procfs_register ("certificate2.der", &certificate2_der_entry); ++ grub_procfs_register ("certificate_printable.der", ++ &certificate_printable_der_entry); ++ grub_procfs_register ("certificate_eku.der", &certificate_eku_der_entry); ++ ++ cmd_trust = grub_command_find ("trust_certificate"); ++ if (!cmd_trust) ++ { ++ grub_test_assert (0, "can't find command `%s'", "trust_certificate"); ++ return; ++ } ++ err = (cmd_trust->func) (cmd_trust, 1, trust_args); ++ ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "loading certificate failed: %d: %s", grub_errno, ++ grub_errmsg); ++ ++ /* If we have no certificate the remainder of the tests are meaningless */ ++ if (err != GRUB_ERR_NONE) ++ return; ++ ++ /* ++ * Reload the command: this works around some 'interesting' behaviour in the ++ * dynamic command dispatcher. The first time you call cmd->func you get a ++ * dispatcher that loads the module, finds the real cmd, calls it, and then ++ * releases some internal storage. This means it's not safe to call a second ++ * time and we need to reload it. ++ */ ++ cmd_trust = grub_command_find ("trust_certificate"); ++ ++ /* hi, signed with key 1, SHA-512 */ ++ DO_TEST (hi_signed, 1); ++ ++ /* hi, signed with key 1, SHA-256 */ ++ DO_TEST (hi_signed_sha256, 1); ++ ++ /* hi, key 1, SHA-512, second byte corrupted */ ++ DO_TEST (hj_signed, 0); ++ ++ /* message too short for a signature */ ++ DO_TEST (short_msg, 0); ++ ++ /* lorem ipsum */ ++ DO_TEST (unsigned_msg, 0); ++ ++ /* hi, signed with both keys, SHA-512 */ ++ DO_TEST (hi_double, 1); ++ ++ /* ++ * hi, signed with both keys and with empty space to test we haven't broken ++ * support for adding more signatures after the fact ++ */ ++ DO_TEST (hi_double_extended, 1); ++ ++ /* ++ * in enforcing mode, we shouldn't be able to load a certificate that isn't ++ * signed by an existing trusted key. ++ * ++ * However, procfs files automatically skip the verification test, so we can't ++ * easily test this. ++ */ ++ ++ /* ++ * verify that testing with 2 trusted certs works ++ */ ++ DO_TEST (hi_signed_2nd, 0); ++ ++ err = (cmd_trust->func) (cmd_trust, 1, trust_args2); ++ ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "loading certificate 2 failed: %d: %s", grub_errno, ++ grub_errmsg); ++ ++ if (err != GRUB_ERR_NONE) ++ return; ++ ++ DO_TEST (hi_signed_2nd, 1); ++ DO_TEST (hi_signed, 1); ++ DO_TEST (hi_double, 1); ++ DO_TEST (hi_double_extended, 1); ++ ++ /* ++ * Check certificate removal. They're added to the _top_ of the list and ++ * removed by position in the list. Current the list looks like [#2, #1]. ++ * ++ * First test removing the second certificate in the list, which is ++ * certificate #1, giving us just [#2]. ++ */ ++ cmd_distrust = grub_command_find ("distrust_certificate"); ++ if (!cmd_distrust) ++ { ++ grub_test_assert (0, "can't find command `%s'", "distrust_certificate"); ++ return; ++ } ++ ++ err = (cmd_distrust->func) (cmd_distrust, 1, distrust2_args); ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "distrusting certificate 1 failed: %d: %s", grub_errno, ++ grub_errmsg); ++ DO_TEST (hi_signed_2nd, 1); ++ DO_TEST (hi_signed, 0); ++ DO_TEST (hi_double, 1); ++ ++ /* ++ * Now reload certificate #1. This will make the list look like [#1, #2] ++ */ ++ err = (cmd_trust->func) (cmd_trust, 1, trust_args); ++ ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "reloading certificate 1 failed: %d: %s", grub_errno, ++ grub_errmsg); ++ DO_TEST (hi_signed, 1); ++ ++ /* Remove the first certificate in the list, giving us just [#2] */ ++ err = (cmd_distrust->func) (cmd_distrust, 1, distrust_args); ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "distrusting certificate 1 (first time) failed: %d: %s", ++ grub_errno, grub_errmsg); ++ DO_TEST (hi_signed_2nd, 1); ++ DO_TEST (hi_signed, 0); ++ ++ /* ++ * Remove the first certificate again, giving an empty list. ++ * ++ * verify_appended should fail if there are no certificates to verify against. ++ */ ++ err = (cmd_distrust->func) (cmd_distrust, 1, distrust_args); ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "distrusting certificate 1 (second time) failed: %d: %s", ++ grub_errno, grub_errmsg); ++ DO_TEST (hi_signed_2nd, 0); ++ DO_TEST (hi_double, 0); ++ ++ /* ++ * Lastly, check a certificate that uses printableString rather than ++ * utf8String loads properly, and that a certificate with an appropriate ++ * extended key usage loads. ++ */ ++ err = (cmd_trust->func) (cmd_trust, 1, trust_args_printable); ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "trusting printable certificate failed: %d: %s", ++ grub_errno, grub_errmsg); ++ ++ err = (cmd_trust->func) (cmd_trust, 1, trust_args_eku); ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "trusting certificate with extended key usage failed: %d: %s", ++ grub_errno, grub_errmsg); ++ ++ grub_procfs_unregister (&certificate_der_entry); ++ grub_procfs_unregister (&certificate2_der_entry); ++ grub_procfs_unregister (&certificate_printable_der_entry); ++ grub_procfs_unregister (&certificate_eku_der_entry); ++} ++ ++GRUB_FUNCTIONAL_TEST (appended_signature_test, appended_signature_test); +diff --git a/grub-core/tests/appended_signatures.h b/grub-core/tests/appended_signatures.h +new file mode 100644 +index 000000000..c6aa12d86 +--- /dev/null ++++ b/grub-core/tests/appended_signatures.h +@@ -0,0 +1,975 @@ ++unsigned char certificate_der[] = { ++ 0x30, 0x82, 0x05, 0x5d, 0x30, 0x82, 0x03, 0x45, 0xa0, 0x03, 0x02, 0x01, ++ 0x02, 0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, ++ 0x3a, 0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x92, 0x03, 0x30, ++ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, ++ 0x05, 0x00, 0x30, 0x3d, 0x31, 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, ++ 0x03, 0x0c, 0x32, 0x47, 0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, ++ 0x6e, 0x64, 0x65, 0x64, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, ++ 0x72, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, ++ 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, ++ 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x31, 0x30, ++ 0x36, 0x32, 0x39, 0x30, 0x38, 0x33, 0x36, 0x31, 0x33, 0x5a, 0x18, 0x0f, ++ 0x32, 0x31, 0x32, 0x31, 0x30, 0x36, 0x30, 0x35, 0x30, 0x38, 0x33, 0x36, ++ 0x31, 0x33, 0x5a, 0x30, 0x33, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55, ++ 0x04, 0x03, 0x0c, 0x28, 0x47, 0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, ++ 0x65, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, ++ 0x75, 0x72, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x69, 0x67, ++ 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x4b, 0x65, 0x79, 0x30, 0x82, 0x02, 0x22, ++ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, ++ 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, ++ 0x02, 0x82, 0x02, 0x01, 0x00, 0xb9, 0x09, 0xb2, 0xf6, 0x24, 0x34, 0xdc, ++ 0x62, 0xe6, 0x4e, 0xee, 0x04, 0xdb, 0x29, 0xdc, 0x94, 0xcc, 0xee, 0x8a, ++ 0x5b, 0xc3, 0x9e, 0x06, 0xba, 0xa7, 0x9b, 0xa4, 0x5f, 0x15, 0x59, 0x8e, ++ 0xb8, 0x6e, 0x3c, 0xeb, 0x2e, 0xf2, 0xac, 0x21, 0x42, 0xbd, 0x30, 0xa1, ++ 0x39, 0xe5, 0xb9, 0x4f, 0xa0, 0x53, 0xd5, 0x42, 0xdc, 0x8a, 0x87, 0x30, ++ 0x38, 0x93, 0x44, 0x80, 0x3b, 0x1a, 0x7e, 0x9e, 0x8e, 0x3e, 0xea, 0x45, ++ 0xa0, 0x11, 0x8b, 0xfb, 0x78, 0xe4, 0xbc, 0x65, 0x6b, 0x73, 0xea, 0x6e, ++ 0xdf, 0x7c, 0x5b, 0x63, 0x7e, 0x5b, 0x0a, 0x1c, 0xe6, 0x76, 0x19, 0xb5, ++ 0x01, 0xde, 0xf6, 0x65, 0x51, 0x30, 0x0a, 0x56, 0x69, 0x69, 0xe8, 0x20, ++ 0xf9, 0x13, 0xf1, 0xbf, 0x6f, 0xdd, 0xce, 0x94, 0x96, 0x6e, 0x63, 0xd6, ++ 0xfa, 0xa4, 0x91, 0x5f, 0xb3, 0x9c, 0xc7, 0xfa, 0xa9, 0xff, 0x66, 0x5f, ++ 0xf3, 0xab, 0x5e, 0xdf, 0x4e, 0xca, 0x11, 0xcf, 0xbf, 0xf8, 0xad, 0x65, ++ 0xb1, 0x49, 0x8b, 0xe9, 0x2a, 0xad, 0x7d, 0xf3, 0x0b, 0xfa, 0x5b, 0x6a, ++ 0x6a, 0x20, 0x12, 0x77, 0xef, 0x4b, 0xb6, 0xbe, 0x92, 0xba, 0x14, 0x9c, ++ 0x5e, 0xea, 0xdc, 0x56, 0x6d, 0x92, 0xd3, 0x64, 0x22, 0xf6, 0x12, 0xe8, ++ 0x7d, 0x5e, 0x9c, 0xd6, 0xf9, 0x75, 0x68, 0x7f, 0x8f, 0xd3, 0x6e, 0x05, ++ 0x94, 0x91, 0x4f, 0xa1, 0xd6, 0x50, 0x72, 0x3b, 0x11, 0x1f, 0x28, 0x13, ++ 0xe8, 0x25, 0x6b, 0xdf, 0xff, 0x72, 0x46, 0x25, 0xe9, 0x05, 0x6f, 0x02, ++ 0xc7, 0x1e, 0xc9, 0xcf, 0x99, 0xe9, 0xa7, 0xe2, 0xae, 0xbc, 0xc1, 0x22, ++ 0x32, 0x73, 0x2d, 0xa3, 0x70, 0x8f, 0xa7, 0x8d, 0xbf, 0x5f, 0x74, 0x05, ++ 0x1b, 0x5e, 0xfe, 0x97, 0x3c, 0xe7, 0x3b, 0x86, 0x0d, 0xf6, 0x38, 0xdb, ++ 0xd2, 0x39, 0x47, 0x82, 0x00, 0x44, 0x6c, 0x7b, 0x40, 0x24, 0x0b, 0x3a, ++ 0xd4, 0x19, 0x31, 0xba, 0x4e, 0x8e, 0xa3, 0x33, 0xa6, 0x78, 0xef, 0x72, ++ 0x9f, 0x06, 0x37, 0x01, 0x9b, 0x79, 0x0d, 0x04, 0xbf, 0xba, 0xd5, 0x1f, ++ 0x27, 0xdc, 0x85, 0xbb, 0xef, 0xd2, 0x60, 0xda, 0xa0, 0x3f, 0x66, 0xce, ++ 0x9f, 0xa2, 0x7e, 0xa8, 0x8d, 0xee, 0x14, 0x4b, 0xcb, 0x93, 0xf1, 0x38, ++ 0xac, 0x4f, 0xd8, 0x29, 0xf3, 0x6f, 0xd4, 0xfd, 0x4d, 0x34, 0x77, 0x58, ++ 0x99, 0xdb, 0x16, 0xc1, 0xd0, 0xc7, 0x43, 0x41, 0x70, 0xc4, 0xad, 0x01, ++ 0x29, 0x65, 0x22, 0x43, 0x00, 0x6f, 0xb3, 0x00, 0x27, 0x38, 0xc1, 0x4f, ++ 0xda, 0x28, 0x96, 0x42, 0xdc, 0xbc, 0x3e, 0x34, 0x8e, 0x14, 0xb8, 0xf3, ++ 0x86, 0x4a, 0xea, 0x16, 0x90, 0xf9, 0x0e, 0x9e, 0x8f, 0x66, 0x0c, 0xbf, ++ 0x29, 0xd3, 0x8f, 0xfc, 0x4d, 0x38, 0x68, 0xe2, 0xe7, 0x64, 0x32, 0x47, ++ 0xdd, 0x56, 0xc9, 0xe4, 0x47, 0x9f, 0x18, 0x89, 0xfc, 0x30, 0x7a, 0xae, ++ 0x63, 0xe4, 0xec, 0x93, 0x04, 0xd4, 0x61, 0xe7, 0xbf, 0x0a, 0x06, 0x29, ++ 0xc2, 0xa6, 0xd5, 0x53, 0x5d, 0x65, 0x6d, 0x4a, 0xd0, 0xb7, 0x68, 0x4d, ++ 0x46, 0x0a, 0xb5, 0xff, 0x52, 0x5e, 0x92, 0x7e, 0x75, 0x08, 0xa4, 0x63, ++ 0x0a, 0x6c, 0x31, 0x7a, 0xaa, 0x0c, 0x52, 0xf4, 0x2e, 0xcd, 0x08, 0xeb, ++ 0xb3, 0xbd, 0xad, 0x8b, 0x8b, 0x9b, 0x8d, 0x71, 0x42, 0x30, 0x8e, 0xc7, ++ 0xfd, 0xec, 0xb7, 0xe6, 0x26, 0x96, 0xf2, 0x74, 0x1b, 0x78, 0x95, 0x22, ++ 0x14, 0xf3, 0xc9, 0xd3, 0x79, 0x11, 0xd9, 0xb7, 0x4d, 0x0d, 0x61, 0x60, ++ 0x5c, 0x47, 0x50, 0xf3, 0xca, 0x84, 0x4c, 0x5c, 0x30, 0x2c, 0x6a, 0x18, ++ 0x26, 0xb0, 0xf3, 0xd1, 0x15, 0x19, 0x39, 0xc3, 0x23, 0x13, 0x0f, 0x9c, ++ 0x97, 0x2b, 0x97, 0x93, 0xf9, 0xf8, 0x18, 0x9b, 0x4a, 0x4d, 0xd6, 0xd3, ++ 0xf5, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x5d, 0x30, 0x5b, 0x30, 0x0c, ++ 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, ++ 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x07, ++ 0x80, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, ++ 0x8f, 0xba, 0x8b, 0xf5, 0xf4, 0x77, 0xb2, 0xa4, 0x19, 0xef, 0x43, 0xb1, ++ 0x8b, 0x03, 0x4b, 0x45, 0x47, 0xb5, 0x2a, 0x48, 0x30, 0x1f, 0x06, 0x03, ++ 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x59, 0x1c, 0xb5, ++ 0x52, 0x62, 0x83, 0x05, 0x3b, 0x41, 0x4c, 0x63, 0x4d, 0x5b, 0xf4, 0x8c, ++ 0xe6, 0xd7, 0xda, 0x87, 0x54, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, ++ 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, ++ 0x00, 0x36, 0x2d, 0x0a, 0xcb, 0x49, 0x54, 0x75, 0xd7, 0xca, 0x21, 0x86, ++ 0xae, 0x40, 0x0f, 0x63, 0x10, 0x35, 0xfd, 0xbc, 0xba, 0x28, 0x31, 0x33, ++ 0x07, 0x08, 0x64, 0x03, 0x6c, 0xd3, 0xd5, 0xf7, 0xb7, 0x79, 0x11, 0x0c, ++ 0xa8, 0x9e, 0xfd, 0x34, 0xa2, 0xba, 0x77, 0x15, 0x15, 0x2d, 0x2c, 0x96, ++ 0xae, 0x47, 0xbb, 0x82, 0x89, 0x09, 0x7f, 0xd1, 0x95, 0x69, 0x9b, 0xfe, ++ 0xd7, 0x6f, 0x4e, 0x68, 0xf6, 0xe7, 0x5f, 0x54, 0xa1, 0x3a, 0xeb, 0xa4, ++ 0xbf, 0x7a, 0xb6, 0x7f, 0xaa, 0xd8, 0xd7, 0x99, 0xcb, 0xae, 0x88, 0x6d, ++ 0x7a, 0xf3, 0xfa, 0x9e, 0x44, 0x2f, 0x30, 0xa8, 0xe6, 0xb9, 0x75, 0xa0, ++ 0x82, 0xd6, 0xb0, 0xe3, 0x03, 0xb3, 0x12, 0xa3, 0xdc, 0xb9, 0x4d, 0x93, ++ 0xd4, 0x30, 0xea, 0xce, 0x96, 0x92, 0x07, 0xf8, 0xba, 0xe4, 0x0f, 0x41, ++ 0xe3, 0x04, 0xaa, 0x8c, 0x07, 0x1a, 0x34, 0x60, 0xfc, 0xc0, 0x05, 0xd2, ++ 0x5a, 0xa8, 0x66, 0xef, 0xe0, 0x94, 0xc5, 0x2f, 0x0f, 0xff, 0xdc, 0x70, ++ 0xfb, 0xe2, 0x9d, 0x61, 0x51, 0x25, 0x02, 0xff, 0x4b, 0x69, 0xfd, 0x66, ++ 0xb9, 0xeb, 0x0c, 0xc8, 0x50, 0xd3, 0xb1, 0x08, 0x1e, 0x09, 0x54, 0x87, ++ 0xe8, 0xa3, 0x4b, 0xef, 0x0c, 0x32, 0x0a, 0x6c, 0xec, 0x27, 0x22, 0xba, ++ 0x7f, 0xdc, 0x52, 0x27, 0x31, 0x14, 0x9a, 0xa8, 0xf7, 0xf9, 0xeb, 0xc8, ++ 0xb5, 0x8d, 0x12, 0xed, 0x94, 0xab, 0x3d, 0x9a, 0xfb, 0x4e, 0x04, 0x05, ++ 0xd2, 0x3c, 0x7c, 0x8a, 0xed, 0x46, 0x1b, 0x7c, 0xb5, 0x6c, 0x40, 0xb8, ++ 0xc1, 0xbf, 0xb0, 0xd2, 0x93, 0x8e, 0xa8, 0x0f, 0xde, 0x78, 0xf3, 0x8c, ++ 0xd8, 0x9f, 0xf8, 0xdc, 0xa1, 0x23, 0x20, 0x40, 0x17, 0xb4, 0xdb, 0xb7, ++ 0x09, 0x74, 0xa7, 0x80, 0xc2, 0x12, 0xd9, 0x76, 0x79, 0x5b, 0x71, 0xa9, ++ 0x6c, 0xd4, 0x57, 0x48, 0xe8, 0xfe, 0xc5, 0xc2, 0x6e, 0xe7, 0x83, 0x5a, ++ 0x07, 0xf0, 0x33, 0xc1, 0xc1, 0x1d, 0x34, 0xd4, 0xc8, 0xb0, 0xb7, 0xdb, ++ 0xeb, 0xe9, 0xe3, 0x59, 0xdc, 0x7f, 0x36, 0x58, 0xa9, 0xb8, 0x52, 0xdd, ++ 0xf9, 0xfd, 0x1c, 0x22, 0x2f, 0x93, 0x3d, 0x53, 0x89, 0x80, 0xde, 0xa2, ++ 0xb5, 0xa5, 0x36, 0xbd, 0xc3, 0x92, 0x03, 0xf3, 0x93, 0xc8, 0xc7, 0x4a, ++ 0x0b, 0x8b, 0x62, 0xfe, 0xd0, 0xf8, 0x0d, 0x7a, 0x32, 0xb4, 0x39, 0x1a, ++ 0xb7, 0x4e, 0xaa, 0xc4, 0x33, 0x32, 0x90, 0x8c, 0xab, 0xd4, 0xae, 0xa5, ++ 0xa4, 0x85, 0xcf, 0xba, 0xe1, 0x1b, 0x26, 0x7f, 0x74, 0x02, 0x12, 0x09, ++ 0x89, 0x56, 0xe4, 0xe7, 0x9d, 0x91, 0xde, 0x88, 0xe7, 0x1c, 0xed, 0x80, ++ 0x05, 0xa8, 0x58, 0x9a, 0x3e, 0x16, 0x97, 0xd5, 0xbc, 0x54, 0xcc, 0xf0, ++ 0x32, 0xf2, 0x93, 0x09, 0x94, 0x9f, 0x3c, 0xd9, 0x58, 0xca, 0x68, 0x0b, ++ 0xde, 0x3f, 0x73, 0x64, 0xb7, 0xf4, 0xd7, 0x5f, 0x2b, 0xe7, 0x7b, 0x06, ++ 0xca, 0xb1, 0x3e, 0xed, 0xd2, 0xb9, 0x29, 0xc1, 0x95, 0x87, 0xad, 0xd6, ++ 0x63, 0x69, 0xb8, 0x1f, 0x70, 0xdb, 0xeb, 0xc7, 0x11, 0x7d, 0xe2, 0x99, ++ 0x64, 0x6a, 0xf5, 0x3f, 0x30, 0x74, 0x5f, 0x2a, 0x21, 0xda, 0xef, 0x44, ++ 0x1d, 0xad, 0x97, 0xa1, 0xfe, 0x14, 0xa7, 0x88, 0x99, 0xd0, 0x1e, 0xb0, ++ 0x61, 0x88, 0x09, 0xc9, 0xfa, 0xd1, 0xb3, 0xcb, 0x1d, 0x76, 0x04, 0xbe, ++ 0x06, 0x44, 0xd2, 0x30, 0x5e, 0x95, 0x4b, 0x96, 0xc0, 0xd6, 0xbe, 0xd0, ++ 0x4d, 0xf2, 0xf4, 0x71, 0x72, 0xa9, 0xbd, 0x07, 0x4f, 0xbc, 0xb3, 0x78, ++ 0xb4, 0x8a, 0x44, 0xbd, 0x58, 0xd5, 0x21, 0xb6, 0x47, 0x9c, 0x88, 0x1f, ++ 0xbc, 0xbd, 0x54, 0xfa, 0x1d, 0x49, 0xec, 0x51, 0xd9, 0x43, 0x49, 0x9c, ++ 0x0c, 0xfa, 0x18, 0xdb, 0xeb, 0x05, 0x77, 0xa2, 0x9a ++}; ++unsigned int certificate_der_len = 1377; ++ ++unsigned char hi_signed[] = { ++ 0x68, 0x69, 0x0a, 0x30, 0x82, 0x02, 0xb4, 0x06, 0x09, 0x2a, 0x86, 0x48, ++ 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0xa5, 0x30, 0x82, ++ 0x02, 0xa1, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, ++ 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09, ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x02, ++ 0x7e, 0x30, 0x82, 0x02, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x55, 0x30, 0x3d, ++ 0x31, 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x32, 0x47, ++ 0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64, ++ 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, ++ 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, ++ 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, ++ 0x79, 0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, ++ 0x3a, 0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x92, 0x03, 0x30, ++ 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, ++ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, ++ 0x01, 0x05, 0x00, 0x04, 0x82, 0x02, 0x00, 0xa0, 0x83, 0x3f, 0xac, 0x77, ++ 0x97, 0x74, 0x9b, 0x4b, 0x25, 0xa1, 0x64, 0x09, 0x8d, 0x53, 0xa6, 0x03, ++ 0xdf, 0x9a, 0x10, 0x52, 0xe5, 0x3f, 0xd4, 0x72, 0x75, 0x30, 0xd4, 0x6e, ++ 0x77, 0x32, 0x49, 0x84, 0xe2, 0xbe, 0xef, 0xe4, 0xf3, 0xac, 0xb0, 0x52, ++ 0x55, 0xbf, 0xa9, 0x57, 0x12, 0x08, 0x7d, 0xb0, 0x86, 0xc0, 0x9d, 0x01, ++ 0xc2, 0x1a, 0x4a, 0x2e, 0x3d, 0xd5, 0xc8, 0x56, 0xac, 0xd1, 0x83, 0x75, ++ 0x88, 0xd4, 0xcc, 0x9f, 0x0d, 0xcf, 0xd3, 0xa6, 0x91, 0xb6, 0xb6, 0xb1, ++ 0xd1, 0x24, 0x9c, 0xd0, 0x13, 0xe8, 0x6b, 0x15, 0x9c, 0x62, 0x33, 0x8d, ++ 0xe3, 0x67, 0x9b, 0xb1, 0x8a, 0x72, 0x38, 0xf7, 0x48, 0x32, 0x2f, 0x1e, ++ 0x45, 0xa8, 0xc4, 0xa5, 0xae, 0xb1, 0xfc, 0x35, 0x25, 0xb5, 0xf9, 0x7f, ++ 0x86, 0xef, 0xa2, 0x6d, 0x78, 0xcc, 0xfd, 0x0c, 0xca, 0x8a, 0xe1, 0xae, ++ 0xcd, 0x0f, 0x58, 0x69, 0xf1, 0x8b, 0xcc, 0x22, 0x35, 0x6d, 0x1f, 0xd5, ++ 0x27, 0x87, 0x39, 0x62, 0x3f, 0xb2, 0x17, 0x3d, 0x5e, 0xb1, 0x32, 0x7a, ++ 0xf1, 0x70, 0xce, 0xfa, 0xab, 0x1c, 0x92, 0xa8, 0xe1, 0xc4, 0xb2, 0x33, ++ 0x1a, 0x16, 0xf3, 0x60, 0x39, 0xdf, 0xb8, 0x85, 0xe7, 0x5d, 0x4d, 0xc2, ++ 0x8d, 0x55, 0x00, 0x49, 0x94, 0x04, 0x17, 0x88, 0x7c, 0xf4, 0xac, 0xa9, ++ 0xc5, 0x3a, 0x09, 0xc4, 0xc2, 0xcd, 0x3d, 0xc3, 0xfc, 0x4e, 0xf3, 0x70, ++ 0xa1, 0xc1, 0x54, 0x36, 0x1f, 0x38, 0x6d, 0x7a, 0x6b, 0x6a, 0xd3, 0x67, ++ 0x04, 0xd5, 0x53, 0xd4, 0xa5, 0xad, 0x63, 0x55, 0x0e, 0x06, 0x06, 0x3a, ++ 0x9a, 0xc5, 0xfe, 0x38, 0xc9, 0xb0, 0x69, 0x42, 0x90, 0x35, 0x1f, 0xe3, ++ 0x1c, 0x57, 0xea, 0xdb, 0x51, 0x35, 0x53, 0xd3, 0x94, 0xfe, 0x72, 0x33, ++ 0xd6, 0x8a, 0x46, 0x74, 0xf9, 0x6e, 0x94, 0x40, 0x2f, 0xba, 0xa2, 0xc4, ++ 0xe9, 0xc9, 0x8a, 0xf4, 0xda, 0xe2, 0xca, 0x3e, 0x98, 0x85, 0xa5, 0xd1, ++ 0x60, 0x94, 0xc8, 0xdf, 0x82, 0xee, 0x5c, 0x0d, 0x2a, 0xa9, 0x8e, 0x26, ++ 0x83, 0x3f, 0x02, 0xa2, 0xaf, 0xb8, 0x3b, 0x83, 0xf2, 0x44, 0x46, 0x41, ++ 0xd7, 0x5c, 0xa1, 0x42, 0x17, 0xa2, 0xd0, 0x50, 0x42, 0xef, 0x66, 0xda, ++ 0x35, 0x03, 0xd1, 0x8e, 0x77, 0x22, 0x7d, 0x4e, 0xf7, 0x4e, 0x04, 0xe3, ++ 0x0f, 0x98, 0x7d, 0xaa, 0x58, 0xba, 0xef, 0x9a, 0xd0, 0x88, 0x7c, 0x98, ++ 0xa0, 0xc2, 0xff, 0xa6, 0xb1, 0xec, 0xbe, 0x6e, 0xb0, 0x7e, 0xc6, 0xe5, ++ 0xaa, 0xcf, 0x10, 0x73, 0xc9, 0x13, 0x1a, 0x20, 0x12, 0x5c, 0xd2, 0x0e, ++ 0xe2, 0x60, 0x17, 0xdf, 0x4a, 0x44, 0x08, 0x22, 0xbc, 0xcd, 0x75, 0xbe, ++ 0xc3, 0x7a, 0x12, 0x90, 0x90, 0xc7, 0x94, 0x4c, 0x98, 0x45, 0x02, 0x5c, ++ 0x24, 0xae, 0x82, 0x2f, 0xcd, 0x30, 0xa6, 0xf5, 0x3f, 0xd3, 0xa7, 0xa6, ++ 0xe6, 0xea, 0x11, 0x4e, 0x45, 0xb7, 0xc0, 0xe6, 0x24, 0x8b, 0x76, 0xc5, ++ 0x5e, 0xc1, 0xd8, 0x07, 0x1e, 0x26, 0x94, 0x7a, 0x80, 0xc6, 0x3b, 0x1f, ++ 0x74, 0xe6, 0xae, 0x43, 0x2d, 0x11, 0xee, 0x96, 0x56, 0x6c, 0xff, 0xcb, ++ 0x3b, 0xde, 0xcc, 0xb3, 0x7b, 0x08, 0xf5, 0x3e, 0x6e, 0x51, 0x71, 0xe0, ++ 0x8a, 0xfa, 0xdd, 0x19, 0x39, 0xcf, 0x3f, 0x29, 0x4f, 0x2d, 0xd2, 0xd4, ++ 0xdc, 0x5c, 0xc4, 0xd1, 0xa7, 0xf5, 0xbf, 0x4a, 0xc0, 0x9b, 0xb4, 0x2b, ++ 0x83, 0x7a, 0x63, 0x4d, 0x20, 0x40, 0x8b, 0x11, 0x5c, 0x53, 0xd4, 0x52, ++ 0x21, 0xe7, 0xe4, 0x1f, 0x01, 0xf6, 0xd1, 0x25, 0x28, 0xba, 0x51, 0x6f, ++ 0x51, 0x69, 0xf4, 0x41, 0x45, 0x75, 0x23, 0x25, 0x77, 0xef, 0xa8, 0x1c, ++ 0x19, 0x8a, 0x66, 0x8c, 0x61, 0x13, 0x37, 0x4f, 0xa3, 0xa1, 0x83, 0x17, ++ 0x35, 0x23, 0x2d, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x02, 0xb8, 0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, ++ 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, ++ 0x65, 0x6e, 0x64, 0x65, 0x64, 0x7e, 0x0a ++}; ++unsigned int hi_signed_len = 739; ++ ++unsigned char hj_signed[] = { ++ 0x68, 0x6a, 0x0a, 0x30, 0x82, 0x02, 0xb4, 0x06, 0x09, 0x2a, 0x86, 0x48, ++ 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0xa5, 0x30, 0x82, ++ 0x02, 0xa1, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, ++ 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09, ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x02, ++ 0x7e, 0x30, 0x82, 0x02, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x55, 0x30, 0x3d, ++ 0x31, 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x32, 0x47, ++ 0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64, ++ 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, ++ 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, ++ 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, ++ 0x79, 0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, ++ 0x3a, 0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x92, 0x03, 0x30, ++ 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, ++ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, ++ 0x01, 0x05, 0x00, 0x04, 0x82, 0x02, 0x00, 0xa0, 0x83, 0x3f, 0xac, 0x77, ++ 0x97, 0x74, 0x9b, 0x4b, 0x25, 0xa1, 0x64, 0x09, 0x8d, 0x53, 0xa6, 0x03, ++ 0xdf, 0x9a, 0x10, 0x52, 0xe5, 0x3f, 0xd4, 0x72, 0x75, 0x30, 0xd4, 0x6e, ++ 0x77, 0x32, 0x49, 0x84, 0xe2, 0xbe, 0xef, 0xe4, 0xf3, 0xac, 0xb0, 0x52, ++ 0x55, 0xbf, 0xa9, 0x57, 0x12, 0x08, 0x7d, 0xb0, 0x86, 0xc0, 0x9d, 0x01, ++ 0xc2, 0x1a, 0x4a, 0x2e, 0x3d, 0xd5, 0xc8, 0x56, 0xac, 0xd1, 0x83, 0x75, ++ 0x88, 0xd4, 0xcc, 0x9f, 0x0d, 0xcf, 0xd3, 0xa6, 0x91, 0xb6, 0xb6, 0xb1, ++ 0xd1, 0x24, 0x9c, 0xd0, 0x13, 0xe8, 0x6b, 0x15, 0x9c, 0x62, 0x33, 0x8d, ++ 0xe3, 0x67, 0x9b, 0xb1, 0x8a, 0x72, 0x38, 0xf7, 0x48, 0x32, 0x2f, 0x1e, ++ 0x45, 0xa8, 0xc4, 0xa5, 0xae, 0xb1, 0xfc, 0x35, 0x25, 0xb5, 0xf9, 0x7f, ++ 0x86, 0xef, 0xa2, 0x6d, 0x78, 0xcc, 0xfd, 0x0c, 0xca, 0x8a, 0xe1, 0xae, ++ 0xcd, 0x0f, 0x58, 0x69, 0xf1, 0x8b, 0xcc, 0x22, 0x35, 0x6d, 0x1f, 0xd5, ++ 0x27, 0x87, 0x39, 0x62, 0x3f, 0xb2, 0x17, 0x3d, 0x5e, 0xb1, 0x32, 0x7a, ++ 0xf1, 0x70, 0xce, 0xfa, 0xab, 0x1c, 0x92, 0xa8, 0xe1, 0xc4, 0xb2, 0x33, ++ 0x1a, 0x16, 0xf3, 0x60, 0x39, 0xdf, 0xb8, 0x85, 0xe7, 0x5d, 0x4d, 0xc2, ++ 0x8d, 0x55, 0x00, 0x49, 0x94, 0x04, 0x17, 0x88, 0x7c, 0xf4, 0xac, 0xa9, ++ 0xc5, 0x3a, 0x09, 0xc4, 0xc2, 0xcd, 0x3d, 0xc3, 0xfc, 0x4e, 0xf3, 0x70, ++ 0xa1, 0xc1, 0x54, 0x36, 0x1f, 0x38, 0x6d, 0x7a, 0x6b, 0x6a, 0xd3, 0x67, ++ 0x04, 0xd5, 0x53, 0xd4, 0xa5, 0xad, 0x63, 0x55, 0x0e, 0x06, 0x06, 0x3a, ++ 0x9a, 0xc5, 0xfe, 0x38, 0xc9, 0xb0, 0x69, 0x42, 0x90, 0x35, 0x1f, 0xe3, ++ 0x1c, 0x57, 0xea, 0xdb, 0x51, 0x35, 0x53, 0xd3, 0x94, 0xfe, 0x72, 0x33, ++ 0xd6, 0x8a, 0x46, 0x74, 0xf9, 0x6e, 0x94, 0x40, 0x2f, 0xba, 0xa2, 0xc4, ++ 0xe9, 0xc9, 0x8a, 0xf4, 0xda, 0xe2, 0xca, 0x3e, 0x98, 0x85, 0xa5, 0xd1, ++ 0x60, 0x94, 0xc8, 0xdf, 0x82, 0xee, 0x5c, 0x0d, 0x2a, 0xa9, 0x8e, 0x26, ++ 0x83, 0x3f, 0x02, 0xa2, 0xaf, 0xb8, 0x3b, 0x83, 0xf2, 0x44, 0x46, 0x41, ++ 0xd7, 0x5c, 0xa1, 0x42, 0x17, 0xa2, 0xd0, 0x50, 0x42, 0xef, 0x66, 0xda, ++ 0x35, 0x03, 0xd1, 0x8e, 0x77, 0x22, 0x7d, 0x4e, 0xf7, 0x4e, 0x04, 0xe3, ++ 0x0f, 0x98, 0x7d, 0xaa, 0x58, 0xba, 0xef, 0x9a, 0xd0, 0x88, 0x7c, 0x98, ++ 0xa0, 0xc2, 0xff, 0xa6, 0xb1, 0xec, 0xbe, 0x6e, 0xb0, 0x7e, 0xc6, 0xe5, ++ 0xaa, 0xcf, 0x10, 0x73, 0xc9, 0x13, 0x1a, 0x20, 0x12, 0x5c, 0xd2, 0x0e, ++ 0xe2, 0x60, 0x17, 0xdf, 0x4a, 0x44, 0x08, 0x22, 0xbc, 0xcd, 0x75, 0xbe, ++ 0xc3, 0x7a, 0x12, 0x90, 0x90, 0xc7, 0x94, 0x4c, 0x98, 0x45, 0x02, 0x5c, ++ 0x24, 0xae, 0x82, 0x2f, 0xcd, 0x30, 0xa6, 0xf5, 0x3f, 0xd3, 0xa7, 0xa6, ++ 0xe6, 0xea, 0x11, 0x4e, 0x45, 0xb7, 0xc0, 0xe6, 0x24, 0x8b, 0x76, 0xc5, ++ 0x5e, 0xc1, 0xd8, 0x07, 0x1e, 0x26, 0x94, 0x7a, 0x80, 0xc6, 0x3b, 0x1f, ++ 0x74, 0xe6, 0xae, 0x43, 0x2d, 0x11, 0xee, 0x96, 0x56, 0x6c, 0xff, 0xcb, ++ 0x3b, 0xde, 0xcc, 0xb3, 0x7b, 0x08, 0xf5, 0x3e, 0x6e, 0x51, 0x71, 0xe0, ++ 0x8a, 0xfa, 0xdd, 0x19, 0x39, 0xcf, 0x3f, 0x29, 0x4f, 0x2d, 0xd2, 0xd4, ++ 0xdc, 0x5c, 0xc4, 0xd1, 0xa7, 0xf5, 0xbf, 0x4a, 0xc0, 0x9b, 0xb4, 0x2b, ++ 0x83, 0x7a, 0x63, 0x4d, 0x20, 0x40, 0x8b, 0x11, 0x5c, 0x53, 0xd4, 0x52, ++ 0x21, 0xe7, 0xe4, 0x1f, 0x01, 0xf6, 0xd1, 0x25, 0x28, 0xba, 0x51, 0x6f, ++ 0x51, 0x69, 0xf4, 0x41, 0x45, 0x75, 0x23, 0x25, 0x77, 0xef, 0xa8, 0x1c, ++ 0x19, 0x8a, 0x66, 0x8c, 0x61, 0x13, 0x37, 0x4f, 0xa3, 0xa1, 0x83, 0x17, ++ 0x35, 0x23, 0x2d, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x02, 0xb8, 0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, ++ 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, ++ 0x65, 0x6e, 0x64, 0x65, 0x64, 0x7e, 0x0a ++}; ++unsigned int hj_signed_len = 739; ++ ++unsigned char hi_signed_sha256[] = { ++ 0x68, 0x69, 0x0a, 0x30, 0x82, 0x02, 0xb4, 0x06, 0x09, 0x2a, 0x86, 0x48, ++ 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0xa5, 0x30, 0x82, ++ 0x02, 0xa1, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, ++ 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x30, 0x0b, 0x06, 0x09, ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x02, ++ 0x7e, 0x30, 0x82, 0x02, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x55, 0x30, 0x3d, ++ 0x31, 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x32, 0x47, ++ 0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64, ++ 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, ++ 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, ++ 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, ++ 0x79, 0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, ++ 0x3a, 0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x92, 0x03, 0x30, ++ 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, ++ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, ++ 0x01, 0x05, 0x00, 0x04, 0x82, 0x02, 0x00, 0x96, 0x02, 0x7b, 0xa4, 0x07, ++ 0xa7, 0x39, 0x8d, 0xa6, 0x0b, 0xde, 0x33, 0xdd, 0xf8, 0xec, 0x24, 0x5d, ++ 0x06, 0x81, 0xe7, 0x3c, 0x2d, 0x0c, 0x53, 0xfb, 0x7e, 0x5a, 0xf3, 0xee, ++ 0xe5, 0x4c, 0x7c, 0xf7, 0xe7, 0x8f, 0x36, 0x62, 0x35, 0xb8, 0x99, 0xc3, ++ 0xeb, 0x85, 0x1d, 0x2e, 0x40, 0x6e, 0x2a, 0xb4, 0x3a, 0x76, 0x48, 0x4f, ++ 0x8b, 0x29, 0xd4, 0x9e, 0x5c, 0xd2, 0x41, 0x4d, 0xc1, 0x72, 0x0f, 0x97, ++ 0xe0, 0x7d, 0x88, 0xed, 0x1a, 0xb0, 0xde, 0x1b, 0x21, 0xa6, 0x0c, 0x19, ++ 0xd8, 0xb0, 0x12, 0x54, 0x7b, 0xd8, 0x19, 0x03, 0xbd, 0x77, 0x83, 0x23, ++ 0xeb, 0xeb, 0x68, 0x0a, 0x7b, 0x3a, 0x4d, 0x25, 0x44, 0xe1, 0x64, 0x8d, ++ 0x43, 0x5a, 0x1c, 0x9f, 0x74, 0x79, 0x31, 0x3f, 0xc7, 0x8e, 0xae, 0xe1, ++ 0xf9, 0x1e, 0x54, 0x12, 0x36, 0x85, 0xf2, 0x55, 0xba, 0x42, 0x60, 0x64, ++ 0x25, 0x9f, 0x73, 0x62, 0x42, 0xd2, 0x1c, 0x5e, 0x39, 0x4f, 0x7d, 0x91, ++ 0xb8, 0xf9, 0x59, 0x3c, 0x13, 0x6b, 0x84, 0x76, 0x6d, 0x8a, 0xc3, 0xcb, ++ 0x2d, 0x14, 0x27, 0x16, 0xdc, 0x20, 0x2c, 0xbc, 0x6b, 0xc9, 0xda, 0x9f, ++ 0xef, 0xe2, 0x2d, 0xc3, 0x83, 0xd8, 0xf9, 0x94, 0x18, 0xbc, 0xfe, 0x8f, ++ 0xa9, 0x44, 0xad, 0xff, 0x1b, 0xcb, 0x86, 0x30, 0x96, 0xa8, 0x3c, 0x7a, ++ 0x4b, 0x73, 0x1b, 0xa9, 0xc3, 0x3b, 0xaa, 0xd7, 0x44, 0xa8, 0x4d, 0xd6, ++ 0x92, 0xb6, 0x00, 0x04, 0x09, 0x05, 0x4a, 0x95, 0x02, 0x90, 0x19, 0x8c, ++ 0x9a, 0xa5, 0xee, 0x58, 0x24, 0xb0, 0xca, 0x5e, 0x6f, 0x73, 0xdb, 0xf5, ++ 0xa1, 0xf4, 0xf0, 0xa9, 0xeb, 0xe4, 0xdc, 0x55, 0x9f, 0x8f, 0x7a, 0xd0, ++ 0xf7, 0xb6, 0xaa, 0xa6, 0xb5, 0xb4, 0xab, 0xb8, 0x65, 0xad, 0x12, 0x32, ++ 0x1c, 0xe6, 0x99, 0x71, 0x93, 0xe8, 0xb4, 0x1e, 0x21, 0x27, 0x52, 0xea, ++ 0x8c, 0xc8, 0x79, 0x96, 0x2e, 0x48, 0x60, 0x57, 0x1c, 0x7d, 0x8c, 0x0d, ++ 0x07, 0xa7, 0x12, 0x83, 0x0a, 0x76, 0x6a, 0x64, 0xed, 0xbe, 0x8d, 0xaf, ++ 0xdf, 0x51, 0x05, 0xdd, 0xf2, 0xd3, 0xb8, 0x93, 0xa9, 0x13, 0xa5, 0x96, ++ 0xe8, 0xfa, 0x82, 0x02, 0x18, 0x71, 0x7a, 0x71, 0xbb, 0x39, 0x6f, 0x85, ++ 0xee, 0x16, 0x82, 0x27, 0x42, 0x9f, 0x83, 0xc8, 0xab, 0x6a, 0x3b, 0x99, ++ 0xba, 0x38, 0x92, 0x38, 0xae, 0x59, 0xfa, 0xaa, 0x40, 0x2b, 0x52, 0x95, ++ 0xca, 0x5e, 0xe1, 0x9b, 0x00, 0xbd, 0xb9, 0x63, 0x25, 0x8d, 0xc7, 0x22, ++ 0xaf, 0xe5, 0x67, 0x76, 0x91, 0xf4, 0xda, 0xc9, 0x7e, 0x9e, 0xec, 0x9b, ++ 0x1f, 0x7d, 0x3b, 0xfe, 0xa1, 0x20, 0x52, 0xac, 0xd0, 0xe5, 0xa6, 0xf1, ++ 0xfd, 0x4c, 0x08, 0x59, 0x7d, 0x50, 0xbb, 0x0c, 0xcf, 0xd8, 0xb6, 0x0f, ++ 0xc7, 0x19, 0xcb, 0x7a, 0x96, 0x6f, 0x0f, 0x6c, 0x71, 0x56, 0x72, 0xd1, ++ 0x06, 0x29, 0x0f, 0x08, 0xa2, 0x46, 0x3e, 0x58, 0x42, 0xc4, 0x8c, 0xe0, ++ 0x6e, 0xe9, 0x37, 0xd5, 0x2f, 0x74, 0x36, 0x1d, 0x14, 0xcb, 0x10, 0x0e, ++ 0x7d, 0x67, 0xbd, 0x38, 0x0e, 0xa4, 0x27, 0x1d, 0x3c, 0x78, 0x4d, 0x0d, ++ 0x15, 0x42, 0x70, 0x20, 0xe0, 0x1d, 0x83, 0x6c, 0x4d, 0xf1, 0x02, 0xa1, ++ 0x51, 0xc4, 0xc5, 0x5d, 0x69, 0x90, 0x58, 0x82, 0x94, 0x50, 0x36, 0x22, ++ 0xb3, 0xa4, 0x15, 0x77, 0xdc, 0x44, 0xb0, 0x50, 0xa2, 0x3f, 0xd0, 0x0e, ++ 0x1b, 0xfc, 0xf4, 0x5b, 0x3b, 0x7d, 0x63, 0x94, 0x22, 0xf3, 0x87, 0x0a, ++ 0x41, 0x8a, 0x27, 0x48, 0xcb, 0x6c, 0xfd, 0x70, 0x66, 0x5f, 0x11, 0x6f, ++ 0x74, 0x2c, 0x42, 0xaf, 0x74, 0x45, 0x3f, 0x0c, 0x03, 0xc8, 0x80, 0xe2, ++ 0x71, 0x08, 0x93, 0xbd, 0x4d, 0x18, 0x78, 0x1e, 0x8e, 0xb9, 0x3a, 0xd6, ++ 0x1a, 0xde, 0xf9, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x02, 0xb8, 0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, ++ 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, ++ 0x65, 0x6e, 0x64, 0x65, 0x64, 0x7e, 0x0a ++}; ++unsigned int hi_signed_sha256_len = 739; ++ ++unsigned char short_msg[] = { ++ 0x68, 0x69, 0x0a ++}; ++unsigned int short_msg_len = 3; ++ ++unsigned char unsigned_msg[] = { ++ 0x53, 0x65, 0x64, 0x20, 0x75, 0x74, 0x20, 0x70, 0x65, 0x72, 0x73, 0x70, ++ 0x69, 0x63, 0x69, 0x61, 0x74, 0x69, 0x73, 0x20, 0x75, 0x6e, 0x64, 0x65, ++ 0x20, 0x6f, 0x6d, 0x6e, 0x69, 0x73, 0x20, 0x69, 0x73, 0x74, 0x65, 0x20, ++ 0x6e, 0x61, 0x74, 0x75, 0x73, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20, ++ 0x73, 0x69, 0x74, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x74, ++ 0x65, 0x6d, 0x20, 0x61, 0x63, 0x63, 0x75, 0x73, 0x61, 0x6e, 0x74, 0x69, ++ 0x75, 0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x65, 0x6d, 0x71, 0x75, ++ 0x65, 0x20, 0x6c, 0x61, 0x75, 0x64, 0x61, 0x6e, 0x74, 0x69, 0x75, 0x6d, ++ 0x2c, 0x20, 0x74, 0x6f, 0x74, 0x61, 0x6d, 0x20, 0x72, 0x65, 0x6d, 0x20, ++ 0x61, 0x70, 0x65, 0x72, 0x69, 0x61, 0x6d, 0x2c, 0x20, 0x65, 0x61, 0x71, ++ 0x75, 0x65, 0x20, 0x69, 0x70, 0x73, 0x61, 0x20, 0x71, 0x75, 0x61, 0x65, ++ 0x20, 0x61, 0x62, 0x20, 0x69, 0x6c, 0x6c, 0x6f, 0x20, 0x69, 0x6e, 0x76, ++ 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x76, 0x65, 0x72, 0x69, 0x74, ++ 0x61, 0x74, 0x69, 0x73, 0x20, 0x65, 0x74, 0x20, 0x71, 0x75, 0x61, 0x73, ++ 0x69, 0x20, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x6f, ++ 0x20, 0x62, 0x65, 0x61, 0x74, 0x61, 0x65, 0x20, 0x76, 0x69, 0x74, 0x61, ++ 0x65, 0x20, 0x64, 0x69, 0x63, 0x74, 0x61, 0x20, 0x73, 0x75, 0x6e, 0x74, ++ 0x20, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x62, 0x6f, 0x2e, 0x20, ++ 0x4e, 0x65, 0x6d, 0x6f, 0x20, 0x65, 0x6e, 0x69, 0x6d, 0x20, 0x69, 0x70, ++ 0x73, 0x61, 0x6d, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x74, ++ 0x65, 0x6d, 0x20, 0x71, 0x75, 0x69, 0x61, 0x20, 0x76, 0x6f, 0x6c, 0x75, ++ 0x70, 0x74, 0x61, 0x73, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x73, 0x70, ++ 0x65, 0x72, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x20, 0x61, 0x75, 0x74, 0x20, ++ 0x6f, 0x64, 0x69, 0x74, 0x20, 0x61, 0x75, 0x74, 0x20, 0x66, 0x75, 0x67, ++ 0x69, 0x74, 0x2c, 0x20, 0x73, 0x65, 0x64, 0x20, 0x71, 0x75, 0x69, 0x61, ++ 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x75, 0x6e, 0x74, 0x75, ++ 0x72, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x69, 0x20, 0x64, 0x6f, 0x6c, 0x6f, ++ 0x72, 0x65, 0x73, 0x20, 0x65, 0x6f, 0x73, 0x20, 0x71, 0x75, 0x69, 0x20, ++ 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x20, 0x76, 0x6f, 0x6c, 0x75, ++ 0x70, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x20, 0x73, 0x65, 0x71, 0x75, 0x69, ++ 0x20, 0x6e, 0x65, 0x73, 0x63, 0x69, 0x75, 0x6e, 0x74, 0x2e, 0x20, 0x4e, ++ 0x65, 0x71, 0x75, 0x65, 0x20, 0x70, 0x6f, 0x72, 0x72, 0x6f, 0x20, 0x71, ++ 0x75, 0x69, 0x73, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x65, 0x73, 0x74, 0x2c, ++ 0x20, 0x71, 0x75, 0x69, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x65, 0x6d, ++ 0x20, 0x69, 0x70, 0x73, 0x75, 0x6d, 0x20, 0x71, 0x75, 0x69, 0x61, 0x20, ++ 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6d, ++ 0x65, 0x74, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x63, 0x74, 0x65, ++ 0x74, 0x75, 0x72, 0x2c, 0x20, 0x61, 0x64, 0x69, 0x70, 0x69, 0x73, 0x63, ++ 0x69, 0x20, 0x76, 0x65, 0x6c, 0x69, 0x74, 0x2c, 0x20, 0x73, 0x65, 0x64, ++ 0x20, 0x71, 0x75, 0x69, 0x61, 0x20, 0x6e, 0x6f, 0x6e, 0x20, 0x6e, 0x75, ++ 0x6d, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x65, 0x69, 0x75, 0x73, 0x20, 0x6d, ++ 0x6f, 0x64, 0x69, 0x20, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x20, ++ 0x69, 0x6e, 0x63, 0x69, 0x64, 0x75, 0x6e, 0x74, 0x20, 0x75, 0x74, 0x20, ++ 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x65, 0x20, 0x65, 0x74, 0x20, 0x64, 0x6f, ++ 0x6c, 0x6f, 0x72, 0x65, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x61, 0x6d, 0x20, ++ 0x61, 0x6c, 0x69, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x71, 0x75, 0x61, 0x65, ++ 0x72, 0x61, 0x74, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x74, ++ 0x65, 0x6d, 0x2e, 0x20, 0x55, 0x74, 0x20, 0x65, 0x6e, 0x69, 0x6d, 0x20, ++ 0x61, 0x64, 0x20, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x61, 0x20, 0x76, 0x65, ++ 0x6e, 0x69, 0x61, 0x6d, 0x2c, 0x20, 0x71, 0x75, 0x69, 0x73, 0x20, 0x6e, ++ 0x6f, 0x73, 0x74, 0x72, 0x75, 0x6d, 0x20, 0x65, 0x78, 0x65, 0x72, 0x63, ++ 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x6d, 0x20, 0x75, 0x6c, ++ 0x6c, 0x61, 0x6d, 0x20, 0x63, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x69, 0x73, ++ 0x20, 0x73, 0x75, 0x73, 0x63, 0x69, 0x70, 0x69, 0x74, 0x20, 0x6c, 0x61, ++ 0x62, 0x6f, 0x72, 0x69, 0x6f, 0x73, 0x61, 0x6d, 0x2c, 0x20, 0x6e, 0x69, ++ 0x73, 0x69, 0x20, 0x75, 0x74, 0x20, 0x61, 0x6c, 0x69, 0x71, 0x75, 0x69, ++ 0x64, 0x20, 0x65, 0x78, 0x20, 0x65, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x6d, ++ 0x6f, 0x64, 0x69, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x61, ++ 0x74, 0x75, 0x72, 0x3f, 0x20, 0x51, 0x75, 0x69, 0x73, 0x20, 0x61, 0x75, ++ 0x74, 0x65, 0x6d, 0x20, 0x76, 0x65, 0x6c, 0x20, 0x65, 0x75, 0x6d, 0x20, ++ 0x69, 0x75, 0x72, 0x65, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x68, 0x65, ++ 0x6e, 0x64, 0x65, 0x72, 0x69, 0x74, 0x20, 0x71, 0x75, 0x69, 0x20, 0x69, ++ 0x6e, 0x20, 0x65, 0x61, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, ++ 0x74, 0x65, 0x20, 0x76, 0x65, 0x6c, 0x69, 0x74, 0x20, 0x65, 0x73, 0x73, ++ 0x65, 0x20, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x6e, 0x69, 0x68, 0x69, 0x6c, ++ 0x20, 0x6d, 0x6f, 0x6c, 0x65, 0x73, 0x74, 0x69, 0x61, 0x65, 0x20, 0x63, ++ 0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x61, 0x74, 0x75, 0x72, 0x2c, 0x20, ++ 0x76, 0x65, 0x6c, 0x20, 0x69, 0x6c, 0x6c, 0x75, 0x6d, 0x20, 0x71, 0x75, ++ 0x69, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x65, 0x75, ++ 0x6d, 0x20, 0x66, 0x75, 0x67, 0x69, 0x61, 0x74, 0x20, 0x71, 0x75, 0x6f, ++ 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x73, 0x20, 0x6e, 0x75, ++ 0x6c, 0x6c, 0x61, 0x20, 0x70, 0x61, 0x72, 0x69, 0x61, 0x74, 0x75, 0x72, ++ 0x3f, 0x0a ++}; ++unsigned int unsigned_msg_len = 866; ++ ++unsigned char certificate2_der[] = { ++ 0x30, 0x82, 0x05, 0x52, 0x30, 0x82, 0x03, 0x3a, 0xa0, 0x03, 0x02, 0x01, ++ 0x02, 0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, ++ 0x3a, 0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x91, 0xff, 0x30, ++ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, ++ 0x05, 0x00, 0x30, 0x3a, 0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, ++ 0x03, 0x0c, 0x2f, 0x47, 0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, ++ 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, ++ 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, ++ 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, ++ 0x74, 0x79, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x30, 0x30, 0x37, 0x32, 0x38, ++ 0x31, 0x33, 0x32, 0x34, 0x32, 0x39, 0x5a, 0x18, 0x0f, 0x32, 0x31, 0x32, ++ 0x30, 0x30, 0x37, 0x30, 0x34, 0x31, 0x33, 0x32, 0x34, 0x32, 0x39, 0x5a, ++ 0x30, 0x2b, 0x31, 0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, ++ 0x20, 0x47, 0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, 0x43, 0x65, ++ 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x53, 0x69, ++ 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x4b, 0x65, 0x79, 0x30, 0x82, 0x02, ++ 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, ++ 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, ++ 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xb0, 0x2f, 0x50, 0x01, 0x9c, 0x0e, ++ 0xd6, 0x8c, 0x07, 0xca, 0xc1, 0xcf, 0xbc, 0x03, 0xdd, 0xd3, 0xfa, 0xe3, ++ 0x4f, 0x71, 0xc1, 0x30, 0xaa, 0x09, 0x96, 0xe4, 0xd0, 0x6c, 0x42, 0x93, ++ 0xdb, 0x35, 0xf6, 0x7e, 0x1b, 0x67, 0xc0, 0xc2, 0x2d, 0x5b, 0xec, 0xca, ++ 0x35, 0x06, 0x32, 0x6c, 0x7b, 0x2c, 0xd3, 0x71, 0x2b, 0xe9, 0x7a, 0x19, ++ 0xd1, 0xf2, 0xa0, 0x7f, 0xd7, 0x4d, 0x6e, 0x28, 0xbb, 0xae, 0x49, 0x4a, ++ 0xbc, 0xea, 0x47, 0x67, 0xb8, 0x36, 0xa6, 0xf5, 0x0d, 0x0e, 0x20, 0x14, ++ 0x0c, 0x66, 0x67, 0x28, 0xb5, 0x97, 0x8b, 0x1f, 0x5e, 0x32, 0x06, 0x29, ++ 0x9c, 0x99, 0x92, 0x0f, 0x73, 0xac, 0xfd, 0xd2, 0x1d, 0xf2, 0xa8, 0x55, ++ 0x9d, 0x1b, 0xd8, 0x3d, 0xb0, 0x76, 0x9a, 0xb6, 0x6c, 0x9f, 0x62, 0x37, ++ 0x2f, 0xc0, 0xef, 0x44, 0xb3, 0x0d, 0x4a, 0x3e, 0x4f, 0x7d, 0xbd, 0xdb, ++ 0xd8, 0x75, 0x5f, 0x68, 0xe3, 0xf0, 0xec, 0x82, 0x66, 0x7c, 0x31, 0x70, ++ 0xa9, 0xa1, 0x6f, 0x38, 0x9f, 0xdf, 0xf5, 0xf0, 0x7d, 0x23, 0x9d, 0x34, ++ 0xa5, 0x85, 0xd3, 0xdf, 0x68, 0x41, 0xfc, 0x4f, 0x89, 0x45, 0x3c, 0x24, ++ 0x81, 0xa6, 0xf2, 0x3c, 0x02, 0x26, 0x09, 0x48, 0xdd, 0xfe, 0x4b, 0xb6, ++ 0x66, 0xbf, 0x8f, 0xe5, 0x5f, 0xf0, 0x5d, 0x8a, 0x61, 0x2e, 0x5f, 0x9f, ++ 0x80, 0xd9, 0xd5, 0xe6, 0x41, 0xd8, 0x10, 0x5e, 0x7a, 0xc6, 0xdb, 0x89, ++ 0xc7, 0xca, 0x6c, 0x5b, 0xb1, 0x4e, 0x7d, 0x0c, 0x03, 0xfd, 0x50, 0xca, ++ 0xbf, 0xbb, 0xe2, 0x69, 0x4b, 0x4e, 0xc2, 0x3d, 0x75, 0xfa, 0xd1, 0xcc, ++ 0xd6, 0xf9, 0x39, 0xb9, 0xdc, 0x53, 0xad, 0x62, 0xfb, 0x1b, 0x94, 0x26, ++ 0x7f, 0x21, 0x54, 0x5c, 0xb7, 0xdc, 0xe7, 0x96, 0x8c, 0xce, 0x75, 0xe0, ++ 0x17, 0x01, 0x3a, 0x3c, 0x77, 0x6e, 0xa4, 0x8b, 0x7a, 0x83, 0x28, 0x7a, ++ 0xf7, 0xb0, 0x5f, 0xfc, 0x7f, 0x2d, 0x2e, 0xec, 0xf5, 0xeb, 0x9c, 0x63, ++ 0x74, 0xd0, 0xe5, 0xdc, 0x19, 0xe4, 0x71, 0xc5, 0x4a, 0x8a, 0x54, 0xa4, ++ 0xe0, 0x7d, 0x4e, 0xbf, 0x53, 0x30, 0xaf, 0xd0, 0xeb, 0x96, 0xc3, 0xbb, ++ 0x65, 0xf7, 0x67, 0xf5, 0xae, 0xd3, 0x96, 0xf2, 0x63, 0xc8, 0x69, 0xf7, ++ 0x47, 0xcb, 0x27, 0x79, 0xe1, 0xff, 0x2f, 0x68, 0xdf, 0x1e, 0xb3, 0xb8, ++ 0x0c, 0xc5, 0x58, 0x73, 0xcc, 0xfe, 0x8c, 0xda, 0x4e, 0x3b, 0x01, 0x04, ++ 0xcd, 0xcb, 0xb8, 0x3e, 0x06, 0xfd, 0x4c, 0x0a, 0x9f, 0x5e, 0x76, 0x8c, ++ 0x0c, 0x83, 0x75, 0x09, 0x08, 0xb2, 0xdb, 0xf4, 0x49, 0x4e, 0xa0, 0xf2, ++ 0x0c, 0x7b, 0x87, 0x38, 0x9e, 0x22, 0x67, 0xbd, 0xd1, 0x97, 0x57, 0x24, ++ 0xf1, 0x46, 0x07, 0xf9, 0xd2, 0x1b, 0xec, 0x25, 0x5e, 0x67, 0xd9, 0x66, ++ 0x23, 0x1b, 0xd3, 0xe4, 0xaa, 0xec, 0x88, 0xf0, 0x7e, 0x15, 0x83, 0x51, ++ 0x31, 0x67, 0x51, 0x76, 0x5f, 0x55, 0xd7, 0x36, 0xdf, 0x4a, 0x84, 0x0b, ++ 0x6f, 0x5c, 0xbb, 0x5b, 0x8f, 0x37, 0x23, 0x7f, 0xf8, 0x17, 0x84, 0xa2, ++ 0x70, 0x20, 0x07, 0x0c, 0x90, 0x3a, 0x04, 0xfd, 0xf0, 0x08, 0x4a, 0xb1, ++ 0x16, 0x0f, 0xe6, 0xf6, 0x40, 0x51, 0x83, 0xd2, 0x87, 0x40, 0x9c, 0x1c, ++ 0x9f, 0x13, 0x38, 0x17, 0xd3, 0x34, 0x58, 0xad, 0x05, 0x71, 0xa0, 0x73, ++ 0xca, 0x40, 0xa6, 0xa4, 0x81, 0x02, 0xee, 0xa8, 0x72, 0x41, 0xa1, 0x41, ++ 0x18, 0x64, 0x8a, 0x86, 0x8a, 0x5d, 0xe6, 0x4f, 0x0a, 0xc5, 0x95, 0x98, ++ 0xf9, 0x78, 0xfe, 0x19, 0x0d, 0xc9, 0xb3, 0x89, 0xc1, 0x2b, 0x09, 0xbe, ++ 0xf1, 0xd2, 0x04, 0x5d, 0xcc, 0x28, 0xf5, 0x4b, 0xd2, 0x20, 0x4f, 0xc5, ++ 0x41, 0x9d, 0x8c, 0x85, 0xd8, 0xb0, 0x68, 0x5e, 0xc1, 0x0c, 0xb7, 0x24, ++ 0x4d, 0x67, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x5d, 0x30, 0x5b, 0x30, ++ 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, ++ 0x00, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, ++ 0x07, 0x80, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, ++ 0x14, 0xac, 0xf5, 0x47, 0x17, 0xd9, 0x7d, 0xc1, 0xb1, 0xc4, 0x41, 0xe1, ++ 0x41, 0x60, 0xcb, 0x37, 0x11, 0x60, 0x28, 0x78, 0x5f, 0x30, 0x1f, 0x06, ++ 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x21, 0x94, ++ 0xfb, 0xf9, 0xb2, 0x43, 0xe9, 0x33, 0xd7, 0x50, 0x7d, 0xc7, 0x37, 0xdb, ++ 0xd5, 0x82, 0x5a, 0x4e, 0xbe, 0x1b, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, ++ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, ++ 0x01, 0x00, 0x96, 0x70, 0x65, 0x26, 0x42, 0xf8, 0xdc, 0x69, 0xde, 0xcf, ++ 0x41, 0x3a, 0x2e, 0x7f, 0x5b, 0xf1, 0xf9, 0x3b, 0x9b, 0xd2, 0x4e, 0x64, ++ 0x48, 0x81, 0xe4, 0x5d, 0x1e, 0x22, 0xce, 0x68, 0x63, 0x62, 0xe5, 0x1b, ++ 0x9b, 0xf2, 0xc7, 0x12, 0xda, 0x1e, 0x9b, 0x90, 0x84, 0x79, 0x48, 0x12, ++ 0xe6, 0x21, 0x6f, 0x2f, 0x7e, 0x18, 0x77, 0xdb, 0x8c, 0xc4, 0xd1, 0x0d, ++ 0x91, 0xbf, 0x39, 0x22, 0x0f, 0x64, 0xcf, 0x25, 0x2e, 0x8c, 0x1f, 0x91, ++ 0x81, 0xb5, 0xe9, 0x6c, 0x02, 0x3a, 0xf8, 0x07, 0xa2, 0x6f, 0x46, 0x5d, ++ 0x7b, 0xfd, 0x43, 0xff, 0x41, 0x0f, 0xe2, 0x57, 0x1c, 0xbd, 0x48, 0x60, ++ 0x53, 0x11, 0x48, 0x87, 0x88, 0x9d, 0x13, 0x82, 0x40, 0x68, 0x44, 0x2c, ++ 0xc6, 0xc8, 0x95, 0x27, 0x4f, 0xb6, 0xb9, 0x4a, 0x22, 0x0a, 0xfd, 0xe4, ++ 0x46, 0x8f, 0x35, 0x12, 0x98, 0x5a, 0x34, 0x6f, 0x2b, 0x57, 0x62, 0xa1, ++ 0x4d, 0x8d, 0x79, 0x37, 0xe4, 0x6b, 0x8a, 0x32, 0x5b, 0xcb, 0xef, 0x79, ++ 0x11, 0xed, 0xa7, 0xf8, 0x7a, 0x1c, 0xbd, 0x86, 0xdc, 0x0e, 0x2e, 0xfd, ++ 0xd3, 0x51, 0xbb, 0x73, 0xad, 0x00, 0xa0, 0x1b, 0xf9, 0x1d, 0xd1, 0x4a, ++ 0xe4, 0xd4, 0x02, 0x63, 0x2b, 0x39, 0x5f, 0x18, 0x08, 0x2f, 0x42, 0xb7, ++ 0x23, 0x4b, 0x48, 0x46, 0x1f, 0x63, 0x87, 0xae, 0x6d, 0xd5, 0xdb, 0x60, ++ 0xf8, 0x5f, 0xd3, 0x13, 0xec, 0xca, 0xdd, 0x60, 0x60, 0x79, 0x52, 0x70, ++ 0x47, 0xae, 0x1d, 0x38, 0x78, 0x71, 0xcf, 0xb3, 0x04, 0x03, 0xbe, 0xba, ++ 0x81, 0xba, 0x74, 0xb1, 0x30, 0x35, 0xdc, 0xea, 0x21, 0x4a, 0x9b, 0x70, ++ 0xfb, 0xd6, 0x60, 0x59, 0x78, 0x0c, 0x4d, 0x39, 0x19, 0x1d, 0xe5, 0x75, ++ 0xba, 0x07, 0xf4, 0x22, 0x37, 0x64, 0xb7, 0xf2, 0x9a, 0xc9, 0x11, 0x2d, ++ 0x8e, 0x58, 0xa6, 0xcf, 0x83, 0xf1, 0xcb, 0x6c, 0x7f, 0x02, 0xbd, 0xda, ++ 0x03, 0x92, 0xa9, 0x45, 0x24, 0x56, 0xc5, 0xbd, 0x41, 0xd1, 0x20, 0x86, ++ 0xc0, 0xb6, 0xb7, 0xe8, 0xa7, 0xb2, 0x46, 0xf7, 0x8e, 0xa9, 0x38, 0x0e, ++ 0x23, 0x77, 0x3c, 0x0d, 0x66, 0x83, 0x6a, 0x1a, 0x6b, 0x7f, 0x54, 0x11, ++ 0x58, 0x0d, 0x4a, 0xb5, 0x74, 0x60, 0xca, 0xed, 0xff, 0x91, 0x47, 0xd9, ++ 0x29, 0xe0, 0xaa, 0x8c, 0xa8, 0x8f, 0x10, 0x4c, 0x15, 0x7d, 0xce, 0x95, ++ 0xf9, 0x87, 0x1e, 0x18, 0x38, 0x18, 0xfc, 0xcc, 0xaf, 0x91, 0x17, 0x3f, ++ 0xfa, 0xf0, 0x8a, 0x09, 0x6f, 0xba, 0x4e, 0x53, 0xf7, 0xfa, 0x4f, 0x20, ++ 0xa3, 0xf4, 0x4a, 0x5a, 0xde, 0x17, 0x1c, 0x29, 0x6a, 0x6f, 0x03, 0x48, ++ 0xdf, 0xad, 0x4f, 0xe4, 0xbc, 0x71, 0xc4, 0x72, 0x32, 0x11, 0x84, 0xac, ++ 0x09, 0xd2, 0x18, 0x44, 0x35, 0xf1, 0xcd, 0xaf, 0xa8, 0x98, 0xe0, 0x8b, ++ 0xec, 0xa0, 0x83, 0x37, 0xc3, 0x35, 0x85, 0xd6, 0xd8, 0x1b, 0xe0, 0x75, ++ 0xdc, 0xfd, 0xde, 0xc9, 0xeb, 0xd5, 0x18, 0x0f, 0xd3, 0x4c, 0x2f, 0x71, ++ 0xdc, 0x48, 0xe3, 0x14, 0xeb, 0xda, 0x00, 0x24, 0x24, 0x9e, 0xa3, 0x8e, ++ 0x3e, 0x08, 0x6f, 0x22, 0x24, 0xd6, 0xc4, 0x85, 0x8f, 0x68, 0x00, 0x4a, ++ 0x82, 0x4c, 0x33, 0x6e, 0xa5, 0x35, 0x7b, 0xeb, 0x4b, 0xdc, 0xa0, 0xa6, ++ 0x65, 0x6f, 0x5a, 0x7a, 0xdf, 0x8a, 0x01, 0x52, 0xa1, 0x6c, 0xff, 0x59, ++ 0x22, 0x7f, 0xe1, 0x96, 0x1b, 0x19, 0xb8, 0xf9, 0x5d, 0x44, 0x9f, 0x91, ++ 0x03, 0x3c, 0x3d, 0xa1, 0x2a, 0xb6, 0x5a, 0x51, 0xa0, 0xce, 0x4a, 0x88, ++ 0x22, 0x72, 0x9c, 0xdc, 0xc0, 0x47, 0x76, 0x35, 0x84, 0x75, 0x9b, 0x87, ++ 0x5c, 0xd3, 0xcf, 0xe7, 0xdd, 0xa3, 0x57, 0x14, 0xdf, 0x00, 0xfd, 0x19, ++ 0x2a, 0x7d, 0x89, 0x27, 0x1c, 0x78, 0x97, 0x04, 0x58, 0x48 ++}; ++unsigned int certificate2_der_len = 1366; ++ ++unsigned char hi_signed_2nd[] = { ++ 0x68, 0x69, 0x0a, 0x30, 0x82, 0x02, 0xb1, 0x06, 0x09, 0x2a, 0x86, 0x48, ++ 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0xa2, 0x30, 0x82, ++ 0x02, 0x9e, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, ++ 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09, ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x02, ++ 0x7b, 0x30, 0x82, 0x02, 0x77, 0x02, 0x01, 0x01, 0x30, 0x52, 0x30, 0x3a, ++ 0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2f, 0x47, ++ 0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, 0x43, 0x65, 0x72, 0x74, ++ 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, ++ 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, ++ 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x02, 0x14, ++ 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, 0x3a, 0x91, 0x07, ++ 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x91, 0xff, 0x30, 0x0b, 0x06, 0x09, ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0d, 0x06, ++ 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, ++ 0x04, 0x82, 0x02, 0x00, 0x0e, 0xc2, 0x30, 0x38, 0x81, 0x23, 0x68, 0x90, ++ 0xae, 0x5f, 0xce, 0xf7, 0x27, 0xb1, 0x8c, 0x2e, 0x12, 0x10, 0xc6, 0x99, ++ 0xdc, 0x4d, 0x4b, 0x79, 0xda, 0xe4, 0x32, 0x10, 0x46, 0x1c, 0x16, 0x07, ++ 0x87, 0x66, 0x55, 0xff, 0x64, 0x1c, 0x61, 0x25, 0xd5, 0xb9, 0xe1, 0xfe, ++ 0xea, 0x5a, 0xcd, 0x56, 0xa5, 0xc3, 0xbe, 0xb1, 0x61, 0xc7, 0x6f, 0x5f, ++ 0x69, 0x20, 0x64, 0x50, 0x6f, 0x12, 0x78, 0xb6, 0x0c, 0x72, 0x44, 0x4f, ++ 0x60, 0x0f, 0x9f, 0xa2, 0x83, 0x3b, 0xc2, 0x83, 0xd5, 0x14, 0x1f, 0x6f, ++ 0x3e, 0xb2, 0x47, 0xb5, 0x58, 0xc5, 0xa7, 0xb4, 0x82, 0x53, 0x2e, 0x53, ++ 0x95, 0x4e, 0x3d, 0xe4, 0x62, 0xe8, 0xa1, 0xaf, 0xae, 0xbf, 0xa9, 0xd2, ++ 0x22, 0x07, 0xbe, 0x71, 0x37, 0x2c, 0x5a, 0xa7, 0x6c, 0xaf, 0x14, 0xc0, ++ 0x6c, 0x2f, 0xbf, 0x4f, 0x15, 0xc2, 0x0f, 0x8b, 0xdc, 0x68, 0x45, 0xdf, ++ 0xf3, 0xa5, 0x7f, 0x11, 0x6a, 0x54, 0xcd, 0x67, 0xb9, 0x2e, 0x7d, 0x05, ++ 0xe3, 0x1c, 0x1d, 0xcc, 0x77, 0x8e, 0x97, 0xb1, 0xa0, 0x11, 0x09, 0x3d, ++ 0x90, 0x54, 0xfc, 0x7e, 0xbb, 0xbb, 0x21, 0x23, 0x03, 0x44, 0xbf, 0x7d, ++ 0x2c, 0xc9, 0x15, 0x42, 0xe5, 0xa0, 0x3b, 0xa2, 0xd1, 0x5b, 0x73, 0x81, ++ 0xff, 0xfa, 0x90, 0xfc, 0x27, 0x7b, 0x2f, 0x86, 0x9c, 0x1d, 0x14, 0x36, ++ 0x94, 0xa2, 0x6e, 0xe8, 0x9d, 0xa0, 0x5f, 0xfc, 0x5a, 0x0d, 0xa4, 0xd5, ++ 0x2f, 0x8d, 0xd6, 0x00, 0xfa, 0x93, 0x5b, 0x09, 0x7f, 0x42, 0x78, 0xcc, ++ 0x8c, 0x49, 0xda, 0xd9, 0xf6, 0x43, 0xe7, 0xe1, 0x3c, 0xa2, 0xe2, 0x70, ++ 0xe2, 0x6a, 0x99, 0xc5, 0xd6, 0xa2, 0xe3, 0x0b, 0xd4, 0x09, 0xac, 0x94, ++ 0xaf, 0xb7, 0xf0, 0xb3, 0x0c, 0x1e, 0xf5, 0x16, 0x4f, 0x53, 0x9a, 0xe3, ++ 0xcc, 0xe2, 0x0c, 0x4a, 0xb9, 0xe6, 0x06, 0xbb, 0xf7, 0x41, 0x43, 0x20, ++ 0x04, 0xee, 0x99, 0x2f, 0xd8, 0x9f, 0xda, 0x3f, 0xfd, 0x49, 0xb8, 0xc2, ++ 0xbd, 0xd9, 0xc5, 0x72, 0xfd, 0xe3, 0xce, 0x1c, 0xbc, 0xe4, 0x39, 0xac, ++ 0x2a, 0x99, 0xe9, 0xb4, 0x3e, 0x74, 0x10, 0xeb, 0xd5, 0x14, 0xcc, 0xdb, ++ 0xf1, 0x04, 0x63, 0x36, 0xfb, 0x1f, 0x2b, 0xe2, 0x73, 0xd4, 0xd8, 0x49, ++ 0x31, 0xa8, 0x55, 0xcc, 0xa7, 0x76, 0x36, 0x6e, 0x18, 0xdc, 0xb9, 0xb0, ++ 0x29, 0x99, 0xcf, 0x49, 0xbf, 0xf9, 0xdb, 0x7f, 0x24, 0x42, 0x02, 0xcb, ++ 0xc1, 0xaa, 0xcb, 0xba, 0x18, 0x85, 0x86, 0xc7, 0xf4, 0x1c, 0x62, 0x76, ++ 0xbc, 0x73, 0xfb, 0xe4, 0x15, 0xb8, 0xdd, 0x5d, 0xa6, 0x68, 0x39, 0xa5, ++ 0x3d, 0x33, 0xaf, 0xd5, 0x92, 0x4d, 0x48, 0xdb, 0x22, 0xc0, 0xdc, 0x49, ++ 0x5f, 0x7b, 0xa8, 0xd2, 0x62, 0x2d, 0xa7, 0x39, 0x93, 0x48, 0xe7, 0x6b, ++ 0x23, 0xba, 0xd4, 0xe0, 0xc1, 0x29, 0x55, 0xc4, 0x34, 0xe3, 0xac, 0x25, ++ 0xa7, 0x15, 0xad, 0xab, 0xb3, 0xb7, 0x25, 0xca, 0x37, 0x88, 0x40, 0x2e, ++ 0x47, 0x6e, 0x92, 0x20, 0x09, 0x2e, 0x5a, 0xec, 0xf2, 0xfb, 0xb3, 0xa0, ++ 0x16, 0xb6, 0x93, 0xf2, 0xf5, 0x8b, 0xfe, 0xaf, 0x25, 0xee, 0x2e, 0x98, ++ 0x6c, 0x0a, 0xfe, 0xae, 0x0b, 0x57, 0xf5, 0x9f, 0x3c, 0x80, 0xe9, 0x8b, ++ 0xaf, 0x92, 0x8a, 0xad, 0xe7, 0xa0, 0xe4, 0xe6, 0x0a, 0xa0, 0xc7, 0x83, ++ 0xb5, 0x48, 0x58, 0x5f, 0x55, 0x9e, 0x9b, 0x27, 0xcd, 0x31, 0x1f, 0x3e, ++ 0x50, 0x5a, 0x91, 0xad, 0x21, 0x1b, 0x97, 0x5b, 0xe8, 0xfa, 0x29, 0x8a, ++ 0xa4, 0x17, 0xe8, 0xab, 0x87, 0x02, 0xd6, 0x18, 0x8c, 0x9f, 0x65, 0xb7, ++ 0x2a, 0xfa, 0xde, 0x5f, 0x77, 0x30, 0x6c, 0x04, 0x22, 0xe6, 0x58, 0x26, ++ 0x14, 0x0d, 0x9c, 0x41, 0x0a, 0x82, 0x77, 0xdb, 0x40, 0xa1, 0x58, 0xac, ++ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xb5, ++ 0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, ++ 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, ++ 0x65, 0x64, 0x7e, 0x0a ++}; ++unsigned int hi_signed_2nd_len = 736; ++ ++unsigned char hi_double[] = { ++ 0x68, 0x69, 0x0a, 0x30, 0x82, 0x05, 0x2f, 0x06, 0x09, 0x2a, 0x86, 0x48, ++ 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x05, 0x20, 0x30, 0x82, ++ 0x05, 0x1c, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, ++ 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09, ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x04, ++ 0xf9, 0x30, 0x82, 0x02, 0x77, 0x02, 0x01, 0x01, 0x30, 0x52, 0x30, 0x3a, ++ 0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2f, 0x47, ++ 0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, 0x43, 0x65, 0x72, 0x74, ++ 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, ++ 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, ++ 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x02, 0x14, ++ 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, 0x3a, 0x91, 0x07, ++ 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x91, 0xff, 0x30, 0x0b, 0x06, 0x09, ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0d, 0x06, ++ 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, ++ 0x04, 0x82, 0x02, 0x00, 0x0e, 0xc2, 0x30, 0x38, 0x81, 0x23, 0x68, 0x90, ++ 0xae, 0x5f, 0xce, 0xf7, 0x27, 0xb1, 0x8c, 0x2e, 0x12, 0x10, 0xc6, 0x99, ++ 0xdc, 0x4d, 0x4b, 0x79, 0xda, 0xe4, 0x32, 0x10, 0x46, 0x1c, 0x16, 0x07, ++ 0x87, 0x66, 0x55, 0xff, 0x64, 0x1c, 0x61, 0x25, 0xd5, 0xb9, 0xe1, 0xfe, ++ 0xea, 0x5a, 0xcd, 0x56, 0xa5, 0xc3, 0xbe, 0xb1, 0x61, 0xc7, 0x6f, 0x5f, ++ 0x69, 0x20, 0x64, 0x50, 0x6f, 0x12, 0x78, 0xb6, 0x0c, 0x72, 0x44, 0x4f, ++ 0x60, 0x0f, 0x9f, 0xa2, 0x83, 0x3b, 0xc2, 0x83, 0xd5, 0x14, 0x1f, 0x6f, ++ 0x3e, 0xb2, 0x47, 0xb5, 0x58, 0xc5, 0xa7, 0xb4, 0x82, 0x53, 0x2e, 0x53, ++ 0x95, 0x4e, 0x3d, 0xe4, 0x62, 0xe8, 0xa1, 0xaf, 0xae, 0xbf, 0xa9, 0xd2, ++ 0x22, 0x07, 0xbe, 0x71, 0x37, 0x2c, 0x5a, 0xa7, 0x6c, 0xaf, 0x14, 0xc0, ++ 0x6c, 0x2f, 0xbf, 0x4f, 0x15, 0xc2, 0x0f, 0x8b, 0xdc, 0x68, 0x45, 0xdf, ++ 0xf3, 0xa5, 0x7f, 0x11, 0x6a, 0x54, 0xcd, 0x67, 0xb9, 0x2e, 0x7d, 0x05, ++ 0xe3, 0x1c, 0x1d, 0xcc, 0x77, 0x8e, 0x97, 0xb1, 0xa0, 0x11, 0x09, 0x3d, ++ 0x90, 0x54, 0xfc, 0x7e, 0xbb, 0xbb, 0x21, 0x23, 0x03, 0x44, 0xbf, 0x7d, ++ 0x2c, 0xc9, 0x15, 0x42, 0xe5, 0xa0, 0x3b, 0xa2, 0xd1, 0x5b, 0x73, 0x81, ++ 0xff, 0xfa, 0x90, 0xfc, 0x27, 0x7b, 0x2f, 0x86, 0x9c, 0x1d, 0x14, 0x36, ++ 0x94, 0xa2, 0x6e, 0xe8, 0x9d, 0xa0, 0x5f, 0xfc, 0x5a, 0x0d, 0xa4, 0xd5, ++ 0x2f, 0x8d, 0xd6, 0x00, 0xfa, 0x93, 0x5b, 0x09, 0x7f, 0x42, 0x78, 0xcc, ++ 0x8c, 0x49, 0xda, 0xd9, 0xf6, 0x43, 0xe7, 0xe1, 0x3c, 0xa2, 0xe2, 0x70, ++ 0xe2, 0x6a, 0x99, 0xc5, 0xd6, 0xa2, 0xe3, 0x0b, 0xd4, 0x09, 0xac, 0x94, ++ 0xaf, 0xb7, 0xf0, 0xb3, 0x0c, 0x1e, 0xf5, 0x16, 0x4f, 0x53, 0x9a, 0xe3, ++ 0xcc, 0xe2, 0x0c, 0x4a, 0xb9, 0xe6, 0x06, 0xbb, 0xf7, 0x41, 0x43, 0x20, ++ 0x04, 0xee, 0x99, 0x2f, 0xd8, 0x9f, 0xda, 0x3f, 0xfd, 0x49, 0xb8, 0xc2, ++ 0xbd, 0xd9, 0xc5, 0x72, 0xfd, 0xe3, 0xce, 0x1c, 0xbc, 0xe4, 0x39, 0xac, ++ 0x2a, 0x99, 0xe9, 0xb4, 0x3e, 0x74, 0x10, 0xeb, 0xd5, 0x14, 0xcc, 0xdb, ++ 0xf1, 0x04, 0x63, 0x36, 0xfb, 0x1f, 0x2b, 0xe2, 0x73, 0xd4, 0xd8, 0x49, ++ 0x31, 0xa8, 0x55, 0xcc, 0xa7, 0x76, 0x36, 0x6e, 0x18, 0xdc, 0xb9, 0xb0, ++ 0x29, 0x99, 0xcf, 0x49, 0xbf, 0xf9, 0xdb, 0x7f, 0x24, 0x42, 0x02, 0xcb, ++ 0xc1, 0xaa, 0xcb, 0xba, 0x18, 0x85, 0x86, 0xc7, 0xf4, 0x1c, 0x62, 0x76, ++ 0xbc, 0x73, 0xfb, 0xe4, 0x15, 0xb8, 0xdd, 0x5d, 0xa6, 0x68, 0x39, 0xa5, ++ 0x3d, 0x33, 0xaf, 0xd5, 0x92, 0x4d, 0x48, 0xdb, 0x22, 0xc0, 0xdc, 0x49, ++ 0x5f, 0x7b, 0xa8, 0xd2, 0x62, 0x2d, 0xa7, 0x39, 0x93, 0x48, 0xe7, 0x6b, ++ 0x23, 0xba, 0xd4, 0xe0, 0xc1, 0x29, 0x55, 0xc4, 0x34, 0xe3, 0xac, 0x25, ++ 0xa7, 0x15, 0xad, 0xab, 0xb3, 0xb7, 0x25, 0xca, 0x37, 0x88, 0x40, 0x2e, ++ 0x47, 0x6e, 0x92, 0x20, 0x09, 0x2e, 0x5a, 0xec, 0xf2, 0xfb, 0xb3, 0xa0, ++ 0x16, 0xb6, 0x93, 0xf2, 0xf5, 0x8b, 0xfe, 0xaf, 0x25, 0xee, 0x2e, 0x98, ++ 0x6c, 0x0a, 0xfe, 0xae, 0x0b, 0x57, 0xf5, 0x9f, 0x3c, 0x80, 0xe9, 0x8b, ++ 0xaf, 0x92, 0x8a, 0xad, 0xe7, 0xa0, 0xe4, 0xe6, 0x0a, 0xa0, 0xc7, 0x83, ++ 0xb5, 0x48, 0x58, 0x5f, 0x55, 0x9e, 0x9b, 0x27, 0xcd, 0x31, 0x1f, 0x3e, ++ 0x50, 0x5a, 0x91, 0xad, 0x21, 0x1b, 0x97, 0x5b, 0xe8, 0xfa, 0x29, 0x8a, ++ 0xa4, 0x17, 0xe8, 0xab, 0x87, 0x02, 0xd6, 0x18, 0x8c, 0x9f, 0x65, 0xb7, ++ 0x2a, 0xfa, 0xde, 0x5f, 0x77, 0x30, 0x6c, 0x04, 0x22, 0xe6, 0x58, 0x26, ++ 0x14, 0x0d, 0x9c, 0x41, 0x0a, 0x82, 0x77, 0xdb, 0x40, 0xa1, 0x58, 0xac, ++ 0x30, 0x82, 0x02, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x55, 0x30, 0x3d, 0x31, ++ 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x32, 0x47, 0x72, ++ 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x20, ++ 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, 0x65, ++ 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, ++ 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, ++ 0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, 0x3a, ++ 0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x92, 0x03, 0x30, 0x0b, ++ 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, ++ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, ++ 0x05, 0x00, 0x04, 0x82, 0x02, 0x00, 0xa0, 0x83, 0x3f, 0xac, 0x77, 0x97, ++ 0x74, 0x9b, 0x4b, 0x25, 0xa1, 0x64, 0x09, 0x8d, 0x53, 0xa6, 0x03, 0xdf, ++ 0x9a, 0x10, 0x52, 0xe5, 0x3f, 0xd4, 0x72, 0x75, 0x30, 0xd4, 0x6e, 0x77, ++ 0x32, 0x49, 0x84, 0xe2, 0xbe, 0xef, 0xe4, 0xf3, 0xac, 0xb0, 0x52, 0x55, ++ 0xbf, 0xa9, 0x57, 0x12, 0x08, 0x7d, 0xb0, 0x86, 0xc0, 0x9d, 0x01, 0xc2, ++ 0x1a, 0x4a, 0x2e, 0x3d, 0xd5, 0xc8, 0x56, 0xac, 0xd1, 0x83, 0x75, 0x88, ++ 0xd4, 0xcc, 0x9f, 0x0d, 0xcf, 0xd3, 0xa6, 0x91, 0xb6, 0xb6, 0xb1, 0xd1, ++ 0x24, 0x9c, 0xd0, 0x13, 0xe8, 0x6b, 0x15, 0x9c, 0x62, 0x33, 0x8d, 0xe3, ++ 0x67, 0x9b, 0xb1, 0x8a, 0x72, 0x38, 0xf7, 0x48, 0x32, 0x2f, 0x1e, 0x45, ++ 0xa8, 0xc4, 0xa5, 0xae, 0xb1, 0xfc, 0x35, 0x25, 0xb5, 0xf9, 0x7f, 0x86, ++ 0xef, 0xa2, 0x6d, 0x78, 0xcc, 0xfd, 0x0c, 0xca, 0x8a, 0xe1, 0xae, 0xcd, ++ 0x0f, 0x58, 0x69, 0xf1, 0x8b, 0xcc, 0x22, 0x35, 0x6d, 0x1f, 0xd5, 0x27, ++ 0x87, 0x39, 0x62, 0x3f, 0xb2, 0x17, 0x3d, 0x5e, 0xb1, 0x32, 0x7a, 0xf1, ++ 0x70, 0xce, 0xfa, 0xab, 0x1c, 0x92, 0xa8, 0xe1, 0xc4, 0xb2, 0x33, 0x1a, ++ 0x16, 0xf3, 0x60, 0x39, 0xdf, 0xb8, 0x85, 0xe7, 0x5d, 0x4d, 0xc2, 0x8d, ++ 0x55, 0x00, 0x49, 0x94, 0x04, 0x17, 0x88, 0x7c, 0xf4, 0xac, 0xa9, 0xc5, ++ 0x3a, 0x09, 0xc4, 0xc2, 0xcd, 0x3d, 0xc3, 0xfc, 0x4e, 0xf3, 0x70, 0xa1, ++ 0xc1, 0x54, 0x36, 0x1f, 0x38, 0x6d, 0x7a, 0x6b, 0x6a, 0xd3, 0x67, 0x04, ++ 0xd5, 0x53, 0xd4, 0xa5, 0xad, 0x63, 0x55, 0x0e, 0x06, 0x06, 0x3a, 0x9a, ++ 0xc5, 0xfe, 0x38, 0xc9, 0xb0, 0x69, 0x42, 0x90, 0x35, 0x1f, 0xe3, 0x1c, ++ 0x57, 0xea, 0xdb, 0x51, 0x35, 0x53, 0xd3, 0x94, 0xfe, 0x72, 0x33, 0xd6, ++ 0x8a, 0x46, 0x74, 0xf9, 0x6e, 0x94, 0x40, 0x2f, 0xba, 0xa2, 0xc4, 0xe9, ++ 0xc9, 0x8a, 0xf4, 0xda, 0xe2, 0xca, 0x3e, 0x98, 0x85, 0xa5, 0xd1, 0x60, ++ 0x94, 0xc8, 0xdf, 0x82, 0xee, 0x5c, 0x0d, 0x2a, 0xa9, 0x8e, 0x26, 0x83, ++ 0x3f, 0x02, 0xa2, 0xaf, 0xb8, 0x3b, 0x83, 0xf2, 0x44, 0x46, 0x41, 0xd7, ++ 0x5c, 0xa1, 0x42, 0x17, 0xa2, 0xd0, 0x50, 0x42, 0xef, 0x66, 0xda, 0x35, ++ 0x03, 0xd1, 0x8e, 0x77, 0x22, 0x7d, 0x4e, 0xf7, 0x4e, 0x04, 0xe3, 0x0f, ++ 0x98, 0x7d, 0xaa, 0x58, 0xba, 0xef, 0x9a, 0xd0, 0x88, 0x7c, 0x98, 0xa0, ++ 0xc2, 0xff, 0xa6, 0xb1, 0xec, 0xbe, 0x6e, 0xb0, 0x7e, 0xc6, 0xe5, 0xaa, ++ 0xcf, 0x10, 0x73, 0xc9, 0x13, 0x1a, 0x20, 0x12, 0x5c, 0xd2, 0x0e, 0xe2, ++ 0x60, 0x17, 0xdf, 0x4a, 0x44, 0x08, 0x22, 0xbc, 0xcd, 0x75, 0xbe, 0xc3, ++ 0x7a, 0x12, 0x90, 0x90, 0xc7, 0x94, 0x4c, 0x98, 0x45, 0x02, 0x5c, 0x24, ++ 0xae, 0x82, 0x2f, 0xcd, 0x30, 0xa6, 0xf5, 0x3f, 0xd3, 0xa7, 0xa6, 0xe6, ++ 0xea, 0x11, 0x4e, 0x45, 0xb7, 0xc0, 0xe6, 0x24, 0x8b, 0x76, 0xc5, 0x5e, ++ 0xc1, 0xd8, 0x07, 0x1e, 0x26, 0x94, 0x7a, 0x80, 0xc6, 0x3b, 0x1f, 0x74, ++ 0xe6, 0xae, 0x43, 0x2d, 0x11, 0xee, 0x96, 0x56, 0x6c, 0xff, 0xcb, 0x3b, ++ 0xde, 0xcc, 0xb3, 0x7b, 0x08, 0xf5, 0x3e, 0x6e, 0x51, 0x71, 0xe0, 0x8a, ++ 0xfa, 0xdd, 0x19, 0x39, 0xcf, 0x3f, 0x29, 0x4f, 0x2d, 0xd2, 0xd4, 0xdc, ++ 0x5c, 0xc4, 0xd1, 0xa7, 0xf5, 0xbf, 0x4a, 0xc0, 0x9b, 0xb4, 0x2b, 0x83, ++ 0x7a, 0x63, 0x4d, 0x20, 0x40, 0x8b, 0x11, 0x5c, 0x53, 0xd4, 0x52, 0x21, ++ 0xe7, 0xe4, 0x1f, 0x01, 0xf6, 0xd1, 0x25, 0x28, 0xba, 0x51, 0x6f, 0x51, ++ 0x69, 0xf4, 0x41, 0x45, 0x75, 0x23, 0x25, 0x77, 0xef, 0xa8, 0x1c, 0x19, ++ 0x8a, 0x66, 0x8c, 0x61, 0x13, 0x37, 0x4f, 0xa3, 0xa1, 0x83, 0x17, 0x35, ++ 0x23, 0x2d, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x05, 0x33, 0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, 0x69, ++ 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, 0x65, ++ 0x6e, 0x64, 0x65, 0x64, 0x7e, 0x0a ++}; ++unsigned int hi_double_len = 1374; ++ ++unsigned char hi_double_extended[] = { ++ 0x68, 0x69, 0x0a, 0x30, 0x82, 0x05, 0x2f, 0x06, 0x09, 0x2a, 0x86, 0x48, ++ 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x05, 0x20, 0x30, 0x82, ++ 0x05, 0x1c, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, ++ 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09, ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x04, ++ 0xf9, 0x30, 0x82, 0x02, 0x77, 0x02, 0x01, 0x01, 0x30, 0x52, 0x30, 0x3a, ++ 0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2f, 0x47, ++ 0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, 0x43, 0x65, 0x72, 0x74, ++ 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, ++ 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, ++ 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x02, 0x14, ++ 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, 0x3a, 0x91, 0x07, ++ 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x91, 0xff, 0x30, 0x0b, 0x06, 0x09, ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0d, 0x06, ++ 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, ++ 0x04, 0x82, 0x02, 0x00, 0x0e, 0xc2, 0x30, 0x38, 0x81, 0x23, 0x68, 0x90, ++ 0xae, 0x5f, 0xce, 0xf7, 0x27, 0xb1, 0x8c, 0x2e, 0x12, 0x10, 0xc6, 0x99, ++ 0xdc, 0x4d, 0x4b, 0x79, 0xda, 0xe4, 0x32, 0x10, 0x46, 0x1c, 0x16, 0x07, ++ 0x87, 0x66, 0x55, 0xff, 0x64, 0x1c, 0x61, 0x25, 0xd5, 0xb9, 0xe1, 0xfe, ++ 0xea, 0x5a, 0xcd, 0x56, 0xa5, 0xc3, 0xbe, 0xb1, 0x61, 0xc7, 0x6f, 0x5f, ++ 0x69, 0x20, 0x64, 0x50, 0x6f, 0x12, 0x78, 0xb6, 0x0c, 0x72, 0x44, 0x4f, ++ 0x60, 0x0f, 0x9f, 0xa2, 0x83, 0x3b, 0xc2, 0x83, 0xd5, 0x14, 0x1f, 0x6f, ++ 0x3e, 0xb2, 0x47, 0xb5, 0x58, 0xc5, 0xa7, 0xb4, 0x82, 0x53, 0x2e, 0x53, ++ 0x95, 0x4e, 0x3d, 0xe4, 0x62, 0xe8, 0xa1, 0xaf, 0xae, 0xbf, 0xa9, 0xd2, ++ 0x22, 0x07, 0xbe, 0x71, 0x37, 0x2c, 0x5a, 0xa7, 0x6c, 0xaf, 0x14, 0xc0, ++ 0x6c, 0x2f, 0xbf, 0x4f, 0x15, 0xc2, 0x0f, 0x8b, 0xdc, 0x68, 0x45, 0xdf, ++ 0xf3, 0xa5, 0x7f, 0x11, 0x6a, 0x54, 0xcd, 0x67, 0xb9, 0x2e, 0x7d, 0x05, ++ 0xe3, 0x1c, 0x1d, 0xcc, 0x77, 0x8e, 0x97, 0xb1, 0xa0, 0x11, 0x09, 0x3d, ++ 0x90, 0x54, 0xfc, 0x7e, 0xbb, 0xbb, 0x21, 0x23, 0x03, 0x44, 0xbf, 0x7d, ++ 0x2c, 0xc9, 0x15, 0x42, 0xe5, 0xa0, 0x3b, 0xa2, 0xd1, 0x5b, 0x73, 0x81, ++ 0xff, 0xfa, 0x90, 0xfc, 0x27, 0x7b, 0x2f, 0x86, 0x9c, 0x1d, 0x14, 0x36, ++ 0x94, 0xa2, 0x6e, 0xe8, 0x9d, 0xa0, 0x5f, 0xfc, 0x5a, 0x0d, 0xa4, 0xd5, ++ 0x2f, 0x8d, 0xd6, 0x00, 0xfa, 0x93, 0x5b, 0x09, 0x7f, 0x42, 0x78, 0xcc, ++ 0x8c, 0x49, 0xda, 0xd9, 0xf6, 0x43, 0xe7, 0xe1, 0x3c, 0xa2, 0xe2, 0x70, ++ 0xe2, 0x6a, 0x99, 0xc5, 0xd6, 0xa2, 0xe3, 0x0b, 0xd4, 0x09, 0xac, 0x94, ++ 0xaf, 0xb7, 0xf0, 0xb3, 0x0c, 0x1e, 0xf5, 0x16, 0x4f, 0x53, 0x9a, 0xe3, ++ 0xcc, 0xe2, 0x0c, 0x4a, 0xb9, 0xe6, 0x06, 0xbb, 0xf7, 0x41, 0x43, 0x20, ++ 0x04, 0xee, 0x99, 0x2f, 0xd8, 0x9f, 0xda, 0x3f, 0xfd, 0x49, 0xb8, 0xc2, ++ 0xbd, 0xd9, 0xc5, 0x72, 0xfd, 0xe3, 0xce, 0x1c, 0xbc, 0xe4, 0x39, 0xac, ++ 0x2a, 0x99, 0xe9, 0xb4, 0x3e, 0x74, 0x10, 0xeb, 0xd5, 0x14, 0xcc, 0xdb, ++ 0xf1, 0x04, 0x63, 0x36, 0xfb, 0x1f, 0x2b, 0xe2, 0x73, 0xd4, 0xd8, 0x49, ++ 0x31, 0xa8, 0x55, 0xcc, 0xa7, 0x76, 0x36, 0x6e, 0x18, 0xdc, 0xb9, 0xb0, ++ 0x29, 0x99, 0xcf, 0x49, 0xbf, 0xf9, 0xdb, 0x7f, 0x24, 0x42, 0x02, 0xcb, ++ 0xc1, 0xaa, 0xcb, 0xba, 0x18, 0x85, 0x86, 0xc7, 0xf4, 0x1c, 0x62, 0x76, ++ 0xbc, 0x73, 0xfb, 0xe4, 0x15, 0xb8, 0xdd, 0x5d, 0xa6, 0x68, 0x39, 0xa5, ++ 0x3d, 0x33, 0xaf, 0xd5, 0x92, 0x4d, 0x48, 0xdb, 0x22, 0xc0, 0xdc, 0x49, ++ 0x5f, 0x7b, 0xa8, 0xd2, 0x62, 0x2d, 0xa7, 0x39, 0x93, 0x48, 0xe7, 0x6b, ++ 0x23, 0xba, 0xd4, 0xe0, 0xc1, 0x29, 0x55, 0xc4, 0x34, 0xe3, 0xac, 0x25, ++ 0xa7, 0x15, 0xad, 0xab, 0xb3, 0xb7, 0x25, 0xca, 0x37, 0x88, 0x40, 0x2e, ++ 0x47, 0x6e, 0x92, 0x20, 0x09, 0x2e, 0x5a, 0xec, 0xf2, 0xfb, 0xb3, 0xa0, ++ 0x16, 0xb6, 0x93, 0xf2, 0xf5, 0x8b, 0xfe, 0xaf, 0x25, 0xee, 0x2e, 0x98, ++ 0x6c, 0x0a, 0xfe, 0xae, 0x0b, 0x57, 0xf5, 0x9f, 0x3c, 0x80, 0xe9, 0x8b, ++ 0xaf, 0x92, 0x8a, 0xad, 0xe7, 0xa0, 0xe4, 0xe6, 0x0a, 0xa0, 0xc7, 0x83, ++ 0xb5, 0x48, 0x58, 0x5f, 0x55, 0x9e, 0x9b, 0x27, 0xcd, 0x31, 0x1f, 0x3e, ++ 0x50, 0x5a, 0x91, 0xad, 0x21, 0x1b, 0x97, 0x5b, 0xe8, 0xfa, 0x29, 0x8a, ++ 0xa4, 0x17, 0xe8, 0xab, 0x87, 0x02, 0xd6, 0x18, 0x8c, 0x9f, 0x65, 0xb7, ++ 0x2a, 0xfa, 0xde, 0x5f, 0x77, 0x30, 0x6c, 0x04, 0x22, 0xe6, 0x58, 0x26, ++ 0x14, 0x0d, 0x9c, 0x41, 0x0a, 0x82, 0x77, 0xdb, 0x40, 0xa1, 0x58, 0xac, ++ 0x30, 0x82, 0x02, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x55, 0x30, 0x3d, 0x31, ++ 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x32, 0x47, 0x72, ++ 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x20, ++ 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, 0x65, ++ 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, ++ 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, ++ 0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, 0x3a, ++ 0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x92, 0x03, 0x30, 0x0b, ++ 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, ++ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, ++ 0x05, 0x00, 0x04, 0x82, 0x02, 0x00, 0xa0, 0x83, 0x3f, 0xac, 0x77, 0x97, ++ 0x74, 0x9b, 0x4b, 0x25, 0xa1, 0x64, 0x09, 0x8d, 0x53, 0xa6, 0x03, 0xdf, ++ 0x9a, 0x10, 0x52, 0xe5, 0x3f, 0xd4, 0x72, 0x75, 0x30, 0xd4, 0x6e, 0x77, ++ 0x32, 0x49, 0x84, 0xe2, 0xbe, 0xef, 0xe4, 0xf3, 0xac, 0xb0, 0x52, 0x55, ++ 0xbf, 0xa9, 0x57, 0x12, 0x08, 0x7d, 0xb0, 0x86, 0xc0, 0x9d, 0x01, 0xc2, ++ 0x1a, 0x4a, 0x2e, 0x3d, 0xd5, 0xc8, 0x56, 0xac, 0xd1, 0x83, 0x75, 0x88, ++ 0xd4, 0xcc, 0x9f, 0x0d, 0xcf, 0xd3, 0xa6, 0x91, 0xb6, 0xb6, 0xb1, 0xd1, ++ 0x24, 0x9c, 0xd0, 0x13, 0xe8, 0x6b, 0x15, 0x9c, 0x62, 0x33, 0x8d, 0xe3, ++ 0x67, 0x9b, 0xb1, 0x8a, 0x72, 0x38, 0xf7, 0x48, 0x32, 0x2f, 0x1e, 0x45, ++ 0xa8, 0xc4, 0xa5, 0xae, 0xb1, 0xfc, 0x35, 0x25, 0xb5, 0xf9, 0x7f, 0x86, ++ 0xef, 0xa2, 0x6d, 0x78, 0xcc, 0xfd, 0x0c, 0xca, 0x8a, 0xe1, 0xae, 0xcd, ++ 0x0f, 0x58, 0x69, 0xf1, 0x8b, 0xcc, 0x22, 0x35, 0x6d, 0x1f, 0xd5, 0x27, ++ 0x87, 0x39, 0x62, 0x3f, 0xb2, 0x17, 0x3d, 0x5e, 0xb1, 0x32, 0x7a, 0xf1, ++ 0x70, 0xce, 0xfa, 0xab, 0x1c, 0x92, 0xa8, 0xe1, 0xc4, 0xb2, 0x33, 0x1a, ++ 0x16, 0xf3, 0x60, 0x39, 0xdf, 0xb8, 0x85, 0xe7, 0x5d, 0x4d, 0xc2, 0x8d, ++ 0x55, 0x00, 0x49, 0x94, 0x04, 0x17, 0x88, 0x7c, 0xf4, 0xac, 0xa9, 0xc5, ++ 0x3a, 0x09, 0xc4, 0xc2, 0xcd, 0x3d, 0xc3, 0xfc, 0x4e, 0xf3, 0x70, 0xa1, ++ 0xc1, 0x54, 0x36, 0x1f, 0x38, 0x6d, 0x7a, 0x6b, 0x6a, 0xd3, 0x67, 0x04, ++ 0xd5, 0x53, 0xd4, 0xa5, 0xad, 0x63, 0x55, 0x0e, 0x06, 0x06, 0x3a, 0x9a, ++ 0xc5, 0xfe, 0x38, 0xc9, 0xb0, 0x69, 0x42, 0x90, 0x35, 0x1f, 0xe3, 0x1c, ++ 0x57, 0xea, 0xdb, 0x51, 0x35, 0x53, 0xd3, 0x94, 0xfe, 0x72, 0x33, 0xd6, ++ 0x8a, 0x46, 0x74, 0xf9, 0x6e, 0x94, 0x40, 0x2f, 0xba, 0xa2, 0xc4, 0xe9, ++ 0xc9, 0x8a, 0xf4, 0xda, 0xe2, 0xca, 0x3e, 0x98, 0x85, 0xa5, 0xd1, 0x60, ++ 0x94, 0xc8, 0xdf, 0x82, 0xee, 0x5c, 0x0d, 0x2a, 0xa9, 0x8e, 0x26, 0x83, ++ 0x3f, 0x02, 0xa2, 0xaf, 0xb8, 0x3b, 0x83, 0xf2, 0x44, 0x46, 0x41, 0xd7, ++ 0x5c, 0xa1, 0x42, 0x17, 0xa2, 0xd0, 0x50, 0x42, 0xef, 0x66, 0xda, 0x35, ++ 0x03, 0xd1, 0x8e, 0x77, 0x22, 0x7d, 0x4e, 0xf7, 0x4e, 0x04, 0xe3, 0x0f, ++ 0x98, 0x7d, 0xaa, 0x58, 0xba, 0xef, 0x9a, 0xd0, 0x88, 0x7c, 0x98, 0xa0, ++ 0xc2, 0xff, 0xa6, 0xb1, 0xec, 0xbe, 0x6e, 0xb0, 0x7e, 0xc6, 0xe5, 0xaa, ++ 0xcf, 0x10, 0x73, 0xc9, 0x13, 0x1a, 0x20, 0x12, 0x5c, 0xd2, 0x0e, 0xe2, ++ 0x60, 0x17, 0xdf, 0x4a, 0x44, 0x08, 0x22, 0xbc, 0xcd, 0x75, 0xbe, 0xc3, ++ 0x7a, 0x12, 0x90, 0x90, 0xc7, 0x94, 0x4c, 0x98, 0x45, 0x02, 0x5c, 0x24, ++ 0xae, 0x82, 0x2f, 0xcd, 0x30, 0xa6, 0xf5, 0x3f, 0xd3, 0xa7, 0xa6, 0xe6, ++ 0xea, 0x11, 0x4e, 0x45, 0xb7, 0xc0, 0xe6, 0x24, 0x8b, 0x76, 0xc5, 0x5e, ++ 0xc1, 0xd8, 0x07, 0x1e, 0x26, 0x94, 0x7a, 0x80, 0xc6, 0x3b, 0x1f, 0x74, ++ 0xe6, 0xae, 0x43, 0x2d, 0x11, 0xee, 0x96, 0x56, 0x6c, 0xff, 0xcb, 0x3b, ++ 0xde, 0xcc, 0xb3, 0x7b, 0x08, 0xf5, 0x3e, 0x6e, 0x51, 0x71, 0xe0, 0x8a, ++ 0xfa, 0xdd, 0x19, 0x39, 0xcf, 0x3f, 0x29, 0x4f, 0x2d, 0xd2, 0xd4, 0xdc, ++ 0x5c, 0xc4, 0xd1, 0xa7, 0xf5, 0xbf, 0x4a, 0xc0, 0x9b, 0xb4, 0x2b, 0x83, ++ 0x7a, 0x63, 0x4d, 0x20, 0x40, 0x8b, 0x11, 0x5c, 0x53, 0xd4, 0x52, 0x21, ++ 0xe7, 0xe4, 0x1f, 0x01, 0xf6, 0xd1, 0x25, 0x28, 0xba, 0x51, 0x6f, 0x51, ++ 0x69, 0xf4, 0x41, 0x45, 0x75, 0x23, 0x25, 0x77, 0xef, 0xa8, 0x1c, 0x19, ++ 0x8a, 0x66, 0x8c, 0x61, 0x13, 0x37, 0x4f, 0xa3, 0xa1, 0x83, 0x17, 0x35, ++ 0x23, 0x2d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x05, 0x34, 0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, ++ 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, ++ 0x65, 0x6e, 0x64, 0x65, 0x64, 0x7e, 0x0a ++}; ++unsigned int hi_double_extended_len = 1375; ++ ++unsigned char certificate_printable_der[] = { ++ 0x30, 0x82, 0x03, 0x39, 0x30, 0x82, 0x02, 0x21, 0xa0, 0x03, 0x02, 0x01, ++ 0x02, 0x02, 0x09, 0x00, 0xde, 0xf6, 0x22, 0xc4, 0xf2, 0xf1, 0x86, 0x02, ++ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, ++ 0x0b, 0x05, 0x00, 0x30, 0x2a, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, ++ 0x04, 0x03, 0x13, 0x1f, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20, ++ 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20, ++ 0x43, 0x41, 0x20, 0x32, 0x20, 0x28, 0x62, 0x65, 0x74, 0x61, 0x29, 0x30, ++ 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x31, 0x30, 0x33, 0x31, 0x31, 0x34, 0x31, ++ 0x39, 0x32, 0x33, 0x5a, 0x17, 0x0d, 0x33, 0x37, 0x31, 0x30, 0x32, 0x35, ++ 0x31, 0x34, 0x31, 0x39, 0x32, 0x33, 0x5a, 0x30, 0x2f, 0x31, 0x2d, 0x30, ++ 0x2b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x24, 0x52, 0x65, 0x64, 0x20, ++ 0x48, 0x61, 0x74, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42, ++ 0x6f, 0x6f, 0x74, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, ++ 0x33, 0x20, 0x28, 0x62, 0x65, 0x74, 0x61, 0x29, 0x30, 0x82, 0x01, 0x22, ++ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, ++ 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, ++ 0x02, 0x82, 0x01, 0x01, 0x00, 0xbd, 0xda, 0xa1, 0xed, 0x8d, 0x8e, 0x15, ++ 0x5c, 0xf8, 0x01, 0x77, 0x48, 0x4a, 0x60, 0x96, 0xf9, 0x27, 0xfa, 0xe2, ++ 0xb1, 0x69, 0x0f, 0x51, 0x19, 0x52, 0x7e, 0xc4, 0x34, 0x8e, 0xe1, 0x9b, ++ 0x9c, 0xa4, 0xb1, 0x5c, 0xd6, 0x81, 0x98, 0x78, 0xfe, 0xa9, 0xe5, 0x0b, ++ 0x00, 0xba, 0x9c, 0x64, 0x7e, 0xc7, 0xcc, 0x72, 0xb1, 0x73, 0x4b, 0x11, ++ 0x07, 0x52, 0xf0, 0x20, 0x96, 0x8b, 0x99, 0x39, 0xde, 0xdb, 0xfa, 0x3d, ++ 0x45, 0xe2, 0x98, 0x7b, 0x0c, 0x41, 0xe4, 0x0c, 0xb5, 0x5d, 0x92, 0x74, ++ 0x39, 0x96, 0xe1, 0x97, 0x97, 0xa1, 0xad, 0x2e, 0xcc, 0xd0, 0x1b, 0x4d, ++ 0x9d, 0xbd, 0x3e, 0xa9, 0x36, 0x8e, 0xcc, 0xc7, 0x5f, 0x6a, 0x7d, 0x39, ++ 0x5e, 0x0b, 0x8d, 0xca, 0xe4, 0x83, 0xe9, 0x3b, 0x5c, 0x86, 0x47, 0xd4, ++ 0xba, 0x7d, 0x98, 0x26, 0xa1, 0xf4, 0xe8, 0x90, 0x6b, 0x0f, 0xf1, 0x6b, ++ 0x8c, 0xe3, 0xa2, 0x80, 0x3c, 0x96, 0xf1, 0x0a, 0xb6, 0x66, 0xc0, 0x4b, ++ 0x61, 0xf7, 0x74, 0xcd, 0xd3, 0x7b, 0x8e, 0x5e, 0x39, 0xda, 0x99, 0x20, ++ 0x33, 0x93, 0xd3, 0xf0, 0x7f, 0xad, 0x35, 0xe9, 0x88, 0x8d, 0x9c, 0xbf, ++ 0x65, 0xf1, 0x47, 0x02, 0xf9, 0x7c, 0xed, 0x27, 0x5f, 0x4a, 0x65, 0x3c, ++ 0xcf, 0x5f, 0x0e, 0x88, 0x95, 0x74, 0xde, 0xfb, 0x9e, 0x2e, 0x91, 0x9b, ++ 0x45, 0x37, 0xc8, 0x85, 0xff, 0xe3, 0x41, 0x70, 0xfe, 0xd5, 0xef, 0x0e, ++ 0x82, 0x22, 0x08, 0xb7, 0x3b, 0x44, 0x3e, 0xdc, 0x5b, 0x7f, 0xba, 0xbf, ++ 0xe6, 0x58, 0x9d, 0x02, 0x6e, 0x75, 0xbf, 0x50, 0xec, 0xcf, 0x3f, 0xa5, ++ 0x91, 0x0a, 0xe2, 0x59, 0x2c, 0xc3, 0xe7, 0x05, 0x03, 0xe8, 0xf2, 0x6f, ++ 0x2a, 0x04, 0x68, 0x9a, 0x31, 0x32, 0x8f, 0x04, 0x35, 0xcd, 0x1f, 0x34, ++ 0xcc, 0x4f, 0x79, 0x5a, 0x99, 0x8d, 0x9d, 0x5c, 0xf5, 0x02, 0x03, 0x01, ++ 0x00, 0x01, 0xa3, 0x5d, 0x30, 0x5b, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, ++ 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0b, 0x06, 0x03, ++ 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80, 0x30, 0x1d, 0x06, ++ 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x65, 0xc5, 0xbe, 0xca, ++ 0xe6, 0x59, 0x6a, 0xfd, 0x6c, 0x71, 0xc4, 0xa7, 0x98, 0xc6, 0x25, 0x8d, ++ 0x7b, 0x67, 0x05, 0xd0, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, ++ 0x18, 0x30, 0x16, 0x80, 0x14, 0x81, 0xf8, 0xee, 0x47, 0x5c, 0x3e, 0xed, ++ 0xfb, 0xce, 0xa5, 0x84, 0xbe, 0xd7, 0xae, 0xdb, 0xd3, 0x7d, 0x64, 0xb3, ++ 0x2a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, ++ 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x66, 0x1e, 0x3d, ++ 0x1d, 0x53, 0x33, 0xde, 0x4e, 0xc7, 0xc4, 0xf4, 0xdf, 0xda, 0x18, 0x19, ++ 0x8a, 0xa9, 0xff, 0xe2, 0x63, 0x2b, 0xbe, 0xf2, 0x61, 0x63, 0xe2, 0xf6, ++ 0xed, 0x47, 0x1a, 0x71, 0x02, 0xec, 0x2a, 0xef, 0x89, 0x77, 0xe3, 0xfd, ++ 0x86, 0x69, 0xf1, 0x3f, 0x0d, 0xf9, 0x6e, 0xf9, 0x3b, 0xad, 0x26, 0x47, ++ 0xb7, 0xf2, 0x0d, 0xad, 0x23, 0xa3, 0x67, 0x3b, 0xcb, 0x6d, 0x9e, 0x03, ++ 0x0f, 0xbc, 0x69, 0x73, 0x9f, 0xd4, 0xa5, 0x0f, 0x6f, 0xf8, 0xab, 0x4d, ++ 0x36, 0xd1, 0xe0, 0xe0, 0x5d, 0x20, 0x43, 0x90, 0xc4, 0x65, 0x61, 0x93, ++ 0xe2, 0x0f, 0x51, 0x59, 0x0a, 0xf7, 0x88, 0x70, 0x57, 0xb9, 0x04, 0xa9, ++ 0x32, 0x57, 0x9c, 0xb3, 0x57, 0x38, 0x8b, 0x8e, 0x46, 0xc8, 0x32, 0x6c, ++ 0xb4, 0xf3, 0x96, 0x7f, 0x4b, 0xf0, 0x88, 0xf9, 0x7f, 0xe2, 0x71, 0xe1, ++ 0x8b, 0xe2, 0x14, 0xf1, 0x4b, 0x25, 0x00, 0x48, 0x1c, 0x7e, 0xe5, 0x8d, ++ 0x65, 0x2d, 0xeb, 0x72, 0x4f, 0x92, 0x44, 0xf3, 0xe6, 0xe0, 0xd0, 0xdf, ++ 0x85, 0xa8, 0x13, 0x4a, 0xfb, 0x99, 0xca, 0x14, 0x2c, 0x97, 0x80, 0x93, ++ 0x27, 0xd3, 0x20, 0xf8, 0x6d, 0x29, 0x28, 0x2c, 0xb9, 0x77, 0xea, 0xb1, ++ 0x63, 0xbd, 0x7d, 0x53, 0xfd, 0x4a, 0x62, 0x64, 0x0b, 0x98, 0xa8, 0xae, ++ 0x11, 0xfc, 0x6e, 0x8d, 0x63, 0xd4, 0x15, 0x55, 0xc6, 0x4c, 0x74, 0xf5, ++ 0x5f, 0xa0, 0xb9, 0x2c, 0x2d, 0x9a, 0x7a, 0x87, 0x6e, 0xf0, 0x5e, 0x25, ++ 0xed, 0xfc, 0xd8, 0xc4, 0x34, 0x33, 0x32, 0xad, 0x01, 0xd4, 0x4b, 0x49, ++ 0x51, 0xc2, 0x07, 0x7f, 0x90, 0x6d, 0xea, 0xf5, 0x4c, 0x41, 0x71, 0x64, ++ 0xeb, 0x1f, 0x29, 0xa3, 0x1f, 0x64, 0xa2, 0x1e, 0x0e, 0x6f, 0xa1, 0x67, ++ 0x99, 0x8d, 0x98, 0x1c, 0xb8, 0x53, 0x9d, 0x30, 0x1d, 0xae, 0x32, 0x56, ++ 0xd2 ++}; ++unsigned int certificate_printable_der_len = 829; ++ ++unsigned char certificate_eku_der[] = { ++ 0x30, 0x82, 0x03, 0x90, 0x30, 0x82, 0x02, 0x78, 0xa0, 0x03, 0x02, 0x01, ++ 0x02, 0x02, 0x09, 0x00, 0xd3, 0x9c, 0x41, 0x33, 0xdd, 0x6b, 0x5f, 0x45, ++ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, ++ 0x0b, 0x05, 0x00, 0x30, 0x47, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, ++ 0x04, 0x03, 0x0c, 0x18, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20, ++ 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20, ++ 0x43, 0x41, 0x20, 0x36, 0x31, 0x22, 0x30, 0x20, 0x06, 0x09, 0x2a, 0x86, ++ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x13, 0x73, 0x65, 0x63, ++ 0x61, 0x6c, 0x65, 0x72, 0x74, 0x40, 0x72, 0x65, 0x64, 0x68, 0x61, 0x74, ++ 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x30, 0x32, ++ 0x31, 0x35, 0x31, 0x34, 0x30, 0x30, 0x34, 0x34, 0x5a, 0x17, 0x0d, 0x33, ++ 0x38, 0x30, 0x31, 0x31, 0x37, 0x31, 0x34, 0x30, 0x30, 0x34, 0x34, 0x5a, ++ 0x30, 0x4e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, ++ 0x1f, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20, 0x53, 0x65, 0x63, ++ 0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20, 0x53, 0x69, 0x67, ++ 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x36, 0x30, 0x32, 0x31, 0x22, 0x30, 0x20, ++ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, ++ 0x13, 0x73, 0x65, 0x63, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x40, 0x72, 0x65, ++ 0x64, 0x68, 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22, ++ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, ++ 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, ++ 0x02, 0x82, 0x01, 0x01, 0x00, 0xaa, 0x6f, 0xbb, 0x92, 0x77, 0xd7, 0x15, ++ 0xef, 0x88, 0x80, 0x88, 0xc0, 0xe7, 0x89, 0xeb, 0x35, 0x76, 0xf4, 0x85, ++ 0x05, 0x0f, 0x19, 0xe4, 0x5f, 0x25, 0xdd, 0xc1, 0xa2, 0xe5, 0x5c, 0x06, ++ 0xfb, 0xf1, 0x06, 0xb5, 0x65, 0x45, 0xcb, 0xbd, 0x19, 0x33, 0x54, 0xb5, ++ 0x1a, 0xcd, 0xe4, 0xa8, 0x35, 0x2a, 0xfe, 0x9c, 0x53, 0xf4, 0xc6, 0x76, ++ 0xdb, 0x1f, 0x8a, 0xd4, 0x7b, 0x18, 0x11, 0xaf, 0xa3, 0x90, 0xd4, 0xdd, ++ 0x4d, 0xd5, 0x42, 0xcc, 0x14, 0x9a, 0x64, 0x6b, 0xc0, 0x7f, 0xaa, 0x1c, ++ 0x94, 0x47, 0x4d, 0x79, 0xbd, 0x57, 0x9a, 0xbf, 0x99, 0x4e, 0x96, 0xa9, ++ 0x31, 0x2c, 0xa9, 0xe7, 0x14, 0x65, 0x86, 0xc8, 0xac, 0x79, 0x5e, 0x78, ++ 0xa4, 0x3c, 0x00, 0x24, 0xd3, 0xf7, 0xe1, 0xf5, 0x12, 0xad, 0xa0, 0x29, ++ 0xe5, 0xfe, 0x80, 0xae, 0xf8, 0xaa, 0x60, 0x36, 0xe7, 0xe8, 0x94, 0xcb, ++ 0xe9, 0xd1, 0xcc, 0x0b, 0x4d, 0xf7, 0xde, 0xeb, 0x52, 0xd2, 0x73, 0x09, ++ 0x28, 0xdf, 0x48, 0x99, 0x53, 0x9f, 0xc5, 0x9a, 0xd4, 0x36, 0xa3, 0xc6, ++ 0x5e, 0x8d, 0xbe, 0xd5, 0xdc, 0x76, 0xb4, 0x74, 0xb8, 0x26, 0x18, 0x27, ++ 0xfb, 0xf2, 0xfb, 0xd0, 0x9b, 0x3d, 0x7f, 0x10, 0xe2, 0xab, 0x44, 0xc7, ++ 0x88, 0x7f, 0xb4, 0x3d, 0x3e, 0xa3, 0xff, 0x6d, 0x06, 0x4b, 0x3e, 0x55, ++ 0xb2, 0x84, 0xf4, 0xad, 0x54, 0x88, 0x81, 0xc3, 0x9c, 0xf8, 0xb6, 0x68, ++ 0x96, 0x38, 0x8b, 0xcd, 0x90, 0x6d, 0x25, 0x4b, 0xbf, 0x0c, 0x44, 0x90, ++ 0xa5, 0x5b, 0x98, 0xd0, 0x40, 0x2f, 0xbb, 0x0d, 0xa8, 0x4b, 0x8a, 0x62, ++ 0x82, 0x46, 0x46, 0x18, 0x38, 0xae, 0x82, 0x07, 0xd0, 0xb4, 0x2f, 0x16, ++ 0x79, 0x55, 0x9f, 0x1b, 0xc5, 0x08, 0x6d, 0x85, 0xdf, 0x3f, 0xa9, 0x9b, ++ 0x4b, 0xc6, 0x28, 0xd3, 0x58, 0x72, 0x3d, 0x37, 0x11, 0x02, 0x03, 0x01, ++ 0x00, 0x01, 0xa3, 0x78, 0x30, 0x76, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, ++ 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0e, 0x06, 0x03, ++ 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80, ++ 0x30, 0x16, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x01, 0x01, 0xff, 0x04, 0x0c, ++ 0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x03, ++ 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x6c, ++ 0xe4, 0x6c, 0x27, 0xaa, 0xcd, 0x0d, 0x4b, 0x74, 0x21, 0xa4, 0xf6, 0x5f, ++ 0x87, 0xb5, 0x31, 0xfe, 0x10, 0xbb, 0xa7, 0x30, 0x1f, 0x06, 0x03, 0x55, ++ 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xe8, 0x6a, 0x1c, 0xab, ++ 0x2c, 0x48, 0xf9, 0x60, 0x36, 0xa2, 0xf0, 0x7b, 0x8e, 0xd2, 0x9d, 0xb4, ++ 0x2a, 0x28, 0x98, 0xc8, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, ++ 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, ++ 0x55, 0x34, 0xe2, 0xfa, 0xf6, 0x89, 0x86, 0xad, 0x92, 0x21, 0xec, 0xb9, ++ 0x54, 0x0e, 0x18, 0x47, 0x0d, 0x1b, 0xa7, 0x58, 0xad, 0x69, 0xe4, 0xef, ++ 0x3b, 0xe6, 0x8d, 0xdd, 0xda, 0x0c, 0x45, 0xf6, 0xe8, 0x96, 0xa4, 0x29, ++ 0x0f, 0xbb, 0xcf, 0x16, 0xae, 0x93, 0xd0, 0xcb, 0x2a, 0x26, 0x1a, 0x7b, ++ 0xfc, 0x51, 0x22, 0x76, 0x98, 0x31, 0xa7, 0x0f, 0x29, 0x35, 0x79, 0xbf, ++ 0xe2, 0x4f, 0x0f, 0x14, 0xf5, 0x1f, 0xcb, 0xbf, 0x87, 0x65, 0x13, 0x32, ++ 0xa3, 0x19, 0x4a, 0xd1, 0x3f, 0x45, 0xd4, 0x4b, 0xe2, 0x00, 0x26, 0xa9, ++ 0x3e, 0xd7, 0xa5, 0x37, 0x9f, 0xf5, 0xad, 0x61, 0xe2, 0x40, 0xa9, 0x74, ++ 0x24, 0x53, 0xf2, 0x78, 0xeb, 0x10, 0x9b, 0x2c, 0x27, 0x88, 0x46, 0xcb, ++ 0xe4, 0x60, 0xca, 0xf5, 0x06, 0x24, 0x40, 0x2a, 0x97, 0x3a, 0xcc, 0xd0, ++ 0x81, 0xb1, 0x15, 0xa3, 0x4f, 0xd0, 0x2b, 0x4f, 0xca, 0x6e, 0xaa, 0x24, ++ 0x31, 0xb3, 0xac, 0xa6, 0x75, 0x05, 0xfe, 0x8a, 0xf4, 0x41, 0xc4, 0x06, ++ 0x8a, 0xc7, 0x0a, 0x83, 0x4e, 0x49, 0xd4, 0x3f, 0x83, 0x50, 0xec, 0x57, ++ 0x04, 0x97, 0x14, 0x49, 0xf5, 0xe1, 0xb1, 0x7a, 0x9c, 0x09, 0x4f, 0x61, ++ 0x87, 0xc3, 0x97, 0x22, 0x17, 0xc2, 0xeb, 0xcc, 0x32, 0x81, 0x31, 0x21, ++ 0x3f, 0x10, 0x57, 0x5b, 0x43, 0xbe, 0xcd, 0x68, 0x82, 0xbe, 0xe5, 0xc1, ++ 0x65, 0x94, 0x7e, 0xc2, 0x34, 0x76, 0x2b, 0xcf, 0x89, 0x3c, 0x2b, 0x81, ++ 0x23, 0x72, 0x95, 0xcf, 0xc9, 0x67, 0x19, 0x2a, 0xd5, 0x5c, 0xca, 0xa3, ++ 0x46, 0xbd, 0x48, 0x06, 0x0b, 0xa6, 0xa3, 0x96, 0x50, 0x28, 0xc7, 0x7e, ++ 0xcf, 0x62, 0xf2, 0xfa, 0xc4, 0xf2, 0x53, 0xe3, 0xc9, 0xe8, 0x2e, 0xdd, ++ 0x29, 0x37, 0x07, 0x47, 0xff, 0xff, 0x8a, 0x32, 0xbd, 0xa2, 0xb7, 0x21, ++ 0x89, 0xa0, 0x55, 0xf7 ++}; ++unsigned int certificate_eku_der_len = 916; +diff --git a/grub-core/tests/lib/functional_test.c b/grub-core/tests/lib/functional_test.c +index 96781fb39..403fa5c78 100644 +--- a/grub-core/tests/lib/functional_test.c ++++ b/grub-core/tests/lib/functional_test.c +@@ -73,6 +73,7 @@ grub_functional_all_tests (grub_extcmd_context_t ctxt __attribute__ ((unused)), + grub_dl_load ("xnu_uuid_test"); + grub_dl_load ("pbkdf2_test"); + grub_dl_load ("signature_test"); ++ grub_dl_load ("appended_signature_test"); + grub_dl_load ("sleep_test"); + grub_dl_load ("bswap_test"); + grub_dl_load ("ctz_test"); +-- +2.31.1 + diff --git a/0020-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch b/0020-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch new file mode 100644 index 0000000..449d23a --- /dev/null +++ b/0020-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch @@ -0,0 +1,73 @@ +From e33af61c202972c81aaccdd395d61855e1584f66 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 20 Dec 2021 21:55:43 +1100 +Subject: [PATCH 20/32] net/dns: Don't read past the end of the string we're + checking against + +I don't really understand what's going on here but fuzzing found +a bug where we read past the end of check_with. That's a C string, +so use grub_strlen() to make sure we don't overread it. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/net/dns.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c +index 135faac035..17961a9f18 100644 +--- a/grub-core/net/dns.c ++++ b/grub-core/net/dns.c +@@ -146,11 +146,18 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head, + int *length, char *set) + { + const char *readable_ptr = check_with; ++ int readable_len; + const grub_uint8_t *ptr; + char *optr = set; + int bytes_processed = 0; + if (length) + *length = 0; ++ ++ if (readable_ptr != NULL) ++ readable_len = grub_strlen (readable_ptr); ++ else ++ readable_len = 0; ++ + for (ptr = name_at; ptr < tail && bytes_processed < tail - head + 2; ) + { + /* End marker. */ +@@ -172,13 +179,16 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head, + ptr = head + (((ptr[0] & 0x3f) << 8) | ptr[1]); + continue; + } +- if (readable_ptr && grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0) ++ if (readable_ptr != NULL && (*ptr > readable_len || grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0)) + return 0; + if (grub_memchr (ptr + 1, 0, *ptr) + || grub_memchr (ptr + 1, '.', *ptr)) + return 0; + if (readable_ptr) +- readable_ptr += *ptr; ++ { ++ readable_ptr += *ptr; ++ readable_len -= *ptr; ++ } + if (readable_ptr && *readable_ptr != '.' && *readable_ptr != 0) + return 0; + bytes_processed += *ptr + 1; +@@ -192,7 +202,10 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head, + if (optr) + *optr++ = '.'; + if (readable_ptr && *readable_ptr) +- readable_ptr++; ++ { ++ readable_ptr++; ++ readable_len--; ++ } + ptr += *ptr + 1; + } + return 0; +-- +2.34.1 + diff --git a/0021-appended-signatures-documentation.patch b/0021-appended-signatures-documentation.patch new file mode 100644 index 0000000..99e3349 --- /dev/null +++ b/0021-appended-signatures-documentation.patch @@ -0,0 +1,342 @@ +From 4edb825a012e9e7b9ad08aa693cfdebf42ae40e6 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 1 Oct 2020 13:02:09 +1000 +Subject: [PATCH 21/23] appended signatures: documentation + +This explains how appended signatures can be used to form part of +a secure boot chain, and documents the commands and variables +introduced. + +Signed-off-by: Daniel Axtens + +--- + +v2: fix a grammar issue, thanks Stefan Berger. +--- + docs/grub.texi | 193 +++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 176 insertions(+), 17 deletions(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index dc1c58304..988ef8ddc 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -3209,6 +3209,7 @@ These variables have special meaning to GRUB. + + @menu + * biosnum:: ++* check_appended_signatures:: + * check_signatures:: + * chosen:: + * cmdpath:: +@@ -3268,11 +3269,18 @@ For an alternative approach which also changes BIOS drive mappings for the + chain-loaded system, @pxref{drivemap}. + + ++@node check_appended_signatures ++@subsection check_appended_signatures ++ ++This variable controls whether GRUB enforces appended signature validation on ++certain loaded files. @xref{Using appended signatures}. ++ ++ + @node check_signatures + @subsection check_signatures + +-This variable controls whether GRUB enforces digital signature +-validation on loaded files. @xref{Using digital signatures}. ++This variable controls whether GRUB enforces GPG-style digital signature ++validation on loaded files. @xref{Using GPG-style digital signatures}. + + @node chosen + @subsection chosen +@@ -3989,6 +3997,7 @@ you forget a command, you can run the command @command{help} + * date:: Display or set current date and time + * devicetree:: Load a device tree blob + * distrust:: Remove a pubkey from trusted keys ++* distrust_certificate:: Remove a certificate from the list of trusted certificates + * drivemap:: Map a drive to another + * echo:: Display a line of text + * eval:: Evaluate agruments as GRUB commands +@@ -4005,6 +4014,7 @@ you forget a command, you can run the command @command{help} + * keystatus:: Check key modifier status + * linux:: Load a Linux kernel + * linux16:: Load a Linux kernel (16-bit mode) ++* list_certificates:: List trusted certificates + * list_env:: List variables in environment block + * list_trusted:: List trusted public keys + * load_env:: Load variables from environment block +@@ -4042,8 +4052,10 @@ you forget a command, you can run the command @command{help} + * test:: Check file types and compare values + * true:: Do nothing, successfully + * trust:: Add public key to list of trusted keys ++* trust_certificate:: Add an x509 certificate to the list of trusted certificates + * unset:: Unset an environment variable + @comment * vbeinfo:: List available video modes ++* verify_appended:: Verify appended digital signature + * verify_detached:: Verify detached digital signature + * videoinfo:: List available video modes + @comment * xen_*:: Xen boot commands for AArch64 +@@ -4371,9 +4383,28 @@ These keys are used to validate signatures when environment variable + @code{check_signatures} is set to @code{enforce} + (@pxref{check_signatures}), and by some invocations of + @command{verify_detached} (@pxref{verify_detached}). @xref{Using +-digital signatures}, for more information. ++GPG-style digital signatures}, for more information. ++@end deffn ++ ++ ++@node distrust_certificate ++@subsection distrust_certificate ++ ++@deffn Command distrust_certificate cert_number ++Remove the x509 certificate numbered @var{cert_number} from GRUB's keyring of ++trusted x509 certificates for verifying appended signatures. ++ ++@var{cert_number} is the certificate number as listed by ++@command{list_certificates} (@pxref{list_certificates}). ++ ++These certificates are used to validate appended signatures when environment ++variable @code{check_appended_signatures} is set to @code{enforce} ++(@pxref{check_appended_signatures}), and by @command{verify_appended} ++(@pxref{verify_appended}). See @xref{Using appended signatures} for more ++information. + @end deffn + ++ + @node drivemap + @subsection drivemap + +@@ -4631,6 +4662,21 @@ This command is only available on x86 systems. + @end deffn + + ++@node list_certificates ++@subsection list_certificates ++ ++@deffn Command list_certificates ++List all x509 certificates trusted by GRUB for validating appended signatures. ++The output is a numbered list of certificates, showing the certificate's serial ++number and Common Name. ++ ++The certificate number can be used as an argument to ++@command{distrust_certificate} (@pxref{distrust_certificate}). ++ ++See @xref{Using appended signatures} for more information. ++@end deffn ++ ++ + @node list_env + @subsection list_env + +@@ -4650,7 +4696,7 @@ The output is in GPG's v4 key fingerprint format (i.e., the output of + @code{gpg --fingerprint}). The least significant four bytes (last + eight hexadecimal digits) can be used as an argument to + @command{distrust} (@pxref{distrust}). +-@xref{Using digital signatures}, for more information about uses for ++@xref{Using GPG-style digital signatures}, for more information about uses for + these keys. + @end deffn + +@@ -4685,8 +4731,12 @@ When used with care, @option{--skip-sig} and the whitelist enable an + administrator to configure a system to boot only signed + configurations, but to allow the user to select from among multiple + configurations, and to enable ``one-shot'' boot attempts and +-``savedefault'' behavior. @xref{Using digital signatures}, for more ++``savedefault'' behavior. @xref{Using GPG-style digital signatures}, for more + information. ++ ++Extra care should be taken when combining this command with appended signatures ++(@pxref{Using appended signatures}), as this file is not validated by an ++appended signature and could set @code{check_appended_signatures=no}. + @end deffn + + +@@ -4982,7 +5032,7 @@ read. It is possible to modify a digitally signed environment block + file from within GRUB using this command, such that its signature will + no longer be valid on subsequent boots. Care should be taken in such + advanced configurations to avoid rendering the system +-unbootable. @xref{Using digital signatures}, for more information. ++unbootable. @xref{Using GPG-style digital signatures}, for more information. + @end deffn + + +@@ -5382,11 +5432,31 @@ signatures when environment variable @code{check_signatures} is set to + must itself be properly signed. The @option{--skip-sig} option can be + used to disable signature-checking when reading @var{pubkey_file} + itself. It is expected that @option{--skip-sig} is useful for testing +-and manual booting. @xref{Using digital signatures}, for more ++and manual booting. @xref{Using GPG-style digital signatures}, for more + information. + @end deffn + + ++@node trust_certificate ++@subsection trust_certificate ++ ++@deffn Command trust_certificate x509_certificate ++Read a DER-formatted x509 certificate from the file @var{x509_certificate} ++and add it to GRUB's internal list of trusted x509 certificates. These ++certificates are used to validate appended signatures when the environment ++variable @code{check_appended_signatures} is set to @code{enforce}. ++ ++Note that if @code{check_appended_signatures} is set to @code{enforce} ++when @command{trust_certificate} is executed, then @var{x509_certificate} ++must itself bear an appended signature. (It is not sufficient that ++@var{x509_certificate} be signed by a trusted certificate according to the ++x509 rules: grub does not include support for validating signatures within x509 ++certificates themselves.) ++ ++See @xref{Using appended signatures} for more information. ++@end deffn ++ ++ + @node unset + @subsection unset + +@@ -5405,6 +5475,18 @@ only on PC BIOS platforms. + @end deffn + @end ignore + ++@node verify_appended ++@subsection verify_appended ++ ++@deffn Command verify_appended file ++Verifies an appended signature on @var{file} against the trusted certificates ++known to GRUB (See @pxref{list_certificates}, @pxref{trust_certificate}, and ++@pxref{distrust_certificate}). ++ ++Exit code @code{$?} is set to 0 if the signature validates ++successfully. If validation fails, it is set to a non-zero value. ++See @xref{Using appended signatures}, for more information. ++@end deffn + + @node verify_detached + @subsection verify_detached +@@ -5423,7 +5505,7 @@ tried. + + Exit code @code{$?} is set to 0 if the signature validates + successfully. If validation fails, it is set to a non-zero value. +-@xref{Using digital signatures}, for more information. ++@xref{Using GPG-style digital signatures}, for more information. + @end deffn + + @node videoinfo +@@ -5808,13 +5890,14 @@ environment variables and commands are listed in the same order. + @chapter Security + + @menu +-* Authentication and authorisation:: Users and access control +-* Using digital signatures:: Booting digitally signed code +-* UEFI secure boot and shim:: Booting digitally signed PE files +-* Secure Boot Advanced Targeting:: Embedded information for generation number based revocation +-* Measured Boot:: Measuring boot components +-* Lockdown:: Lockdown when booting on a secure setup +-* Signing GRUB itself:: Ensuring the integrity of the GRUB core image ++* Authentication and authorisation:: Users and access control ++* Using GPG-style digital signatures:: Booting digitally signed code ++* Using appended signatures:: An alternative approach to booting digitally signed code ++* UEFI secure boot and shim:: Booting digitally signed PE files ++* Secure Boot Advanced Targeting:: Embedded information for generation number based revocation ++* Measured Boot:: Measuring boot components ++* Lockdown:: Lockdown when booting on a secure setup ++* Signing GRUB itself:: Ensuring the integrity of the GRUB core image + @end menu + + @node Authentication and authorisation +@@ -5888,8 +5971,8 @@ generating configuration files with authentication. You can use + adding @kbd{set superusers=} and @kbd{password} or @kbd{password_pbkdf2} + commands. + +-@node Using digital signatures +-@section Using digital signatures in GRUB ++@node Using GPG-style digital signatures ++@section Using GPG-style digital signatures in GRUB + + GRUB's @file{core.img} can optionally provide enforcement that all files + subsequently read from disk are covered by a valid digital signature. +@@ -5972,6 +6055,82 @@ or BIOS) configuration to cause the machine to boot from a different + (attacker-controlled) device. GRUB is at best only one link in a + secure boot chain. + ++@node Using appended signatures ++@section Using appended signatures in GRUB ++ ++GRUB supports verifying Linux-style 'appended signatures' for secure boot. ++Appended signatures are PKCS#7 messages containing a signature over the ++contents of a file, plus some metadata, appended to the end of a file. A file ++with an appended signature ends with the magic string: ++ ++@example ++~Module signature appended~\n ++@end example ++ ++where @code{\n} represents the carriage-return character, @code{0x0a}. ++ ++To enable appended signature verification, load the appendedsig module and an ++x509 certificate for verification. Building the appendedsig module into the ++core grub image is recommended. ++ ++Certificates can be managed at boot time using the @pxref{trust_certificate}, ++@pxref{distrust_certificate} and @pxref{list_certificates} commands. ++Certificates can also be built in to the core image using the @code{--x509} ++parameter to @command{grub-install} or @command{grub-mkimage}. ++ ++A file can be explictly verified using the @pxref{verify_appended} command. ++ ++Only signatures made with the SHA-256 or SHA-512 hash algorithm are supported, ++and only RSA signatures are supported. ++ ++A file can be signed with the @command{sign-file} utility supplied with the ++Linux kernel source. For example, if you have @code{signing.key} as the private ++key and @code{certificate.der} as the x509 certificate containing the public key: ++ ++@example ++sign-file SHA256 signing.key certificate.der vmlinux vmlinux.signed ++@end example ++ ++Enforcement of signature verification is controlled by the ++@code{check_appended_signatures} variable. Verification will only take place ++when files are loaded if the variable is set to @code{enforce}. If a ++certificate is built into the grub core image with the @code{--x509} parameter, ++the variable will be automatically set to @code{enforce} when the appendedsig ++module is loaded. ++ ++Unlike GPG-style signatures, not all files loaded by GRUB are required to be ++signed. Once verification is turned on, the following file types must carry ++appended signatures: ++ ++@enumerate ++@item Linux, Multiboot, BSD, XNU and Plan9 kernels ++@item Grub modules, except those built in to the core image ++@item Any new certificate files to be trusted ++@end enumerate ++ ++ACPI tables and Device Tree images will not be checked for appended signatures ++but must be verified by another mechanism such as GPG-style signatures before ++they will be loaded. ++ ++No attempt is made to validate any other file type. In particular, ++chain-loaded binaries are not verified - if your platform supports ++chain-loading and this cannot be disabled, consider an alternative secure ++boot mechanism. ++ ++As with GPG-style appended signatures, signature checking does @strong{not} ++stop an attacker with console access from dropping manually to the GRUB ++console and executing: ++ ++@example ++set check_appended_signatures=no ++@end example ++ ++Refer to the section on password-protecting GRUB (@pxref{Authentication ++and authorisation}) for more information on preventing this. ++ ++Additionally, special care must be taken around the @command{loadenv} command, ++which can be used to turn off @code{check_appended_signature}. ++ + @node UEFI secure boot and shim + @section UEFI secure boot and shim support + +-- +2.31.1 + diff --git a/0021-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch b/0021-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch new file mode 100644 index 0000000..8424f1e --- /dev/null +++ b/0021-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch @@ -0,0 +1,115 @@ +From 4adbb12d15af04f8f279a6290cd0195e57cc9e69 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 20 Sep 2021 01:12:24 +1000 +Subject: [PATCH 21/32] net/tftp: Prevent a UAF and double-free from a failed + seek + +A malicious tftp server can cause UAFs and a double free. + +An attempt to read from a network file is handled by grub_net_fs_read(). If +the read is at an offset other than the current offset, grub_net_seek_real() +is invoked. + +In grub_net_seek_real(), if a backwards seek cannot be satisfied from the +currently received packets, and the underlying transport does not provide +a seek method, then grub_net_seek_real() will close and reopen the network +protocol layer. + +For tftp, the ->close() call goes to tftp_close() and frees the tftp_data_t +file->data. The file->data pointer is not nulled out after the free. + +If the ->open() call fails, the file->data will not be reallocated and will +continue point to a freed memory block. This could happen from a server +refusing to send the requisite ack to the new tftp request, for example. + +The seek and the read will then fail, but the grub_file continues to exist: +the failed seek does not necessarily cause the entire file to be thrown +away (e.g. where the file is checked to see if it is gzipped/lzio/xz/etc., +a read failure is interpreted as a decompressor passing on the file, not as +an invalidation of the entire grub_file_t structure). + +This means subsequent attempts to read or seek the file will use the old +file->data after free. Eventually, the file will be close()d again and +file->data will be freed again. + +Mark a net_fs file that doesn't reopen as broken. Do not permit read() or +close() on a broken file (seek is not exposed directly to the file API - +it is only called as part of read, so this blocks seeks as well). + +As an additional defence, null out the ->data pointer if tftp_open() fails. +That would have lead to a simple null pointer dereference rather than +a mess of UAFs. + +This may affect other protocols, I haven't checked. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/net/net.c | 11 +++++++++-- + grub-core/net/tftp.c | 1 + + include/grub/net.h | 1 + + 3 files changed, 11 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/net.c b/grub-core/net/net.c +index d11672fbee..b8238b7df1 100644 +--- a/grub-core/net/net.c ++++ b/grub-core/net/net.c +@@ -1546,7 +1546,8 @@ grub_net_fs_close (grub_file_t file) + grub_netbuff_free (file->device->net->packs.first->nb); + grub_net_remove_packet (file->device->net->packs.first); + } +- file->device->net->protocol->close (file); ++ if (!file->device->net->broken) ++ file->device->net->protocol->close (file); + grub_free (file->device->net->name); + return GRUB_ERR_NONE; + } +@@ -1768,7 +1769,10 @@ grub_net_seek_real (struct grub_file *file, grub_off_t offset) + file->device->net->stall = 0; + err = file->device->net->protocol->open (file, file->device->net->name); + if (err) +- return err; ++ { ++ file->device->net->broken = 1; ++ return err; ++ } + grub_net_fs_read_real (file, NULL, offset); + return grub_errno; + } +@@ -1777,6 +1781,9 @@ grub_net_seek_real (struct grub_file *file, grub_off_t offset) + static grub_ssize_t + grub_net_fs_read (grub_file_t file, char *buf, grub_size_t len) + { ++ if (file->device->net->broken) ++ return -1; ++ + if (file->offset != file->device->net->offset) + { + grub_err_t err; +diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c +index f3e7879388..d1afa25352 100644 +--- a/grub-core/net/tftp.c ++++ b/grub-core/net/tftp.c +@@ -404,6 +404,7 @@ tftp_open (struct grub_file *file, const char *filename) + { + grub_net_udp_close (data->sock); + grub_free (data); ++ file->data = NULL; + return grub_errno; + } + +diff --git a/include/grub/net.h b/include/grub/net.h +index cbcae79b1f..8d71ca6cc5 100644 +--- a/include/grub/net.h ++++ b/include/grub/net.h +@@ -277,6 +277,7 @@ typedef struct grub_net + grub_fs_t fs; + int eof; + int stall; ++ int broken; + } *grub_net_t; + + extern grub_net_t (*EXPORT_VAR (grub_net_open)) (const char *name); +-- +2.34.1 + diff --git a/0022-ieee1275-enter-lockdown-based-on-ibm-secure-boot.patch b/0022-ieee1275-enter-lockdown-based-on-ibm-secure-boot.patch new file mode 100644 index 0000000..ee7869f --- /dev/null +++ b/0022-ieee1275-enter-lockdown-based-on-ibm-secure-boot.patch @@ -0,0 +1,112 @@ +From 806bb18c3493537530b6b0387143752478078f5b Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 28 Sep 2020 11:11:17 +1000 +Subject: [PATCH 22/23] ieee1275: enter lockdown based on /ibm,secure-boot + +If the 'ibm,secure-boot' property of the root node is 2 or greater, +enter lockdown. + +Signed-off-by: Daniel Axtens +--- + docs/grub.texi | 4 ++-- + grub-core/Makefile.core.def | 1 + + grub-core/kern/ieee1275/init.c | 27 +++++++++++++++++++++++++++ + include/grub/lockdown.h | 3 ++- + 4 files changed, 32 insertions(+), 3 deletions(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index 988ef8ddc..f4794fdda 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -6208,8 +6208,8 @@ Measured boot is currently only supported on EFI platforms. + @section Lockdown when booting on a secure setup + + The GRUB can be locked down when booted on a secure boot environment, for example +-if the UEFI secure boot is enabled. On a locked down configuration, the GRUB will +-be restricted and some operations/commands cannot be executed. ++if UEFI or Power secure boot is enabled. On a locked down configuration, the ++GRUB will be restricted and some operations/commands cannot be executed. + + The @samp{lockdown} variable is set to @samp{y} when the GRUB is locked down. + Otherwise it does not exit. +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 88eedd16d..49bdb63b6 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -317,6 +317,7 @@ kernel = { + powerpc_ieee1275 = kern/powerpc/cache.S; + powerpc_ieee1275 = kern/powerpc/dl.c; + powerpc_ieee1275 = kern/powerpc/compiler-rt.S; ++ powerpc_ieee1275 = kern/lockdown.c; + + sparc64_ieee1275 = kern/sparc64/cache.S; + sparc64_ieee1275 = kern/sparc64/dl.c; +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index 446201165..d77d89604 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -44,6 +44,7 @@ + #ifdef __sparc__ + #include + #endif ++#include + + /* The maximum heap size we're going to claim. Not used by sparc. + We allocate 1/4 of the available memory under 4G, up to this limit. */ +@@ -440,6 +441,30 @@ grub_parse_cmdline (void) + } + } + ++static void ++grub_get_ieee1275_secure_boot (void) ++{ ++ grub_ieee1275_phandle_t root; ++ int rc; ++ grub_uint32_t is_sb; ++ ++ grub_ieee1275_finddevice ("/", &root); ++ ++ rc = grub_ieee1275_get_integer_property (root, "ibm,secure-boot", &is_sb, ++ sizeof (is_sb), 0); ++ ++ /* ibm,secure-boot: ++ * 0 - disabled ++ * 1 - audit ++ * 2 - enforce ++ * 3 - enforce + OS-specific behaviour ++ * ++ * We only support enforce. ++ */ ++ if (rc >= 0 && is_sb >= 2) ++ grub_lockdown (); ++} ++ + grub_addr_t grub_modbase; + + void +@@ -465,6 +490,8 @@ grub_machine_init (void) + #else + grub_install_get_time_ms (grub_rtc_get_time_ms); + #endif ++ ++ grub_get_ieee1275_secure_boot (); + } + + void +diff --git a/include/grub/lockdown.h b/include/grub/lockdown.h +index 40531fa82..ebfee4bf0 100644 +--- a/include/grub/lockdown.h ++++ b/include/grub/lockdown.h +@@ -24,7 +24,8 @@ + #define GRUB_LOCKDOWN_DISABLED 0 + #define GRUB_LOCKDOWN_ENABLED 1 + +-#ifdef GRUB_MACHINE_EFI ++#if defined(GRUB_MACHINE_EFI) || \ ++ (defined(__powerpc__) && defined(GRUB_MACHINE_IEEE1275)) + extern void + EXPORT_FUNC (grub_lockdown) (void); + extern int +-- +2.31.1 + diff --git a/0022-net-tftp-Avoid-a-trivial-UAF.patch b/0022-net-tftp-Avoid-a-trivial-UAF.patch new file mode 100644 index 0000000..3fec1d4 --- /dev/null +++ b/0022-net-tftp-Avoid-a-trivial-UAF.patch @@ -0,0 +1,37 @@ +From 1824df76e0e712917edce83b5be57d485b81a5a7 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 18 Jan 2022 14:29:20 +1100 +Subject: [PATCH 22/32] net/tftp: Avoid a trivial UAF + +Under tftp errors, we print a tftp error message from the tftp header. +However, the tftph pointer is a pointer inside nb, the netbuff. Previously, +we were freeing the nb and then dereferencing it. Don't do that, use it +and then free it later. + +This isn't really _bad_ per se, especially as we're single-threaded, but +it trips up fuzzers. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/net/tftp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c +index d1afa25352..4222d93b6d 100644 +--- a/grub-core/net/tftp.c ++++ b/grub-core/net/tftp.c +@@ -251,9 +251,9 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)), + return GRUB_ERR_NONE; + case TFTP_ERROR: + data->have_oack = 1; +- grub_netbuff_free (nb); + grub_error (GRUB_ERR_IO, "%s", tftph->u.err.errmsg); + grub_error_save (&data->save_err); ++ grub_netbuff_free (nb); + return GRUB_ERR_NONE; + default: + grub_netbuff_free (nb); +-- +2.34.1 + diff --git a/0023-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch b/0023-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch new file mode 100644 index 0000000..f2e3baf --- /dev/null +++ b/0023-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch @@ -0,0 +1,44 @@ +From 7ec48289eeae517e14e2c957a90fd95a49741894 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 1 Mar 2022 23:14:15 +1100 +Subject: [PATCH 23/32] net/http: Do not tear down socket if it's already been + torn down + +It's possible for data->sock to get torn down in tcp error handling. +If we unconditionally tear it down again we will end up doing writes +to an offset of the NULL pointer when we go to tear it down again. + +Detect if it has been torn down and don't do it again. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/net/http.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/http.c b/grub-core/net/http.c +index bf838660d9..a77bc4e4b8 100644 +--- a/grub-core/net/http.c ++++ b/grub-core/net/http.c +@@ -425,7 +425,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) + return err; + } + +- for (i = 0; !data->headers_recv && i < 100; i++) ++ for (i = 0; data->sock && !data->headers_recv && i < 100; i++) + { + grub_net_tcp_retransmit (); + grub_net_poll_cards (300, &data->headers_recv); +@@ -433,7 +433,8 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) + + if (!data->headers_recv) + { +- grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT); ++ if (data->sock) ++ grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT); + if (data->err) + { + char *str = data->errmsg; +-- +2.34.1 + diff --git a/0023-x509-allow-Digitial-Signature-plus-other-Key-Usages.patch b/0023-x509-allow-Digitial-Signature-plus-other-Key-Usages.patch new file mode 100644 index 0000000..c335b3b --- /dev/null +++ b/0023-x509-allow-Digitial-Signature-plus-other-Key-Usages.patch @@ -0,0 +1,48 @@ +From 5a690183091c2c161481123b17e1925148e516e4 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 30 Nov 2021 15:00:57 +1100 +Subject: [PATCH 23/23] x509: allow Digitial Signature plus other Key Usages + +Currently the x509 certificate parser for appended signature +verification requires that the certificate have the Digitial Signature +key usage and _only_ the Digitial Signature use. This is overly strict +and becomes policy enforcement rather than a security property. + +Require that the Digitial Signature usage is present, but do not +require that it is the only usage present. + +Reported-by: Michal Suchanek +Signed-off-by: Daniel Axtens +--- + grub-core/commands/appendedsig/x509.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/grub-core/commands/appendedsig/x509.c b/grub-core/commands/appendedsig/x509.c +index 70480aa73..6ae985b30 100644 +--- a/grub-core/commands/appendedsig/x509.c ++++ b/grub-core/commands/appendedsig/x509.c +@@ -547,7 +547,7 @@ cleanup: + + /* + * Verify the Key Usage extension. +- * We only permit the Digital signature usage. ++ * We require the Digital signature usage. + */ + static grub_err_t + verify_key_usage (grub_uint8_t *value, int value_size) +@@ -586,10 +586,10 @@ verify_key_usage (grub_uint8_t *value, int value_size) + goto cleanup; + } + +- if (usage != digitalSignatureUsage) ++ if (!(usage & digitalSignatureUsage)) + { + err = +- grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected Key Usage value: %x", ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, "Key Usage (0x%x) missing Digital Signature usage", + usage); + goto cleanup; + } +-- +2.31.1 + diff --git a/0024-net-http-Fix-OOB-write-for-split-http-headers.patch b/0024-net-http-Fix-OOB-write-for-split-http-headers.patch new file mode 100644 index 0000000..b9b615a --- /dev/null +++ b/0024-net-http-Fix-OOB-write-for-split-http-headers.patch @@ -0,0 +1,48 @@ +From d7374ab1a110a7ddcfa5a0eda9574ebef2220ee1 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 8 Mar 2022 18:17:03 +1100 +Subject: [PATCH 24/32] net/http: Fix OOB write for split http headers + +GRUB has special code for handling an http header that is split +across two packets. + +The code tracks the end of line by looking for a "\n" byte. The +code for split headers has always advanced the pointer just past the +end of the line, whereas the code that handles unsplit headers does +not advance the pointer. This extra advance causes the length to be +one greater, which breaks an assumption in parse_line(), leading to +it writing a NUL byte one byte past the end of the buffer where we +reconstruct the line from the two packets. + +It's conceivable that an attacker controlled set of packets could +cause this to zero out the first byte of the "next" pointer of the +grub_mm_region structure following the current_line buffer. + +Do not advance the pointer in the split header case. + +Fixes: CVE-2022-28734 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/net/http.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/grub-core/net/http.c b/grub-core/net/http.c +index a77bc4e4b8..d9d2ade98e 100644 +--- a/grub-core/net/http.c ++++ b/grub-core/net/http.c +@@ -193,9 +193,7 @@ http_receive (grub_net_tcp_socket_t sock __attribute__ ((unused)), + int have_line = 1; + char *t; + ptr = grub_memchr (nb->data, '\n', nb->tail - nb->data); +- if (ptr) +- ptr++; +- else ++ if (ptr == NULL) + { + have_line = 0; + ptr = (char *) nb->tail; +-- +2.34.1 + diff --git a/0025-net-http-Error-out-on-headers-with-LF-without-CR.patch b/0025-net-http-Error-out-on-headers-with-LF-without-CR.patch new file mode 100644 index 0000000..a12505a --- /dev/null +++ b/0025-net-http-Error-out-on-headers-with-LF-without-CR.patch @@ -0,0 +1,50 @@ +From 5a6ca6483123f2290696e7268f875ff72dd841b6 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 8 Mar 2022 19:04:40 +1100 +Subject: [PATCH 25/32] net/http: Error out on headers with LF without CR + +In a similar vein to the previous patch, parse_line() would write +a NUL byte past the end of the buffer if there was an HTTP header +with a LF rather than a CRLF. + +RFC-2616 says: + + Many HTTP/1.1 header field values consist of words separated by LWS + or special characters. These special characters MUST be in a quoted + string to be used within a parameter value (as defined in section 3.6). + +We don't support quoted sections or continuation lines, etc. + +If we see an LF that's not part of a CRLF, bail out. + +Fixes: CVE-2022-28734 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/net/http.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/grub-core/net/http.c b/grub-core/net/http.c +index d9d2ade98e..0472645d12 100644 +--- a/grub-core/net/http.c ++++ b/grub-core/net/http.c +@@ -69,7 +69,15 @@ parse_line (grub_file_t file, http_data_t data, char *ptr, grub_size_t len) + char *end = ptr + len; + while (end > ptr && *(end - 1) == '\r') + end--; ++ ++ /* LF without CR. */ ++ if (end == ptr + len) ++ { ++ data->errmsg = grub_strdup (_("invalid HTTP header - LF without CR")); ++ return GRUB_ERR_NONE; ++ } + *end = 0; ++ + /* Trailing CRLF. */ + if (data->in_chunk_len == 1) + { +-- +2.34.1 + diff --git a/0026-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch b/0026-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch new file mode 100644 index 0000000..f91a9ce --- /dev/null +++ b/0026-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch @@ -0,0 +1,75 @@ +From c1013c295f1e32620db302470f126df0c6a0d5a5 Mon Sep 17 00:00:00 2001 +From: Sudhakar Kuppusamy +Date: Wed, 6 Apr 2022 18:03:37 +0530 +Subject: [PATCH 26/32] fs/f2fs: Do not read past the end of nat journal + entries + +A corrupt f2fs file system could specify a nat journal entry count +that is beyond the maximum NAT_JOURNAL_ENTRIES. + +Check if the specified nat journal entry count before accessing the +array, and throw an error if it is too large. + +Signed-off-by: Sudhakar Kuppusamy +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/fs/f2fs.c | 21 ++++++++++++++------- + 1 file changed, 14 insertions(+), 7 deletions(-) + +diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c +index 8a9992ca9e..63702214b0 100644 +--- a/grub-core/fs/f2fs.c ++++ b/grub-core/fs/f2fs.c +@@ -632,23 +632,27 @@ get_nat_journal (struct grub_f2fs_data *data) + return err; + } + +-static grub_uint32_t +-get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid) ++static grub_err_t ++get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid, ++ grub_uint32_t *blkaddr) + { + grub_uint16_t n = grub_le_to_cpu16 (data->nat_j.n_nats); +- grub_uint32_t blkaddr = 0; + grub_uint16_t i; + ++ if (n >= NAT_JOURNAL_ENTRIES) ++ return grub_error (GRUB_ERR_BAD_FS, ++ "invalid number of nat journal entries"); ++ + for (i = 0; i < n; i++) + { + if (grub_le_to_cpu32 (data->nat_j.entries[i].nid) == nid) + { +- blkaddr = grub_le_to_cpu32 (data->nat_j.entries[i].ne.block_addr); ++ *blkaddr = grub_le_to_cpu32 (data->nat_j.entries[i].ne.block_addr); + break; + } + } + +- return blkaddr; ++ return GRUB_ERR_NONE; + } + + static grub_uint32_t +@@ -656,10 +660,13 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid) + { + struct grub_f2fs_nat_block *nat_block; + grub_uint32_t seg_off, block_off, entry_off, block_addr; +- grub_uint32_t blkaddr; ++ grub_uint32_t blkaddr = 0; + grub_err_t err; + +- blkaddr = get_blkaddr_from_nat_journal (data, nid); ++ err = get_blkaddr_from_nat_journal (data, nid, &blkaddr); ++ if (err != GRUB_ERR_NONE) ++ return 0; ++ + if (blkaddr) + return blkaddr; + +-- +2.34.1 + diff --git a/0027-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch b/0027-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch new file mode 100644 index 0000000..a15e1b9 --- /dev/null +++ b/0027-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch @@ -0,0 +1,134 @@ +From 5ac885d02a9e91a5d6760090f90fa2bb4e7a5dd6 Mon Sep 17 00:00:00 2001 +From: Sudhakar Kuppusamy +Date: Wed, 6 Apr 2022 18:49:09 +0530 +Subject: [PATCH 27/32] fs/f2fs: Do not read past the end of nat bitmap + +A corrupt f2fs filesystem could have a block offset or a bitmap +offset that would cause us to read beyond the bounds of the nat +bitmap. + +Introduce the nat_bitmap_size member in grub_f2fs_data which holds +the size of nat bitmap. + +Set the size when loading the nat bitmap in nat_bitmap_ptr(), and +catch when an invalid offset would create a pointer past the end of +the allocated space. + +Check against the bitmap size in grub_f2fs_test_bit() test bit to avoid +reading past the end of the nat bitmap. + +Signed-off-by: Sudhakar Kuppusamy +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/fs/f2fs.c | 33 +++++++++++++++++++++++++++------ + 1 file changed, 27 insertions(+), 6 deletions(-) + +diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c +index 63702214b0..8898b235e0 100644 +--- a/grub-core/fs/f2fs.c ++++ b/grub-core/fs/f2fs.c +@@ -122,6 +122,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); + #define F2FS_INLINE_DOTS 0x10 /* File having implicit dot dentries. */ + + #define MAX_VOLUME_NAME 512 ++#define MAX_NAT_BITMAP_SIZE 3900 + + enum FILE_TYPE + { +@@ -183,7 +184,7 @@ struct grub_f2fs_checkpoint + grub_uint32_t checksum_offset; + grub_uint64_t elapsed_time; + grub_uint8_t alloc_type[MAX_ACTIVE_LOGS]; +- grub_uint8_t sit_nat_version_bitmap[3900]; ++ grub_uint8_t sit_nat_version_bitmap[MAX_NAT_BITMAP_SIZE]; + grub_uint32_t checksum; + } GRUB_PACKED; + +@@ -302,6 +303,7 @@ struct grub_f2fs_data + + struct grub_f2fs_nat_journal nat_j; + char *nat_bitmap; ++ grub_uint32_t nat_bitmap_size; + + grub_disk_t disk; + struct grub_f2fs_node *inode; +@@ -377,15 +379,20 @@ sum_blk_addr (struct grub_f2fs_data *data, int base, int type) + } + + static void * +-nat_bitmap_ptr (struct grub_f2fs_data *data) ++nat_bitmap_ptr (struct grub_f2fs_data *data, grub_uint32_t *nat_bitmap_size) + { + struct grub_f2fs_checkpoint *ckpt = &data->ckpt; + grub_uint32_t offset; ++ *nat_bitmap_size = MAX_NAT_BITMAP_SIZE; + + if (grub_le_to_cpu32 (data->sblock.cp_payload) > 0) + return ckpt->sit_nat_version_bitmap; + + offset = grub_le_to_cpu32 (ckpt->sit_ver_bitmap_bytesize); ++ if (offset >= MAX_NAT_BITMAP_SIZE) ++ return NULL; ++ ++ *nat_bitmap_size = *nat_bitmap_size - offset; + + return ckpt->sit_nat_version_bitmap + offset; + } +@@ -438,11 +445,15 @@ grub_f2fs_crc_valid (grub_uint32_t blk_crc, void *buf, const grub_uint32_t len) + } + + static int +-grub_f2fs_test_bit (grub_uint32_t nr, const char *p) ++grub_f2fs_test_bit (grub_uint32_t nr, const char *p, grub_uint32_t len) + { + int mask; ++ grub_uint32_t shifted_nr = (nr >> 3); ++ ++ if (shifted_nr >= len) ++ return -1; + +- p += (nr >> 3); ++ p += shifted_nr; + mask = 1 << (7 - (nr & 0x07)); + + return mask & *p; +@@ -662,6 +673,7 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid) + grub_uint32_t seg_off, block_off, entry_off, block_addr; + grub_uint32_t blkaddr = 0; + grub_err_t err; ++ int result_bit; + + err = get_blkaddr_from_nat_journal (data, nid, &blkaddr); + if (err != GRUB_ERR_NONE) +@@ -682,8 +694,15 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid) + ((seg_off * data->blocks_per_seg) << 1) + + (block_off & (data->blocks_per_seg - 1)); + +- if (grub_f2fs_test_bit (block_off, data->nat_bitmap)) ++ result_bit = grub_f2fs_test_bit (block_off, data->nat_bitmap, ++ data->nat_bitmap_size); ++ if (result_bit > 0) + block_addr += data->blocks_per_seg; ++ else if (result_bit == -1) ++ { ++ grub_free (nat_block); ++ return 0; ++ } + + err = grub_f2fs_block_read (data, block_addr, nat_block); + if (err) +@@ -833,7 +852,9 @@ grub_f2fs_mount (grub_disk_t disk) + if (err) + goto fail; + +- data->nat_bitmap = nat_bitmap_ptr (data); ++ data->nat_bitmap = nat_bitmap_ptr (data, &data->nat_bitmap_size); ++ if (data->nat_bitmap == NULL) ++ goto fail; + + err = get_nat_journal (data); + if (err) +-- +2.34.1 + diff --git a/0028-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch b/0028-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch new file mode 100644 index 0000000..3734994 --- /dev/null +++ b/0028-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch @@ -0,0 +1,40 @@ +From 315e2773ed5cae92548d4508301ac0fe7515e5bb Mon Sep 17 00:00:00 2001 +From: Sudhakar Kuppusamy +Date: Wed, 6 Apr 2022 18:17:43 +0530 +Subject: [PATCH 28/32] fs/f2fs: Do not copy file names that are too long + +A corrupt f2fs file system might specify a name length which is greater +than the maximum name length supported by the GRUB f2fs driver. + +We will allocate enough memory to store the overly long name, but there +are only F2FS_NAME_LEN bytes in the source, so we would read past the end +of the source. + +While checking directory entries, do not copy a file name with an invalid +length. + +Signed-off-by: Sudhakar Kuppusamy +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/fs/f2fs.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c +index 8898b235e0..df6beb544c 100644 +--- a/grub-core/fs/f2fs.c ++++ b/grub-core/fs/f2fs.c +@@ -1003,6 +1003,10 @@ grub_f2fs_check_dentries (struct grub_f2fs_dir_iter_ctx *ctx) + + ftype = ctx->dentry[i].file_type; + name_len = grub_le_to_cpu16 (ctx->dentry[i].name_len); ++ ++ if (name_len >= F2FS_NAME_LEN) ++ return 0; ++ + filename = grub_malloc (name_len + 1); + if (!filename) + return 0; +-- +2.34.1 + diff --git a/0029-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch b/0029-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch new file mode 100644 index 0000000..5032186 --- /dev/null +++ b/0029-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch @@ -0,0 +1,79 @@ +From c64e0158654a1098caf652f6ffd192cbe26583f3 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Tue, 29 Mar 2022 10:49:56 +0000 +Subject: [PATCH 29/32] fs/btrfs: Fix several fuzz issues with invalid dir item + sizing + +According to the btrfs code in Linux, the structure of a directory item +leaf should be of the form: + + |struct btrfs_dir_item|name|data| + +in GRUB the name len and data len are in the grub_btrfs_dir_item +structure's n and m fields respectively. + +The combined size of the structure, name and data should be less than +the allocated memory, a difference to the Linux kernel's struct +btrfs_dir_item is that the grub_btrfs_dir_item has an extra field for +where the name is stored, so we adjust for that too. + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/fs/btrfs.c | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index 42fdbaf616..626fd2daa0 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -2210,6 +2210,7 @@ grub_btrfs_dir (grub_device_t device, const char *path, + grub_uint64_t tree; + grub_uint8_t type; + char *new_path = NULL; ++ grub_size_t est_size = 0; + + if (!data) + return grub_errno; +@@ -2276,6 +2277,18 @@ grub_btrfs_dir (grub_device_t device, const char *path, + break; + } + ++ if (direl == NULL || ++ grub_add (grub_le_to_cpu16 (direl->n), ++ grub_le_to_cpu16 (direl->m), &est_size) || ++ grub_add (est_size, sizeof (*direl), &est_size) || ++ grub_sub (est_size, sizeof (direl->name), &est_size) || ++ est_size > allocated) ++ { ++ grub_errno = GRUB_ERR_OUT_OF_RANGE; ++ r = -grub_errno; ++ goto out; ++ } ++ + for (cdirel = direl; + (grub_uint8_t *) cdirel - (grub_uint8_t *) direl + < (grub_ssize_t) elemsize; +@@ -2286,6 +2299,19 @@ grub_btrfs_dir (grub_device_t device, const char *path, + char c; + struct grub_btrfs_inode inode; + struct grub_dirhook_info info; ++ ++ if (cdirel == NULL || ++ grub_add (grub_le_to_cpu16 (cdirel->n), ++ grub_le_to_cpu16 (cdirel->m), &est_size) || ++ grub_add (est_size, sizeof (*cdirel), &est_size) || ++ grub_sub (est_size, sizeof (cdirel->name), &est_size) || ++ est_size > allocated) ++ { ++ grub_errno = GRUB_ERR_OUT_OF_RANGE; ++ r = -grub_errno; ++ goto out; ++ } ++ + err = grub_btrfs_read_inode (data, &inode, cdirel->key.object_id, + tree); + grub_memset (&info, 0, sizeof (info)); +-- +2.34.1 + diff --git a/0030-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch b/0030-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch new file mode 100644 index 0000000..1d1fe6b --- /dev/null +++ b/0030-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch @@ -0,0 +1,137 @@ +From 2576115cc77c45d2a77d7629b8c2f26a3a58822b Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Tue, 29 Mar 2022 15:52:46 +0000 +Subject: [PATCH 30/32] fs/btrfs: Fix more ASAN and SEGV issues found with + fuzzing + +The fuzzer is generating btrfs file systems that have chunks with +invalid combinations of stripes and substripes for the given RAID +configurations. + +After examining the Linux kernel fs/btrfs/tree-checker.c code, it +appears that sub-stripes should only be applied to RAID10, and in that +case there should only ever be 2 of them. + +Similarly, RAID single should only have 1 stripe, and RAID1/1C3/1C4 +should have 2. 3 or 4 stripes respectively, which is what redundancy +corresponds. + +Some of the chunks ended up with a size of 0, which grub_malloc() still +returned memory for and in turn generated ASAN errors later when +accessed. + +While it would be possible to specifically limit the number of stripes, +a more correct test was on the combination of the chunk item, and the +number of stripes by the size of the chunk stripe structure in +comparison to the size of the chunk itself. + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/fs/btrfs.c | 55 ++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 55 insertions(+) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index 626fd2daa0..62fe5e6a69 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -938,6 +938,12 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + return grub_error (GRUB_ERR_BAD_FS, + "couldn't find the chunk descriptor"); + ++ if (!chsize) ++ { ++ grub_dprintf ("btrfs", "zero-size chunk\n"); ++ return grub_error (GRUB_ERR_BAD_FS, ++ "got an invalid zero-size chunk"); ++ } + chunk = grub_malloc (chsize); + if (!chunk) + return grub_errno; +@@ -996,6 +1002,16 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + stripe_length = grub_divmod64 (grub_le_to_cpu64 (chunk->size), + nstripes, + NULL); ++ ++ /* For single, there should be exactly 1 stripe. */ ++ if (grub_le_to_cpu16 (chunk->nstripes) != 1) ++ { ++ grub_dprintf ("btrfs", "invalid RAID_SINGLE: nstripes != 1 (%u)\n", ++ grub_le_to_cpu16 (chunk->nstripes)); ++ return grub_error (GRUB_ERR_BAD_FS, ++ "invalid RAID_SINGLE: nstripes != 1 (%u)", ++ grub_le_to_cpu16 (chunk->nstripes)); ++ } + if (stripe_length == 0) + stripe_length = 512; + stripen = grub_divmod64 (off, stripe_length, &stripe_offset); +@@ -1015,6 +1031,19 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + stripen = 0; + stripe_offset = off; + csize = grub_le_to_cpu64 (chunk->size) - off; ++ ++ /* ++ * Redundancy, and substripes only apply to RAID10, and there ++ * should be exactly 2 sub-stripes. ++ */ ++ if (grub_le_to_cpu16 (chunk->nstripes) != redundancy) ++ { ++ grub_dprintf ("btrfs", "invalid RAID1: nstripes != %u (%u)\n", ++ redundancy, grub_le_to_cpu16 (chunk->nstripes)); ++ return grub_error (GRUB_ERR_BAD_FS, ++ "invalid RAID1: nstripes != %u (%u)", ++ redundancy, grub_le_to_cpu16 (chunk->nstripes)); ++ } + break; + } + case GRUB_BTRFS_CHUNK_TYPE_RAID0: +@@ -1051,6 +1080,20 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + stripe_offset = low + chunk_stripe_length + * high; + csize = chunk_stripe_length - low; ++ ++ /* ++ * Substripes only apply to RAID10, and there ++ * should be exactly 2 sub-stripes. ++ */ ++ if (grub_le_to_cpu16 (chunk->nsubstripes) != 2) ++ { ++ grub_dprintf ("btrfs", "invalid RAID10: nsubstripes != 2 (%u)", ++ grub_le_to_cpu16 (chunk->nsubstripes)); ++ return grub_error (GRUB_ERR_BAD_FS, ++ "invalid RAID10: nsubstripes != 2 (%u)", ++ grub_le_to_cpu16 (chunk->nsubstripes)); ++ } ++ + break; + } + case GRUB_BTRFS_CHUNK_TYPE_RAID5: +@@ -1150,6 +1193,8 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + + for (j = 0; j < 2; j++) + { ++ grub_size_t est_chunk_alloc = 0; ++ + grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T + "+0x%" PRIxGRUB_UINT64_T + " (%d stripes (%d substripes) of %" +@@ -1162,6 +1207,16 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + grub_dprintf ("btrfs", "reading laddr 0x%" PRIxGRUB_UINT64_T "\n", + addr); + ++ if (grub_mul (sizeof (struct grub_btrfs_chunk_stripe), ++ grub_le_to_cpu16 (chunk->nstripes), &est_chunk_alloc) || ++ grub_add (est_chunk_alloc, ++ sizeof (struct grub_btrfs_chunk_item), &est_chunk_alloc) || ++ est_chunk_alloc > chunk->size) ++ { ++ err = GRUB_ERR_BAD_FS; ++ break; ++ } ++ + if (is_raid56) + { + err = btrfs_read_from_chunk (data, chunk, stripen, +-- +2.34.1 + diff --git a/0031-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch b/0031-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch new file mode 100644 index 0000000..a65eda2 --- /dev/null +++ b/0031-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch @@ -0,0 +1,78 @@ +From 480019e546386b8e25a26d03408897a7752b98b6 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Thu, 7 Apr 2022 15:18:12 +0000 +Subject: [PATCH 31/32] fs/btrfs: Fix more fuzz issues related to chunks + +The corpus was generating issues in grub_btrfs_read_logical() when +attempting to iterate over stripe entries in the superblock's +bootmapping. + +In most cases the reason for the failure was that the number of stripes +in chunk->nstripes exceeded the possible space statically allocated in +superblock bootmapping space. Each stripe entry in the bootmapping block +consists of a grub_btrfs_key followed by a grub_btrfs_chunk_stripe. + +Another issue that came up was that while calculating the chunk size, +in an earlier piece of code in that function, depending on the data +provided in the btrfs file system, it would end up calculating a size +that was too small to contain even 1 grub_btrfs_chunk_item, which is +obviously invalid too. + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/fs/btrfs.c | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index 62fe5e6a69..7007463c6e 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -944,6 +944,17 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + return grub_error (GRUB_ERR_BAD_FS, + "got an invalid zero-size chunk"); + } ++ ++ /* ++ * The space being allocated for a chunk should at least be able to ++ * contain one chunk item. ++ */ ++ if (chsize < sizeof (struct grub_btrfs_chunk_item)) ++ { ++ grub_dprintf ("btrfs", "chunk-size too small\n"); ++ return grub_error (GRUB_ERR_BAD_FS, ++ "got an invalid chunk size"); ++ } + chunk = grub_malloc (chsize); + if (!chunk) + return grub_errno; +@@ -1191,6 +1202,13 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + if (csize > (grub_uint64_t) size) + csize = size; + ++ /* ++ * The space for a chunk stripe is limited to the space provide in the super-block's ++ * bootstrap mapping with an initial btrfs key at the start of each chunk. ++ */ ++ grub_size_t avail_stripes = sizeof (data->sblock.bootstrap_mapping) / ++ (sizeof (struct grub_btrfs_key) + sizeof (struct grub_btrfs_chunk_stripe)); ++ + for (j = 0; j < 2; j++) + { + grub_size_t est_chunk_alloc = 0; +@@ -1217,6 +1235,12 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + break; + } + ++ if (grub_le_to_cpu16 (chunk->nstripes) > avail_stripes) ++ { ++ err = GRUB_ERR_BAD_FS; ++ break; ++ } ++ + if (is_raid56) + { + err = btrfs_read_from_chunk (data, chunk, stripen, +-- +2.34.1 + diff --git a/0032-Use-grub_loader_set_ex-for-secureboot-chainloader.patch b/0032-Use-grub_loader_set_ex-for-secureboot-chainloader.patch new file mode 100644 index 0000000..d3fee3e --- /dev/null +++ b/0032-Use-grub_loader_set_ex-for-secureboot-chainloader.patch @@ -0,0 +1,261 @@ +From 836337d9b895da32bcbc451c84bc3a7865a15963 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Mon, 18 Apr 2022 22:16:49 +0800 +Subject: [PATCH 32/32] Use grub_loader_set_ex() for secureboot chainloader + +This is required as many distributions, including SUSE, has been +shipping a variation to load and start image using native functions than +calling out efi protocols when secure boot is enabled and shim lock is +used to verify image. + +Signed-off-by: Michael Chang +--- + grub-core/loader/efi/chainloader.c | 100 +++++++++++++++++++---------- + 1 file changed, 66 insertions(+), 34 deletions(-) + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index b3e1e89302..48d69c7795 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -53,10 +53,6 @@ GRUB_MOD_LICENSE ("GPLv3+"); + + static grub_dl_t my_mod; + +-static grub_ssize_t fsize; +-static grub_ssize_t cmdline_len; +-static grub_efi_handle_t dev_handle; +- + #ifdef SUPPORT_SECURE_BOOT + static grub_efi_boolean_t debug_secureboot = 0; + static grub_efi_status_t (*entry_point) (grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table); +@@ -76,8 +72,6 @@ grub_chainloader_unload (void *context) + b = grub_efi_system_table->boot_services; + efi_call_1 (b->unload_image, image_handle); + +- dev_handle = 0; +- + grub_dl_unref (my_mod); + return GRUB_ERR_NONE; + } +@@ -254,6 +248,17 @@ struct pe_coff_loader_image_context + struct grub_pe32_header_no_msdos_stub *pe_hdr; + }; + ++struct grub_secureboot_chainloader_context ++{ ++ grub_efi_physical_address_t address; ++ grub_efi_uintn_t pages; ++ grub_ssize_t fsize; ++ grub_efi_device_path_t *file_path; ++ grub_efi_char16_t *cmdline; ++ grub_ssize_t cmdline_len; ++ grub_efi_handle_t dev_handle; ++}; ++ + typedef struct pe_coff_loader_image_context pe_coff_loader_image_context_t; + + struct grub_efi_shim_lock +@@ -477,11 +482,13 @@ grub_efi_get_media_file_path (grub_efi_device_path_t *dp) + } + + static grub_efi_boolean_t +-handle_image (void *data, grub_efi_uint32_t datasize) ++handle_image (struct grub_secureboot_chainloader_context *load_context) + { + grub_efi_boot_services_t *b; + grub_efi_loaded_image_t *li, li_bak; + grub_efi_status_t efi_status; ++ void *data = (void *)(unsigned long)load_context->address; ++ grub_efi_uint32_t datasize = load_context->fsize; + char *buffer = NULL; + char *buffer_aligned = NULL; + grub_efi_uint32_t i, size; +@@ -571,10 +578,10 @@ handle_image (void *data, grub_efi_uint32_t datasize) + grub_memcpy (&li_bak, li, sizeof (grub_efi_loaded_image_t)); + li->image_base = buffer_aligned; + li->image_size = context.image_size; +- li->load_options = cmdline; +- li->load_options_size = cmdline_len; +- li->file_path = grub_efi_get_media_file_path (file_path); +- li->device_handle = dev_handle; ++ li->load_options = load_context->cmdline; ++ li->load_options_size = load_context->cmdline_len; ++ li->file_path = grub_efi_get_media_file_path (load_context->file_path); ++ li->device_handle = load_context->dev_handle; + if (li->file_path) + { + grub_printf ("file path: "); +@@ -605,26 +612,27 @@ error_exit: + } + + static grub_err_t +-grub_secureboot_chainloader_unload (void) ++grub_secureboot_chainloader_unload (void* context) + { + grub_efi_boot_services_t *b; ++ struct grub_secureboot_chainloader_context *sb_context = (struct grub_secureboot_chainloader_context *)context; + + b = grub_efi_system_table->boot_services; +- efi_call_2 (b->free_pages, address, pages); +- grub_free (file_path); +- grub_free (cmdline); +- cmdline = 0; +- file_path = 0; +- dev_handle = 0; ++ efi_call_2 (b->free_pages, sb_context->address, sb_context->pages); ++ grub_free (sb_context->file_path); ++ grub_free (sb_context->cmdline); ++ grub_free (sb_context); + + grub_dl_unref (my_mod); + return GRUB_ERR_NONE; + } + + static grub_err_t +-grub_secureboot_chainloader_boot (void) ++grub_secureboot_chainloader_boot (void *context) + { +- handle_image ((void *)address, fsize); ++ struct grub_secureboot_chainloader_context *sb_context = (struct grub_secureboot_chainloader_context *)context; ++ ++ handle_image (sb_context); + grub_loader_unset (); + return grub_errno; + } +@@ -635,6 +643,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) + { + grub_file_t file = 0; ++ grub_ssize_t size; + grub_efi_status_t status; + grub_efi_boot_services_t *b; + grub_device_t dev = 0; +@@ -646,6 +655,8 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_efi_uintn_t pages = 0; + grub_efi_char16_t *cmdline = NULL; + grub_efi_handle_t image_handle = NULL; ++ grub_ssize_t cmdline_len = 0; ++ grub_efi_handle_t dev_handle = 0; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); +@@ -653,8 +664,6 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + + grub_dl_ref (my_mod); + +- dev_handle = 0; +- + b = grub_efi_system_table->boot_services; + + if (argc > 1) +@@ -732,14 +741,14 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_printf ("file path: "); + grub_efi_print_device_path (file_path); + +- fsize = grub_file_size (file); +- if (!fsize) ++ size = grub_file_size (file); ++ if (!size) + { + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), + filename); + goto fail; + } +- pages = (((grub_efi_uintn_t) fsize + ((1 << 12) - 1)) >> 12); ++ pages = (((grub_efi_uintn_t) size + ((1 << 12) - 1)) >> 12); + + status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ANY_PAGES, + GRUB_EFI_LOADER_CODE, +@@ -753,7 +762,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + } + + boot_image = (void *) ((grub_addr_t) address); +- if (grub_file_read (file, boot_image, fsize) != fsize) ++ if (grub_file_read (file, boot_image, size) != size) + { + if (grub_errno == GRUB_ERR_NONE) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), +@@ -763,7 +772,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + } + + #if defined (__i386__) || defined (__x86_64__) +- if (fsize >= (grub_ssize_t) sizeof (struct grub_macho_fat_header)) ++ if (size >= (grub_ssize_t) sizeof (struct grub_macho_fat_header)) + { + struct grub_macho_fat_header *head = boot_image; + if (head->magic +@@ -786,30 +795,42 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + > ~grub_cpu_to_le32 (archs[i].size) + || grub_cpu_to_le32 (archs[i].offset) + + grub_cpu_to_le32 (archs[i].size) +- > (grub_size_t) fsize) ++ > (grub_size_t) size) + { + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), + filename); + goto fail; + } + boot_image = (char *) boot_image + grub_cpu_to_le32 (archs[i].offset); +- fsize = grub_cpu_to_le32 (archs[i].size); ++ size = grub_cpu_to_le32 (archs[i].size); + } + } + #endif + + #ifdef SUPPORT_SECURE_BOOT + /* FIXME is secure boot possible also with universal binaries? */ +- if (debug_secureboot || (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED && grub_secure_validate ((void *)address, fsize))) ++ if (debug_secureboot || (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED && grub_secure_validate ((void *)address, size))) + { ++ struct grub_secureboot_chainloader_context *sb_context; ++ ++ sb_context = grub_malloc (sizeof (*sb_context)); ++ if (!sb_context) ++ goto fail; ++ sb_context->cmdline = cmdline; ++ sb_context->cmdline_len = cmdline_len; ++ sb_context->fsize = size; ++ sb_context->dev_handle = dev_handle; ++ sb_context->address = address; ++ sb_context->pages = pages; ++ sb_context->file_path = file_path; + grub_file_close (file); +- grub_loader_set (grub_secureboot_chainloader_boot, grub_secureboot_chainloader_unload, 0); ++ grub_loader_set_ex (grub_secureboot_chainloader_boot, grub_secureboot_chainloader_unload, sb_context, 0); + return 0; + } + #endif + + status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path, +- boot_image, fsize, ++ boot_image, size, + &image_handle); + #ifdef SUPPORT_SECURE_BOOT + if (status == GRUB_EFI_SECURITY_VIOLATION && grub_efi_get_secureboot () != GRUB_EFI_SECUREBOOT_MODE_ENABLED) +@@ -817,10 +838,21 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + /* If it failed with security violation while not in secure boot mode, + the firmware might be broken. We try to workaround on that by forcing + the SB method! (bsc#887793) */ ++ struct grub_secureboot_chainloader_context *sb_context; ++ + grub_dprintf ("chain", "Possible firmware flaw! Security violation while not in secure boot mode.\n"); ++ sb_context = grub_malloc (sizeof (*sb_context)); ++ if (!sb_context) ++ goto fail; ++ sb_context->cmdline = cmdline; ++ sb_context->cmdline_len = cmdline_len; ++ sb_context->fsize = size; ++ sb_context->dev_handle = dev_handle; ++ sb_context->address = address; ++ sb_context->pages = pages; + grub_file_close (file); +- grub_loader_set (grub_secureboot_chainloader_boot, +- grub_secureboot_chainloader_unload, 0); ++ grub_loader_set_ex (grub_secureboot_chainloader_boot, ++ grub_secureboot_chainloader_unload, sb_context, 0); + return 0; + } + #endif +-- +2.34.1 + diff --git a/0044-squash-kern-Add-lockdown-support.patch b/0044-squash-kern-Add-lockdown-support.patch new file mode 100644 index 0000000..281aacb --- /dev/null +++ b/0044-squash-kern-Add-lockdown-support.patch @@ -0,0 +1,115 @@ +From 3c612287086a5f590f80d874e8c5c6042bf7f6a0 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Wed, 24 Feb 2021 23:51:38 +0800 +Subject: [PATCH 44/46] squash! kern: Add lockdown support + +Since the lockdown feature is efi specific, the +grub_{command,extcmd}_lockdown functions can be removed from other +platform for not taking up space in kernel image. +--- + grub-core/commands/extcmd.c | 2 ++ + grub-core/kern/command.c | 2 ++ + include/grub/command.h | 11 +++++++++++ + include/grub/extcmd.h | 13 +++++++++++++ + 4 files changed, 28 insertions(+) + +diff --git a/grub-core/commands/extcmd.c b/grub-core/commands/extcmd.c +index 90a5ca24a..4ac111a99 100644 +--- a/grub-core/commands/extcmd.c ++++ b/grub-core/commands/extcmd.c +@@ -111,6 +111,7 @@ grub_register_extcmd (const char *name, grub_extcmd_func_t func, + summary, description, parser, 1); + } + ++#ifdef GRUB_MACHINE_EFI + static grub_err_t + grub_extcmd_lockdown (grub_extcmd_context_t ctxt __attribute__ ((unused)), + int argc __attribute__ ((unused)), +@@ -132,6 +133,7 @@ grub_register_extcmd_lockdown (const char *name, grub_extcmd_func_t func, + + return grub_register_extcmd (name, func, flags, summary, description, parser); + } ++#endif + + void + grub_unregister_extcmd (grub_extcmd_t ext) +diff --git a/grub-core/kern/command.c b/grub-core/kern/command.c +index 4aabcd4b5..17363af7b 100644 +--- a/grub-core/kern/command.c ++++ b/grub-core/kern/command.c +@@ -78,6 +78,7 @@ grub_register_command_prio (const char *name, + return cmd; + } + ++#ifdef GRUB_MACHINE_EFI + static grub_err_t + grub_cmd_lockdown (grub_command_t cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), +@@ -100,6 +101,7 @@ grub_register_command_lockdown (const char *name, + + return grub_register_command_prio (name, func, summary, description, 0); + } ++#endif + + void + grub_unregister_command (grub_command_t cmd) +diff --git a/include/grub/command.h b/include/grub/command.h +index 2a6f7f846..b518e262e 100644 +--- a/include/grub/command.h ++++ b/include/grub/command.h +@@ -86,11 +86,22 @@ EXPORT_FUNC(grub_register_command_prio) (const char *name, + const char *summary, + const char *description, + int prio); ++#ifdef GRUB_MACHINE_EFI + grub_command_t + EXPORT_FUNC(grub_register_command_lockdown) (const char *name, + grub_command_func_t func, + const char *summary, + const char *description); ++#else ++static inline grub_command_t ++grub_register_command_lockdown (const char *name, ++ grub_command_func_t func, ++ const char *summary, ++ const char *description) ++{ ++ return grub_register_command_prio (name, func, summary, description, 0); ++} ++#endif + void EXPORT_FUNC(grub_unregister_command) (grub_command_t cmd); + + static inline grub_command_t +diff --git a/include/grub/extcmd.h b/include/grub/extcmd.h +index fe9248b8b..fa1328ea5 100644 +--- a/include/grub/extcmd.h ++++ b/include/grub/extcmd.h +@@ -62,12 +62,25 @@ grub_extcmd_t EXPORT_FUNC(grub_register_extcmd) (const char *name, + const char *description, + const struct grub_arg_option *parser); + ++#ifdef GRUB_MACHINE_EFI + grub_extcmd_t EXPORT_FUNC(grub_register_extcmd_lockdown) (const char *name, + grub_extcmd_func_t func, + grub_command_flags_t flags, + const char *summary, + const char *description, + const struct grub_arg_option *parser); ++#else ++static inline grub_extcmd_t ++grub_register_extcmd_lockdown (const char *name, ++ grub_extcmd_func_t func, ++ grub_command_flags_t flags, ++ const char *summary, ++ const char *description, ++ const struct grub_arg_option *parser) ++{ ++ return grub_register_extcmd (name, func, flags, summary, description, parser); ++} ++#endif + + grub_extcmd_t EXPORT_FUNC(grub_register_extcmd_prio) (const char *name, + grub_extcmd_func_t func, +-- +2.26.2 + diff --git a/0046-squash-verifiers-Move-verifiers-API-to-kernel-image.patch b/0046-squash-verifiers-Move-verifiers-API-to-kernel-image.patch new file mode 100644 index 0000000..e4fc0a1 --- /dev/null +++ b/0046-squash-verifiers-Move-verifiers-API-to-kernel-image.patch @@ -0,0 +1,150 @@ +From 59ac440754a43c6e964e924a086af066e04e753e Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Fri, 26 Feb 2021 19:43:14 +0800 +Subject: [PATCH 46/46] squash! verifiers: Move verifiers API to kernel image + +In case there's broken i386-pc setup running inconsistent installs for +module in filesystem and core image on the disk, keeping the verifiers +as module for i386-pc to avoid potential issue of looking up symbols. +--- + configure.ac | 1 + + grub-core/Makefile.am | 2 ++ + grub-core/Makefile.core.def | 8 +++++++- + grub-core/kern/main.c | 4 ++++ + grub-core/kern/verifiers.c | 11 +++++++++++ + include/grub/verify.h | 9 +++++++++ + 6 files changed, 34 insertions(+), 1 deletion(-) + +Index: grub-2.06~rc1/configure.ac +=================================================================== +--- grub-2.06~rc1.orig/configure.ac ++++ grub-2.06~rc1/configure.ac +@@ -1985,6 +1985,7 @@ AM_CONDITIONAL([COND_real_platform], [te + AM_CONDITIONAL([COND_emu], [test x$platform = xemu]) + AM_CONDITIONAL([COND_NOT_emu], [test x$platform != xemu]) + AM_CONDITIONAL([COND_i386_pc], [test x$target_cpu = xi386 -a x$platform = xpc]) ++AM_CONDITIONAL([COND_NOT_i386_pc], [test x$target_cpu != xi386 -o x$platform != xpc]) + AM_CONDITIONAL([COND_i386_efi], [test x$target_cpu = xi386 -a x$platform = xefi]) + AM_CONDITIONAL([COND_ia64_efi], [test x$target_cpu = xia64 -a x$platform = xefi]) + AM_CONDITIONAL([COND_i386_qemu], [test x$target_cpu = xi386 -a x$platform = xqemu]) +Index: grub-2.06~rc1/grub-core/Makefile.am +=================================================================== +--- grub-2.06~rc1.orig/grub-core/Makefile.am ++++ grub-2.06~rc1/grub-core/Makefile.am +@@ -93,7 +93,9 @@ KERNEL_HEADER_FILES += $(top_srcdir)/inc + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/stack_protector.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/term.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/time.h ++if COND_NOT_i386_pc + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/verify.h ++endif + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/mm_private.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/net.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/memory.h +Index: grub-2.06~rc1/grub-core/Makefile.core.def +=================================================================== +--- grub-2.06~rc1.orig/grub-core/Makefile.core.def ++++ grub-2.06~rc1/grub-core/Makefile.core.def +@@ -141,7 +141,7 @@ kernel = { + common = kern/rescue_parser.c; + common = kern/rescue_reader.c; + common = kern/term.c; +- common = kern/verifiers.c; ++ nopc = kern/verifiers.c; + + noemu = kern/compiler-rt.c; + noemu = kern/mm.c; +@@ -947,6 +947,12 @@ module = { + }; + + module = { ++ name = verifiers; ++ common = kern/verifiers.c; ++ enable = i386_pc; ++}; ++ ++module = { + name = hdparm; + common = commands/hdparm.c; + enable = pci; +Index: grub-2.06~rc1/grub-core/kern/main.c +=================================================================== +--- grub-2.06~rc1.orig/grub-core/kern/main.c ++++ grub-2.06~rc1/grub-core/kern/main.c +@@ -29,7 +29,9 @@ + #include + #include + #include ++#ifndef GRUB_MACHINE_PCBIOS + #include ++#endif + + #ifdef GRUB_MACHINE_PCBIOS + #include +@@ -275,8 +277,10 @@ grub_main (void) + grub_printf ("Welcome to GRUB!\n\n"); + grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); + ++#ifndef GRUB_MACHINE_PCBIOS + /* Init verifiers API. */ + grub_verifiers_init (); ++#endif + + grub_load_config (); + +Index: grub-2.06~rc1/grub-core/kern/verifiers.c +=================================================================== +--- grub-2.06~rc1.orig/grub-core/kern/verifiers.c ++++ grub-2.06~rc1/grub-core/kern/verifiers.c +@@ -221,8 +221,19 @@ grub_verify_string (char *str, enum grub + return GRUB_ERR_NONE; + } + ++#ifdef GRUB_MACHINE_PCBIOS ++GRUB_MOD_INIT(verifiers) ++#else + void + grub_verifiers_init (void) ++#endif + { + grub_file_filter_register (GRUB_FILE_FILTER_VERIFY, grub_verifiers_open); + } ++ ++#ifdef GRUB_MACHINE_PCBIOS ++GRUB_MOD_FINI(verifiers) ++{ ++ grub_file_filter_unregister (GRUB_FILE_FILTER_VERIFY); ++} ++#endif +Index: grub-2.06~rc1/include/grub/verify.h +=================================================================== +--- grub-2.06~rc1.orig/include/grub/verify.h ++++ grub-2.06~rc1/include/grub/verify.h +@@ -64,10 +64,14 @@ struct grub_file_verifier + grub_err_t (*verify_string) (char *str, enum grub_verify_string_type type); + }; + ++#ifdef GRUB_MACHINE_PCBIOS ++extern struct grub_file_verifier *grub_file_verifiers; ++#else + extern struct grub_file_verifier *EXPORT_VAR (grub_file_verifiers); + + extern void + grub_verifiers_init (void); ++#endif + + static inline void + grub_verifier_register (struct grub_file_verifier *ver) +@@ -81,7 +85,12 @@ grub_verifier_unregister (struct grub_fi + grub_list_remove (GRUB_AS_LIST (ver)); + } + ++#ifdef GRUB_MACHINE_PCBIOS ++grub_err_t ++grub_verify_string (char *str, enum grub_verify_string_type type); ++#else + extern grub_err_t + EXPORT_FUNC (grub_verify_string) (char *str, enum grub_verify_string_type type); ++#endif + + #endif /* ! GRUB_VERIFY_HEADER */ diff --git a/20_memtest86+ b/20_memtest86+ new file mode 100644 index 0000000..f53b80f --- /dev/null +++ b/20_memtest86+ @@ -0,0 +1,59 @@ +#! /bin/sh +set -e + +# grub-mkconfig helper script. +# Copyright (C) 2011 Michal Ambroz +# Adapted for openSUSE by Andrey Borzenkov +# +# 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. +# +# 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 the script. If not, see . + +. /usr/share/grub2/grub-mkconfig_lib + +export TEXTDOMAIN=grub2 +export TEXTDOMAINDIR=/usr/share/locale + +# memset86+ requires the x86 real mode +# which is not available with UEFI booting. +if [ -d /sys/firmware/efi ]; then + exit 0 +fi + +CLASS="--class memtest86 --class gnu --class tools" + +if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then + OS=Memtest +else + OS="${GRUB_DISTRIBUTOR} Memtest" + CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1) ${CLASS}" +fi + +memtest=/boot/memtest.bin + +if grub_file_is_not_garbage "$memtest" ; then + gettext_printf "Found memtest image: %s\n" "$memtest" >&2 + basename=`basename $memtest` + dirname=`dirname $memtest` + rel_dirname=`make_system_path_relative_to_its_root $dirname` + boot_device_id="$(grub_get_device_id "${GRUB_DEVICE_BOOT}")" + + printf "menuentry '%s' %s \$menuentry_id_option '%s' {\n" "${OS}" "${CLASS}" "memtest-$boot_device_id" + prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")" + printf '%s\n' "${prepare_boot_cache}" + message="$(gettext_printf "Loading memtest ...\n" | grub_quote)" + cat << EOF + echo '$message' + linux16 ${rel_dirname}/${basename} +} +EOF +fi diff --git a/80_suse_btrfs_snapshot b/80_suse_btrfs_snapshot new file mode 100644 index 0000000..e807504 --- /dev/null +++ b/80_suse_btrfs_snapshot @@ -0,0 +1,28 @@ +#! /bin/sh +set -e +SNAPSHOTS="/.snapshots" +if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ] && + [ "x${GRUB_FS}" = "xbtrfs" ] && + [ -d "${SNAPSHOTS}" ]; then + machine=`uname -m` + case "x$machine" in + xs390 | xs390x) : ;; + *) + SNAPSHOT_RID=`btrfs inspect-internal rootid ${SNAPSHOTS}` + ROOT_RID=`btrfs inspect-internal rootid /` + if [ -n "${SNAPSHOT_RID}" -a "${SNAPSHOT_RID}" != "${ROOT_RID}" ]; then + SNAPSHOT_SUBVOL=`btrfs inspect-internal subvolid-resolve ${SNAPSHOT_RID} /` + ROOT_SUBVOL=`btrfs inspect-internal subvolid-resolve ${ROOT_RID} /` + INODE=`stat -c '%i' ${SNAPSHOTS}` + if [ "x${INODE}" = "x256" -a "x${ROOT_SUBVOL}${SNAPSHOTS}" != "x${SNAPSHOT_SUBVOL}" ]; then + echo "btrfs-mount-subvol (\$root) ${SNAPSHOTS} ${SNAPSHOT_SUBVOL}" + fi + fi + ;; + esac + cat <. + +# The output of this script is copied from part of grub.cfg +# that correspond to itself. The achievement is that user can +# modify that part of grub.cfg directly, and it will be persistent +# across update-grub runs. + +transform="s&^&&;s,grub,grub2," +ME=$(echo $0 |sed 's,/,\\/,g') +GRUBCFG=/boot/`echo grub | sed ${transform}`/grub.cfg + +# Exit gracefully if there's no configuration file yet +[ -f ${GRUBCFG} ] || exit 0 + +awk " + BEGIN {echo = 0} + /### BEGIN $ME ###/ {echo = 1; next} + /### END $ME ###/ {echo = 0; next} + {if (echo) print} +" ${GRUBCFG} diff --git a/PATCH_POLICY b/PATCH_POLICY new file mode 100644 index 0000000..5da4218 --- /dev/null +++ b/PATCH_POLICY @@ -0,0 +1,6 @@ +Make sure the patches you add contain tags similar to patches in the kernel +RPM. This means, it should contain From, Subject, Patch-mainline tags and also +a description of the problem, i.e. what the patch is for. + +Also, if it is not a SUSE/openSUSE-specific patch (unlikely is), post the patch to +upstream too. diff --git a/README.ibm3215 b/README.ibm3215 new file mode 100644 index 0000000..252adb6 --- /dev/null +++ b/README.ibm3215 @@ -0,0 +1,59 @@ +[Disclaimer: I do not know enough (by far) about the inner workings +and secrets of these printer-consoles, so please correct me/send advice, +if there are better solutions!] + +On 3215/327x things are dramatically different from everywhere else. +You'll have to live with some severe limitations: + +0. Interactivity is quite limited. You'll need to "blindly" type, + most of the time, to see the effect only on "submission" ([Enter]). + In edit and shell mode it's sometimes useful to insert underlines + just to see, where the curser (AKA "point") is. (BTW, 3270 is _much_ + better at displaying/refreshing grub2 screens than 3215.) +1. No cursor-movement-, alt-, meta-, and control-keys (like [ESC]). +2. To work around the lack of control-keys, the "[^][C]-sends-interrupt"- + trick is extended to translate sequences of caret followed by character + to the respective control-character. In the following this sequence + of two keystrokes is referred to as '^c' instead of that somewhat balky + [^][C]. Thus an [ESC] keypress can be generated with '^[' ("caret" + followed by "opening square bracket"). +3. If a caret itself is needed, send one on it's own (i.e. a solitary [^] + followed by [Enter] -- or use '^^'. +4. No '[Enter]', because it can't be avoided on *any* input. +5. If you still need one to arrive at the application, you may either + press '[Enter]' *twice* (one empty line, sort of) or add '^j' to your + input. In menu mode '^f' works as well (see below). But using "empty + lines" does now work very reliably, so explicit control sequences + are to be preferred. This has the additional advantage, that combined + sequences can be sent, e.g. to exit from 'grub2-emu' without doing + anything, you can simply type 'cexit^j' and submit that with [Enter]. + +Common Substitutes: + '^j'` => [Enter] "engage" + '^[' => [ESC] "abort" / return to previous "state" + '^i' => [TAB] try completion (in edit & shell mode) + +Available Keys in Menu Mode: + '^a' first entry '^e' last entry + '^p' previous entry '^n' next entry + '^g' previous page '^c' next page + '^f' boot selected entry/enter sub-menu (same as '^j') + 'e' edit selected entry 'c' enter grub-shell + +Available Keys in Edit Mode: + '^p' previous line '^n' next line + '^b' backward char '^f' forward char + '^a' beginning of line '^e' end of line + '^h' backspace '^d' delete + '^k' kill (to end of) line '^y' yank + '^o' open line '^l' refresh screen + '^x' boot entry '^c' enter grub-shell + +Availble Keys on Command Line Mode: + '^p' previous command '^n' next command (from history) + '^a' beginning of line '^e' end of line + '^b' backward char '^f' forward char + '^h' backspace '^d' delete + '^k' kill (to end of) line '^u' discard line + '^y' yank + diff --git a/SLES-UEFI-CA-Certificate.crt b/SLES-UEFI-CA-Certificate.crt new file mode 100644 index 0000000..3751f95 --- /dev/null +++ b/SLES-UEFI-CA-Certificate.crt @@ -0,0 +1,39 @@ +-----BEGIN CERTIFICATE----- +MIIG5TCCBM2gAwIBAgIBATANBgkqhkiG9w0BAQsFADCBpjEtMCsGA1UEAwwkU1VT +RSBMaW51eCBFbnRlcnByaXNlIFNlY3VyZSBCb290IENBMQswCQYDVQQGEwJERTES +MBAGA1UEBwwJTnVyZW1iZXJnMSEwHwYDVQQKDBhTVVNFIExpbnV4IFByb2R1Y3Rz +IEdtYkgxEzARBgNVBAsMCkJ1aWxkIFRlYW0xHDAaBgkqhkiG9w0BCQEWDWJ1aWxk +QHN1c2UuZGUwHhcNMTMwMTIyMTQyMDA4WhcNMzQxMjE4MTQyMDA4WjCBpjEtMCsG +A1UEAwwkU1VTRSBMaW51eCBFbnRlcnByaXNlIFNlY3VyZSBCb290IENBMQswCQYD +VQQGEwJERTESMBAGA1UEBwwJTnVyZW1iZXJnMSEwHwYDVQQKDBhTVVNFIExpbnV4 +IFByb2R1Y3RzIEdtYkgxEzARBgNVBAsMCkJ1aWxkIFRlYW0xHDAaBgkqhkiG9w0B +CQEWDWJ1aWxkQHN1c2UuZGUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQCrLYL1Uq02iIgro6x6PFESFDtUKU7xO/bJanI7+AQAroowFuLBI67BBSmoq3hR +QnH3OtQusGV8y+wvjaaunppvWMfjViZ88zssj5fKXrDr5U6BB566DJgHreWaEs2d +FD13XpKRr3Nk9zdjAJu5YsR7hI1NMXsnj1X8w71OY9HLjv+Kq9917PJwZQjOGnAJ +BQTi0ogHuLiwDqMKgg5rrYD4cJDPzoLEmEXnwHDIOSiWdD0bCzhN6GQDKldIxQ2O +d/mjUgzB+dWslIb+bUKaoJgDtyPV20W74t7Y2uwoaEVr9QkPoM3tOPttf4qsWo8B +J1TgeoF01ZeKcvSyvOXCKbfAN9sqURK2ZUTNThqZ//VPQmJP6fByrMJsbvTOSsQt +HI+fFPrg1DC2KT8SzuGtWDRscHZ7MofvUKEQolVgkGwp8u68t/RAAwDpUdqIajzi +yfp9qSDD+9uMeyiLa4rrAr2ATGohNBa0qha95slgvSepXbYKuHG5b4fWMsG7z4Uc +dqE2vK8cQma1nsAeQBaq2/89294TOHEzKyspesfCBCnKQ3q+l9xelYRdvapj1CH/ +cfUZf2/6X3VHN1P88RfRrPubswmrcOCEBT41upa2WKRDJ1GS6YhL6LJnrZSTjfe+ +KsfNVS1D+KqSKiK0hfk6YK6O88mMGeAKQs3Ap8WthBLf0QIDAQABo4IBGjCCARYw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPU1Az5OFOQJLHPxaEt7f6LF+dV8w +gdMGA1UdIwSByzCByIAUPU1Az5OFOQJLHPxaEt7f6LF+dV+hgaykgakwgaYxLTAr +BgNVBAMMJFNVU0UgTGludXggRW50ZXJwcmlzZSBTZWN1cmUgQm9vdCBDQTELMAkG +A1UEBhMCREUxEjAQBgNVBAcMCU51cmVtYmVyZzEhMB8GA1UECgwYU1VTRSBMaW51 +eCBQcm9kdWN0cyBHbWJIMRMwEQYDVQQLDApCdWlsZCBUZWFtMRwwGgYJKoZIhvcN +AQkBFg1idWlsZEBzdXNlLmRlggEBMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0B +AQsFAAOCAgEANtdMT47CjQtuERYa5jfygIO5F+urB4fl8pYcQQ/hTPE0KtAnAtrS +1strtMrVQ1t7Wu3fVbWYA6MZMXXkcwyyNbaWfj6roaSC6G5ZqCJ69oSyzaCbyaTI +eOgzIIiVGOAj7tiM6T88Xp9qx4Xa3F6UQHF6xfwBT3nNKerGKOG01p7mBfBewwO5 +Hxp7OAZmennUxV1uuT5/AsArxw9lMlawXhIAS7tRYHW+32D4tjHPDycldOw1hBjt +z5JdehBiTmxhJ6onl0HSpsX84IMSbkeFIxLfxIF0TNas1pGnSGmh8FcV+ck9js3P +yamJcNkgCstIwo3QZ2D5YdtQjOusyEuGjCIpDIQx36OMzeOo0SayOdzb2dSmcrHv +4DIkXDUELyIzu79A2R2KR7OQaGL6HGAVy6+yXHHygTbbUrb6ck2+aOG8913ChABc +ZAiSFFRKVZzzj7FeIxZNA8GBUbhd20eQB2fUXDypeAnTG6P3dtTs84xNb1qGm3VC +OAKjkWYQijLWmAOs9Q4NM/AXOeDTgXxA7iX7kWHRNeDbACirp7zM2ZOIP5ObIS6z +yMqcG9DecSVbXiH3MJDTBoB1idQTTyreqpM/l6N8xNNVjEiLJGMEM1SeYq6S1lFV +a+GcdOaLYkh7ya3I42l/tDOqH2OLIf7FEtocnc1xU6jTz8au1tZxec8= +-----END CERTIFICATE----- diff --git a/fix-tpm2-build.patch b/fix-tpm2-build.patch new file mode 100644 index 0000000..915ecff --- /dev/null +++ b/fix-tpm2-build.patch @@ -0,0 +1,38 @@ +--- + grub-core/Makefile.core.def | 1 + + grub-core/tpm2/module.c | 2 +- + util/grub-protect.c | 2 +- + 3 files changed, 3 insertions(+), 2 deletions(-) + +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2569,6 +2569,7 @@ + common = tpm2/mu.c; + common = tpm2/tpm2.c; + efi = tpm2/tcg2.c; ++ enable = efi; + }; + + module = { +--- a/util/grub-protect.c ++++ b/util/grub-protect.c +@@ -542,7 +542,7 @@ + if (pcr_values.digests[i].size != pcr_digest_len) + { + fprintf (stderr, +- _("Bad PCR value size: expected %lu bytes but got %u bytes.\n"), ++ _("Bad PCR value size: expected %" PRIuGRUB_SIZE " bytes but got %u bytes.\n"), + pcr_digest_len, pcr_values.digests[i].size); + goto exit2; + } +--- a/grub-core/tpm2/module.c ++++ b/grub-core/tpm2/module.c +@@ -195,7 +195,7 @@ + if (sealed_key_size > buf.cap) + { + grub_dprintf ("tpm2", "Sealed key file is larger than decode buffer " +- "(%lu vs %lu bytes).\n", sealed_key_size, buf.cap); ++ "(%" PRIuGRUB_SIZE " vs %" PRIuGRUB_SIZE " bytes).\n", sealed_key_size, buf.cap); + return GRUB_ERR_BAD_ARGUMENT; + } + diff --git a/grub-install-force-journal-draining-to-ensure-data-i.patch b/grub-install-force-journal-draining-to-ensure-data-i.patch new file mode 100644 index 0000000..96dbafb --- /dev/null +++ b/grub-install-force-journal-draining-to-ensure-data-i.patch @@ -0,0 +1,230 @@ +From 3085db0922a1d803d4a9dfe54daae6fef20e4340 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Mon, 13 Apr 2020 16:08:59 +0800 +Subject: [PATCH] grub-install: force journal draining to ensure data integrity + +In XFS, the system would end up in unbootable state if an abrupt power +off after grub-install is occuring. It can be easily reproduced with. + + grub-install /dev/vda; reboot -f + +The grub error would show many different kinds of corruption in +filesystem and the problem boils down to incompleted journal transaction +which would leave pending writes behind in the on-disk journal. It is +therefore necessary to recover the system via re-mounting the filesystem +from linux system that all pending journal log can be replayed. + +On the other hand if journal draining can be enforced by grub-install +then it can bring more resilience to such abrupt power loss. The fsync +is not enough here for XFS, because that only writes in-memory log to +on-disk (ie makes sure broken state can be repaired). Unfortunately +there's no designated system call to serve solely for the journal +draining, so it can only be achieved via fsfreeze system call that the +journal draining can happen as a byproduct during the process. + +This patch adds fsfreeze/unfreeze at the end of grub-install to induce +journal draining on journaled file system. However btrfs is excluded +from the list as it is using fsync to drain journal and also is not +desired as reportedly having negative side effect. With this patch +applied, the boot falilure can no longer be reproduced with above +procedure. + +v2: +Fix boot failure after kdump due to the content of grub.cfg is not +completed with pending modificaton in xfs journal (bsc#1186975) + +Signed-off-by: Michael Chang +--- + Makefile.util.def | 1 + + grub-core/osdep/basic/journaled_fs.c | 26 +++++++++++++++++++ + grub-core/osdep/journaled_fs.c | 5 ++++ + grub-core/osdep/linux/journaled_fs.c | 48 ++++++++++++++++++++++++++++++++++++ + include/grub/util/install.h | 2 ++ + util/grub-install.c | 20 +++++++++++++++ + 6 files changed, 102 insertions(+) + create mode 100644 grub-core/osdep/basic/journaled_fs.c + create mode 100644 grub-core/osdep/journaled_fs.c + create mode 100644 grub-core/osdep/linux/journaled_fs.c + +Index: grub-2.06/Makefile.util.def +=================================================================== +--- grub-2.06.orig/Makefile.util.def ++++ grub-2.06/Makefile.util.def +@@ -663,6 +663,7 @@ program = { + emu_condition = COND_s390x; + common = grub-core/kern/emu/argp_common.c; + common = grub-core/osdep/init.c; ++ common = grub-core/osdep/journaled_fs.c; + + ldadd = '$(LIBLZMA)'; + ldadd = libgrubmods.a; +Index: grub-2.06/grub-core/osdep/basic/journaled_fs.c +=================================================================== +--- /dev/null ++++ grub-2.06/grub-core/osdep/basic/journaled_fs.c +@@ -0,0 +1,26 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2010,2011,2012,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 . ++ */ ++ ++#include ++ ++int ++grub_install_sync_fs_journal (const char *path) ++{ ++ return 1; ++} ++ +Index: grub-2.06/grub-core/osdep/journaled_fs.c +=================================================================== +--- /dev/null ++++ grub-2.06/grub-core/osdep/journaled_fs.c +@@ -0,0 +1,5 @@ ++#ifdef __linux__ ++#include "linux/journaled_fs.c" ++#else ++#include "basic/journaled_fs.c" ++#endif +Index: grub-2.06/grub-core/osdep/linux/journaled_fs.c +=================================================================== +--- /dev/null ++++ grub-2.06/grub-core/osdep/linux/journaled_fs.c +@@ -0,0 +1,48 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2010,2011,2012,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 . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++int ++grub_install_sync_fs_journal (const char *path) ++{ ++ int fd, ret; ++ ++ fd = open (path, O_RDONLY); ++ ++ if (fd == -1) ++ return 1; ++ ++ if (ioctl (fd, FIFREEZE, 0) == 0) ++ { ++ ioctl(fd, FITHAW, 0); ++ ret = 1; ++ } ++ else if (errno == EOPNOTSUPP) ++ ret = 1; ++ else ++ ret = 0; ++ ++ close (fd); ++ return ret; ++} ++ +Index: grub-2.06/include/grub/util/install.h +=================================================================== +--- grub-2.06.orig/include/grub/util/install.h ++++ grub-2.06/include/grub/util/install.h +@@ -300,4 +300,6 @@ grub_set_install_backup_ponr (void) + } + #endif + ++int ++grub_install_sync_fs_journal (const char *path); + #endif +Index: grub-2.06/util/grub-install.c +=================================================================== +--- grub-2.06.orig/util/grub-install.c ++++ grub-2.06/util/grub-install.c +@@ -42,6 +42,7 @@ + #include + #include + #include ++#include + + #include + +@@ -2025,6 +2026,24 @@ main (int argc, char *argv[]) + break; + } + ++ { ++ const char *journaled_fs[] = {"xfs", "ext2", NULL}; ++ int i; ++ ++ for (i = 0; journaled_fs[i]; ++i) ++ if (grub_strcmp (grub_fs->name, journaled_fs[i]) == 0) ++ { ++ int retries = 10; ++ ++ /* If the fs is already frozen at that point, we could generally ++ * expected that it will be soon unfrozen again (assuming some other ++ * process has frozen it for snapshotting or something), so we may ++ * as well retry a few (limited) times in a delay loop. */ ++ while (retries-- && !grub_install_sync_fs_journal (grubdir)) ++ grub_sleep (1); ++ break; ++ } ++ } + /* + * Either there are no platform specific code, or it didn't raise + * ponr. Raise it here, because usually this is already past point +Index: grub-2.06/util/grub-mkconfig.in +=================================================================== +--- grub-2.06.orig/util/grub-mkconfig.in ++++ grub-2.06/util/grub-mkconfig.in +@@ -328,6 +328,15 @@ for i in "${grub_mkconfig_dir}"/* ; do + esac + done + ++sync_fs_journal () { ++ if test "x$GRUB_DEVICE" = "x$GRUB_DEVICE_BOOT" && ++ test "x$GRUB_FS" = "xxfs" -o "x$GRUB_FS" = "xext2" && ++ test "x${grub_cfg}" != "x" -a "x`make_system_path_relative_to_its_root $grub_cfg`" = "x/boot/grub2/grub.cfg" && ++ test -x /usr/sbin/fsfreeze; then ++ /usr/sbin/fsfreeze --freeze / && /usr/sbin/fsfreeze --unfreeze / ++ fi ++} >&2 ++ + if test "x${grub_cfg}" != "x" ; then + if ! ${grub_script_check} ${grub_cfg}.new; then + # TRANSLATORS: %s is replaced by filename +@@ -341,6 +350,7 @@ and /etc/grub.d/* files or please file a + # none of the children aborted with error, install the new grub.cfg + cat ${grub_cfg}.new > ${grub_cfg} + rm -f ${grub_cfg}.new ++ sync_fs_journal || true + fi + fi + diff --git a/grub.default b/grub.default new file mode 100644 index 0000000..b48dea0 --- /dev/null +++ b/grub.default @@ -0,0 +1,39 @@ +# If you change this file, run 'grub2-mkconfig -o /boot/grub2/grub.cfg' afterwards to update +# /boot/grub2/grub.cfg. + +# Uncomment to set your own custom distributor. If you leave it unset or empty, the default +# policy is to determine the value from /etc/os-release +# GRUB_DISTRIBUTOR="" + +GRUB_DEFAULT=0 +GRUB_HIDDEN_TIMEOUT=0 +GRUB_HIDDEN_TIMEOUT_QUIET=true +GRUB_TIMEOUT=10 +GRUB_CMDLINE_LINUX_DEFAULT="" +GRUB_CMDLINE_LINUX="" + +# Uncomment to automatically save last booted menu entry in GRUB2 environment +# variable `saved_entry' +#GRUB_SAVEDEFAULT="true" + +# Uncomment to enable BadRAM filtering, modify to suit your needs +# This works with Linux (no patch required) and with any kernel that obtains +# the memory map information from GRUB (GNU Mach, kernel of FreeBSD ...) +#GRUB_BADRAM="0x01234567,0xfefefefe,0x89abcdef,0xefefefef" + +# Uncomment to disable graphical terminal (grub-pc only) +#GRUB_TERMINAL=console + +# The resolution used on graphical terminal +# note that you can use only modes which your graphic card supports via VBE +# you can see them in real GRUB with the command `vbeinfo' +#GRUB_GFXMODE=640x480 + +# Uncomment if you don't want GRUB to pass "root=UUID=xxx" parameter to Linux +#GRUB_DISABLE_LINUX_UUID=true + +# Uncomment to disable generation of recovery mode menu entries +#GRUB_DISABLE_RECOVERY="true" + +# Uncomment to get a beep at grub start +#GRUB_INIT_TUNE="480 440 1" diff --git a/grub2-Add-hidden-menu-entries.patch b/grub2-Add-hidden-menu-entries.patch new file mode 100644 index 0000000..b45574d --- /dev/null +++ b/grub2-Add-hidden-menu-entries.patch @@ -0,0 +1,232 @@ +From a06004f4c668abd7c760a2818d0a8205da7568e7 Mon Sep 17 00:00:00 2001 +From: Alexander Graf +Date: Tue, 26 Apr 2016 15:29:25 +0200 +Subject: [PATCH v3] Add hidden menu entries + +The menu infrastructure is quite powerful. It allows you to define menu +entries that can contain arbitrary grub commands that can do a lot more +than just boot kernel entries. + +For some of these it makes sense to hide them inside the normal menu +though and instead have them available through hotkeys that get advertised +differently. My main use case is to switch to the serial console when +gfxterm is loaded. + +So this patch adds support for hidden menu entries that are accessible +using hotkeys, but are not accessible in the grub menu. + +Signed-off-by: Alexander Graf + +--- + +v1 -> v2: + + - fix default entry selection + +v2 -> v3: + + - replace "--hidden" parameter with new command "hiddenentry" + +diff --git a/grub-core/commands/legacycfg.c b/grub-core/commands/legacycfg.c +index dd9d9f1..b282c4f 100644 +--- a/grub-core/commands/legacycfg.c ++++ b/grub-core/commands/legacycfg.c +@@ -133,7 +133,7 @@ legacy_file (const char *filename) + args[0] = oldname; + grub_normal_add_menu_entry (1, args, NULL, NULL, "legacy", + NULL, NULL, +- entrysrc, 0); ++ entrysrc, 0, 0); + grub_free (args); + entrysrc[0] = 0; + grub_free (oldname); +@@ -186,7 +186,7 @@ legacy_file (const char *filename) + } + args[0] = entryname; + grub_normal_add_menu_entry (1, args, NULL, NULL, NULL, +- NULL, NULL, entrysrc, 0); ++ NULL, NULL, entrysrc, 0, 0); + grub_free (args); + } + +diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c +index 58d4dad..b4d6c31 100644 +--- a/grub-core/commands/menuentry.c ++++ b/grub-core/commands/menuentry.c +@@ -78,7 +78,7 @@ grub_normal_add_menu_entry (int argc, const char **args, + char **classes, const char *id, + const char *users, const char *hotkey, + const char *prefix, const char *sourcecode, +- int submenu) ++ int submenu, int hidden) + { + int menu_hotkey = 0; + char **menu_args = NULL; +@@ -188,8 +188,11 @@ grub_normal_add_menu_entry (int argc, const char **args, + (*last)->args = menu_args; + (*last)->sourcecode = menu_sourcecode; + (*last)->submenu = submenu; ++ (*last)->hidden = hidden; ++ ++ if (!hidden) ++ menu->size++; + +- menu->size++; + return GRUB_ERR_NONE; + + fail: +@@ -286,7 +289,8 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) + users, + ctxt->state[2].arg, 0, + ctxt->state[3].arg, +- ctxt->extcmd->cmd->name[0] == 's'); ++ ctxt->extcmd->cmd->name[0] == 's', ++ ctxt->extcmd->cmd->name[0] == 'h'); + + src = args[argc - 1]; + args[argc - 1] = NULL; +@@ -303,7 +307,8 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) + ctxt->state[0].args, ctxt->state[4].arg, + users, + ctxt->state[2].arg, prefix, src + 1, +- ctxt->extcmd->cmd->name[0] == 's'); ++ ctxt->extcmd->cmd->name[0] == 's', ++ ctxt->extcmd->cmd->name[0] == 'h'); + + src[len - 1] = ch; + args[argc - 1] = src; +@@ -311,7 +316,7 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) + return r; + } + +-static grub_extcmd_t cmd, cmd_sub; ++static grub_extcmd_t cmd, cmd_sub, cmd_hidden; + + void + grub_menu_init (void) +@@ -327,6 +332,13 @@ grub_menu_init (void) + | GRUB_COMMAND_FLAG_EXTRACTOR, + N_("BLOCK"), N_("Define a submenu."), + options); ++ cmd_hidden = grub_register_extcmd ("hiddenentry", grub_cmd_menuentry, ++ GRUB_COMMAND_FLAG_BLOCKS ++ | GRUB_COMMAND_ACCEPT_DASH ++ | GRUB_COMMAND_FLAG_EXTRACTOR, ++ N_("BLOCK"), ++ N_("Define a hidden menu entry."), ++ options); + } + + void +diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c +index 719e2fb..2a151fe 100644 +--- a/grub-core/normal/menu.c ++++ b/grub-core/normal/menu.c +@@ -40,6 +40,8 @@ + grub_err_t (*grub_gfxmenu_try_hook) (int entry, grub_menu_t menu, + int nested) = NULL; + ++#define MENU_INCLUDE_HIDDEN 0x10000 ++ + enum timeout_style { + TIMEOUT_STYLE_MENU, + TIMEOUT_STYLE_COUNTDOWN, +@@ -80,8 +82,20 @@ grub_menu_get_entry (grub_menu_t menu, int no) + { + grub_menu_entry_t e; + +- for (e = menu->entry_list; e && no > 0; e = e->next, no--) +- ; ++ if (no & MENU_INCLUDE_HIDDEN) { ++ no &= ~MENU_INCLUDE_HIDDEN; ++ ++ for (e = menu->entry_list; e && no > 0; e = e->next, no--) ++ ; ++ } else { ++ for (e = menu->entry_list; e && no > 0; e = e->next, no--) { ++ /* Skip hidden entries */ ++ while (e && e->hidden) ++ e = e->next; ++ } ++ while (e && e->hidden) ++ e = e->next; ++ } + + return e; + } +@@ -93,10 +107,10 @@ get_entry_index_by_hotkey (grub_menu_t menu, int hotkey) + grub_menu_entry_t entry; + int i; + +- for (i = 0, entry = menu->entry_list; i < menu->size; ++ for (i = 0, entry = menu->entry_list; entry; + i++, entry = entry->next) + if (entry->hotkey == hotkey) +- return i; ++ return i | MENU_INCLUDE_HIDDEN; + + return -1; + } +@@ -510,6 +524,10 @@ get_entry_number (grub_menu_t menu, const char *name) + grub_menu_entry_t e = menu->entry_list; + int i; + ++ /* Skip hidden entries */ ++ while (e && e->hidden) ++ e = e->next; ++ + grub_errno = GRUB_ERR_NONE; + + for (i = 0; e; i++) +@@ -521,6 +539,10 @@ get_entry_number (grub_menu_t menu, const char *name) + break; + } + e = e->next; ++ ++ /* Skip hidden entries */ ++ while (e && e->hidden) ++ e = e->next; + } + + if (! e) +diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c +index e22bb91..4ac2d6b 100644 +--- a/grub-core/normal/menu_text.c ++++ b/grub-core/normal/menu_text.c +@@ -290,6 +290,10 @@ print_entries (grub_menu_t menu, const struct menu_viewer_data *data) + e, data); + if (e) + e = e->next; ++ ++ /* Skip hidden entries */ ++ while (e && e->hidden) ++ e = e->next; + } + + grub_term_gotoxy (data->term, +diff --git a/include/grub/menu.h b/include/grub/menu.h +index ee2b5e9..eb8a86b 100644 +--- a/include/grub/menu.h ++++ b/include/grub/menu.h +@@ -58,6 +58,8 @@ struct grub_menu_entry + + int submenu; + ++ int hidden; ++ + /* The next element. */ + struct grub_menu_entry *next; + }; +diff --git a/include/grub/normal.h b/include/grub/normal.h +index 218cbab..bcb4124 100644 +--- a/include/grub/normal.h ++++ b/include/grub/normal.h +@@ -145,7 +145,7 @@ grub_normal_add_menu_entry (int argc, const char **args, char **classes, + const char *id, + const char *users, const char *hotkey, + const char *prefix, const char *sourcecode, +- int submenu); ++ int submenu, int hidden); + + grub_err_t + grub_normal_set_password (const char *user, const char *password); diff --git a/grub2-Fix-incorrect-netmask-on-ppc64.patch b/grub2-Fix-incorrect-netmask-on-ppc64.patch new file mode 100644 index 0000000..23abad0 --- /dev/null +++ b/grub2-Fix-incorrect-netmask-on-ppc64.patch @@ -0,0 +1,41 @@ +From: Masahiro Matsuya + +The netmask configured in firmware is not respected on ppc64 (big endian). +When 255.255.252.0 is set as netmask in firmware, the following is the value of bootpath string in grub_ieee1275_parse_bootpath(). + + /vdevice/l-lan@30000002:speed=auto,duplex=auto,192.168.88.10,,192.168.89.113,192.168.88.1,5,5,255.255.252.0,512 + +The netmask in this bootpath is no problem, since it's a value specified in firmware. But, +The value of 'subnet_mask.ipv4' was set with 0xfffffc00, and __builtin_ctz (~grub_le_to_cpu32 (subnet_mask.ipv4)) returned 16 (not 22). +As a result, 16 was used for netmask wrongly. + +1111 1111 1111 1111 1111 1100 0000 0000 # subnet_mask.ipv4 (=0xfffffc00) +0000 0000 1111 1100 1111 1111 1111 1111 # grub_le_to_cpu32 (subnet_mask.ipv4) +1111 1111 0000 0011 0000 0000 0000 0000 # ~grub_le_to_cpu32 (subnet_mask.ipv4) + +And, the count of zero with __builtin_ctz can be 16. +This patch changes it as below. + +1111 1111 1111 1111 1111 1100 0000 0000 # subnet_mask.ipv4 (=0xfffffc00) +0000 0000 1111 1100 1111 1111 1111 1111 # grub_le_to_cpu32 (subnet_mask.ipv4) +1111 1111 1111 1111 1111 1100 0000 0000 # grub_swap_bytes32(grub_le_to_cpu32 (subnet_mask.ipv4)) +0000 0000 0000 0000 0000 0011 1111 1111 # ~grub_swap_bytes32(grub_le_to_cpu32 (subnet_mask.ipv4)) + +The count of zero with __builtin_clz can be 22. (clz counts the number of one bits preceding the most significant zero bit) +--- + grub-core/net/drivers/ieee1275/ofnet.c | 2 +- + 1 file changed, 1 insertion(+), 2 deletions(-) + +Index: grub-2.04~rc1/grub-core/net/drivers/ieee1275/ofnet.c +=================================================================== +--- grub-2.04~rc1.orig/grub-core/net/drivers/ieee1275/ofnet.c ++++ grub-2.04~rc1/grub-core/net/drivers/ieee1275/ofnet.c +@@ -220,7 +220,7 @@ grub_ieee1275_parse_bootpath (const char + flags); + inter->vlantag = vlantag; + grub_net_add_ipv4_local (inter, +- __builtin_ctz (~grub_le_to_cpu32 (subnet_mask.ipv4))); ++ __builtin_clz (~ (subnet_mask.ipv4))); + + } + diff --git a/grub2-GRUB_CMDLINE_LINUX_RECOVERY-for-recovery-mode.patch b/grub2-GRUB_CMDLINE_LINUX_RECOVERY-for-recovery-mode.patch new file mode 100644 index 0000000..8cd504d --- /dev/null +++ b/grub2-GRUB_CMDLINE_LINUX_RECOVERY-for-recovery-mode.patch @@ -0,0 +1,46 @@ +From 6225854682a736e4312ce15b34c90fff03b002db Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Fri, 6 Jul 2012 15:55:18 +0800 +Subject: [PATCH] add GRUB_CMDLINE_LINUX_RECOVERY for recovery mode + +References: [openSUSE-factory] Has FailSafe or Safe Mode been removed + permanently from 12.2? +Patch-Mainline: no + +We adapt the script a bit in order to support openSUSE's failsafe +booting mode. We don't use single user mode but with specific kernel +command line options decided in YaST. These command line could be +applied to grub2's recovery mode via the new setting +GRUB_CMDLINE_LINUX_RECOVERY. +--- + util/grub-mkconfig.in | 3 ++- + util/grub.d/10_linux.in | 2 +- + 2 files changed, 3 insertions(+), 2 deletions(-) + +Index: grub-2.02~beta2/util/grub-mkconfig.in +=================================================================== +--- grub-2.02~beta2.orig/util/grub-mkconfig.in ++++ grub-2.02~beta2/util/grub-mkconfig.in +@@ -227,7 +227,8 @@ export GRUB_DEFAULT \ + GRUB_ENABLE_CRYPTODISK \ + GRUB_BADRAM \ + GRUB_OS_PROBER_SKIP_LIST \ +- GRUB_DISABLE_SUBMENU ++ GRUB_DISABLE_SUBMENU \ ++ GRUB_CMDLINE_LINUX_RECOVERY + + if test "x${grub_cfg}" != "x"; then + rm -f "${grub_cfg}.new" +Index: grub-2.02~beta2/util/grub.d/10_linux.in +=================================================================== +--- grub-2.02~beta2.orig/util/grub.d/10_linux.in ++++ grub-2.02~beta2/util/grub.d/10_linux.in +@@ -240,7 +240,7 @@ while [ "x$list" != "x" ] ; do + "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" + if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then + linux_entry "${OS}" "${version}" recovery \ +- "single ${GRUB_CMDLINE_LINUX}" ++ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_RECOVERY}" + fi + + list=`echo $list | tr ' ' '\n' | fgrep -vx "$linux" | tr '\n' ' '` diff --git a/grub2-SUSE-Add-the-t-hotkey.patch b/grub2-SUSE-Add-the-t-hotkey.patch new file mode 100644 index 0000000..3937022 --- /dev/null +++ b/grub2-SUSE-Add-the-t-hotkey.patch @@ -0,0 +1,72 @@ +From f6be3d41e24e685846dfc90ac1ca447501813687 Mon Sep 17 00:00:00 2001 +From: Alexander Graf +Date: Tue, 26 Apr 2016 15:59:03 +0200 +Subject: [PATCH] SUSE: Add the "t" hotkey + +While graphical output is fancy and nice, in some environments (EFI) we can +only have fancy graphical on frame buffer _or_ ugly serial on any output. + +To give the user a nicely graphical screen in the default case, but still +allow them to get their boot menu on the serial console, let's add a new +hidden option "t" that switches the output device back to the firmware default. + +Signed-off-by: Alexander Graf +--- + +v1 -> v2 + + - use hiddenentry instead of --hidden + +v2 -> v3 (by fvogt@suse.de) + + - make it a runtime decision (bsc#1164385) + +Index: grub-2.04/Makefile.util.def +=================================================================== +--- grub-2.04.orig/Makefile.util.def ++++ grub-2.04/Makefile.util.def +@@ -525,6 +525,12 @@ script = { + installdir = grubconf; + }; + ++script = { ++ name = '95_textmode'; ++ common = util/grub.d/95_textmode.in; ++ installdir = grubconf; ++}; ++ + program = { + mansection = 1; + name = grub-mkrescue; +Index: grub-2.04/util/grub.d/00_header.in +=================================================================== +--- grub-2.04.orig/util/grub.d/00_header.in ++++ grub-2.04/util/grub.d/00_header.in +@@ -240,6 +240,10 @@ EOF + fi + + cat << EOF ++ if [ "\${grub_platform}" = "efi" ]; then ++ echo "Please press 't' to show the boot menu on this console" ++ fi ++ + set gfxmode=${GRUB_GFXMODE} + load_video + insmod gfxterm +Index: grub-2.04/util/grub.d/95_textmode.in +=================================================================== +--- /dev/null ++++ grub-2.04/util/grub.d/95_textmode.in +@@ -0,0 +1,12 @@ ++#!/bin/sh ++ ++cat < +Subject: grub2/btrfs: Add ability to boot from subvolumes + +This patch adds the ability to specify a different root on a btrfs +filesystem too boot from other than the default one. + +btrfs-list-snapshots will list the subvolumes available on the +filesystem. + +set btrfs_subvol= and set btrfs_subvolid= will specify +which subvolume to use and any pathnames provided with either of those +variables set will start using that root. If the subvolume or subvolume id +doesn't exist, then an error case will result. + +It is possible to boot into a separate GRUB instance by exporting the +variable and loading the config file from the subvolume. + +Signed-off-by: Jeff Mahoney + +V1: + * Use overflow checking primitives where the arithmetic expression for + buffer allocations may include unvalidated data + +--- + + grub-core/fs/btrfs.c | 529 +++++++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 518 insertions(+), 11 deletions(-) + +Index: grub-2.06~rc1/grub-core/fs/btrfs.c +=================================================================== +--- grub-2.06~rc1.orig/grub-core/fs/btrfs.c ++++ grub-2.06~rc1/grub-core/fs/btrfs.c +@@ -41,6 +41,9 @@ + #include + #include + #include ++#include ++#include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -79,9 +82,11 @@ struct grub_btrfs_superblock + grub_uint64_t generation; + grub_uint64_t root_tree; + grub_uint64_t chunk_tree; +- grub_uint8_t dummy2[0x20]; ++ grub_uint8_t dummy2[0x18]; ++ grub_uint64_t bytes_used; + grub_uint64_t root_dir_objectid; +- grub_uint8_t dummy3[0x41]; ++ grub_uint64_t num_devices; ++ grub_uint8_t dummy3[0x39]; + struct grub_btrfs_device this_device; + char label[0x100]; + grub_uint8_t dummy4[0x100]; +@@ -121,6 +126,7 @@ struct grub_btrfs_data + grub_uint64_t exttree; + grub_size_t extsize; + struct grub_btrfs_extent_data *extent; ++ grub_uint64_t fs_tree; + }; + + struct grub_btrfs_chunk_item +@@ -191,6 +197,14 @@ struct grub_btrfs_leaf_descriptor + } *data; + }; + ++struct grub_btrfs_root_ref ++{ ++ grub_uint64_t dirid; ++ grub_uint64_t sequence; ++ grub_uint16_t name_len; ++ const char name[0]; ++} __attribute__ ((packed)); ++ + struct grub_btrfs_time + { + grub_int64_t sec; +@@ -236,6 +250,14 @@ struct grub_btrfs_extent_data + + #define GRUB_BTRFS_OBJECT_ID_CHUNK 0x100 + ++#define GRUB_BTRFS_ROOT_TREE_OBJECTID 1ULL ++#define GRUB_BTRFS_FS_TREE_OBJECTID 5ULL ++#define GRUB_BTRFS_ROOT_REF_KEY 156 ++#define GRUB_BTRFS_ROOT_ITEM_KEY 132 ++ ++static grub_uint64_t btrfs_default_subvolid = 0; ++static char *btrfs_default_subvol = NULL; ++ + static grub_disk_addr_t superblock_sectors[] = { 64 * 2, 64 * 1024 * 2, + 256 * 1048576 * 2, 1048576ULL * 1048576ULL * 2 + }; +@@ -1173,6 +1195,62 @@ grub_btrfs_read_logical (struct grub_btr + return GRUB_ERR_NONE; + } + ++static grub_err_t ++get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree, ++ grub_uint64_t objectid, grub_uint64_t offset, ++ grub_uint64_t *fs_root); ++ ++static grub_err_t ++lookup_root_by_id(struct grub_btrfs_data *data, grub_uint64_t id) ++{ ++ grub_err_t err; ++ grub_uint64_t tree; ++ ++ err = get_fs_root(data, data->sblock.root_tree, id, -1, &tree); ++ if (!err) ++ data->fs_tree = tree; ++ return err; ++} ++ ++static grub_err_t ++find_path (struct grub_btrfs_data *data, ++ const char *path, struct grub_btrfs_key *key, ++ grub_uint64_t *tree, grub_uint8_t *type); ++ ++static grub_err_t ++lookup_root_by_name(struct grub_btrfs_data *data, const char *path) ++{ ++ grub_err_t err; ++ grub_uint64_t tree = 0; ++ grub_uint8_t type; ++ struct grub_btrfs_key key; ++ ++ err = find_path (data, path, &key, &tree, &type); ++ if (err) ++ return grub_error(GRUB_ERR_FILE_NOT_FOUND, "couldn't locate %s\n", path); ++ ++ if (key.object_id != grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0) ++ return grub_error(GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n", path); ++ ++ data->fs_tree = tree; ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++btrfs_handle_subvol(struct grub_btrfs_data *data __attribute__ ((unused))) ++{ ++ if (btrfs_default_subvol) ++ return lookup_root_by_name(data, btrfs_default_subvol); ++ ++ if (btrfs_default_subvolid) ++ return lookup_root_by_id(data, btrfs_default_subvolid); ++ ++ data->fs_tree = 0; ++ ++ return GRUB_ERR_NONE; ++} ++ ++ + static struct grub_btrfs_data * + grub_btrfs_mount (grub_device_t dev) + { +@@ -1208,6 +1286,13 @@ grub_btrfs_mount (grub_device_t dev) + data->devices_attached[0].dev = dev; + data->devices_attached[0].id = data->sblock.this_device.device_id; + ++ err = btrfs_handle_subvol (data); ++ if (err) ++ { ++ grub_free (data); ++ return NULL; ++ } ++ + return data; + } + +@@ -1674,6 +1759,98 @@ get_root (struct grub_btrfs_data *data, + } + + static grub_err_t ++find_pathname(struct grub_btrfs_data *data, grub_uint64_t objectid, ++ grub_uint64_t fs_root, const char *name, char **pathname) ++{ ++ grub_err_t err; ++ struct grub_btrfs_key key = { ++ .object_id = objectid, ++ .type = GRUB_BTRFS_ITEM_TYPE_INODE_REF, ++ .offset = 0, ++ }; ++ struct grub_btrfs_key key_out; ++ struct grub_btrfs_leaf_descriptor desc; ++ char *p = grub_strdup (name); ++ grub_disk_addr_t elemaddr; ++ grub_size_t elemsize; ++ grub_size_t alloc = grub_strlen(name) + 1; ++ ++ err = lower_bound(data, &key, &key_out, fs_root, ++ &elemaddr, &elemsize, &desc, 0); ++ if (err) ++ return grub_error(err, "lower_bound caught %d\n", err); ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF) ++ next(data, &desc, &elemaddr, &elemsize, &key_out); ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF) ++ { ++ return grub_error(GRUB_ERR_FILE_NOT_FOUND, ++ "Can't find inode ref for {%"PRIuGRUB_UINT64_T ++ ", %u, %"PRIuGRUB_UINT64_T"} %"PRIuGRUB_UINT64_T ++ "/%"PRIuGRUB_SIZE"\n", ++ key_out.object_id, key_out.type, ++ key_out.offset, elemaddr, elemsize); ++ } ++ ++ ++ while (key_out.type == GRUB_BTRFS_ITEM_TYPE_INODE_REF && ++ key_out.object_id != key_out.offset) { ++ struct grub_btrfs_inode_ref *inode_ref; ++ char *new; ++ grub_size_t sz; ++ ++ if (grub_add (elemsize, 1, &sz)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); ++ ++ inode_ref = grub_malloc(sz); ++ if (!inode_ref) ++ return grub_error(GRUB_ERR_OUT_OF_MEMORY, ++ "couldn't allocate memory for inode_ref (%"PRIuGRUB_SIZE")\n", elemsize); ++ ++ err = grub_btrfs_read_logical(data, elemaddr, inode_ref, elemsize, 0); ++ if (err) ++ return grub_error(err, "read_logical caught %d\n", err); ++ ++ if (grub_add (grub_le_to_cpu16 (inode_ref->n), 2, &sz) || ++ grub_add (alloc, sz, &alloc)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); ++ ++ new = grub_malloc(alloc); ++ if (!new) ++ return grub_error(GRUB_ERR_OUT_OF_MEMORY, ++ "couldn't allocate memory for name (%"PRIuGRUB_SIZE")\n", alloc); ++ ++ grub_memcpy(new, inode_ref->name, grub_le_to_cpu16 (inode_ref->n)); ++ if (p) ++ { ++ new[grub_le_to_cpu16 (inode_ref->n)] = '/'; ++ grub_strcpy (new + grub_le_to_cpu16 (inode_ref->n) + 1, p); ++ grub_free(p); ++ } ++ else ++ new[grub_le_to_cpu16 (inode_ref->n)] = 0; ++ grub_free(inode_ref); ++ ++ p = new; ++ ++ key.object_id = key_out.offset; ++ ++ err = lower_bound(data, &key, &key_out, fs_root, &elemaddr, ++ &elemsize, &desc, 0); ++ if (err) ++ return grub_error(err, "lower_bound caught %d\n", err); ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF) ++ next(data, &desc, &elemaddr, &elemsize, &key_out); ++ ++ } ++ ++ *pathname = p; ++ return 0; ++} ++ ++static grub_err_t + find_path (struct grub_btrfs_data *data, + const char *path, struct grub_btrfs_key *key, + grub_uint64_t *tree, grub_uint8_t *type) +@@ -1691,14 +1868,26 @@ find_path (struct grub_btrfs_data *data, + char *origpath = NULL; + unsigned symlinks_max = 32; + +- err = get_root (data, key, tree, type); +- if (err) +- return err; +- + origpath = grub_strdup (path); + if (!origpath) + return grub_errno; + ++ if (data->fs_tree) ++ { ++ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; ++ *tree = data->fs_tree; ++ /* This is a tree root, so everything starts at objectid 256 */ ++ key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); ++ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; ++ key->offset = 0; ++ } ++ else ++ { ++ err = get_root (data, key, tree, type); ++ if (err) ++ return err; ++ } ++ + while (1) + { + while (path[0] == '/') +@@ -1871,9 +2060,21 @@ find_path (struct grub_btrfs_data *data, + path = path_alloc = tmp; + if (path[0] == '/') + { +- err = get_root (data, key, tree, type); +- if (err) +- return err; ++ if (data->fs_tree) ++ { ++ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; ++ *tree = data->fs_tree; ++ /* This is a tree root, so everything starts at objectid 256 */ ++ key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); ++ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; ++ key->offset = 0; ++ } ++ else ++ { ++ err = get_root (data, key, tree, type); ++ if (err) ++ return err; ++ } + } + continue; + } +@@ -2114,6 +2315,20 @@ grub_btrfs_read (grub_file_t file, char + data->tree, file->offset, buf, len); + } + ++static char * ++btrfs_unparse_uuid(struct grub_btrfs_data *data) ++{ ++ return grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x", ++ grub_be_to_cpu16 (data->sblock.uuid[0]), ++ grub_be_to_cpu16 (data->sblock.uuid[1]), ++ grub_be_to_cpu16 (data->sblock.uuid[2]), ++ grub_be_to_cpu16 (data->sblock.uuid[3]), ++ grub_be_to_cpu16 (data->sblock.uuid[4]), ++ grub_be_to_cpu16 (data->sblock.uuid[5]), ++ grub_be_to_cpu16 (data->sblock.uuid[6]), ++ grub_be_to_cpu16 (data->sblock.uuid[7])); ++} ++ + static grub_err_t + grub_btrfs_uuid (grub_device_t device, char **uuid) + { +@@ -2125,15 +2340,7 @@ grub_btrfs_uuid (grub_device_t device, c + if (!data) + return grub_errno; + +- *uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x", +- grub_be_to_cpu16 (data->sblock.uuid[0]), +- grub_be_to_cpu16 (data->sblock.uuid[1]), +- grub_be_to_cpu16 (data->sblock.uuid[2]), +- grub_be_to_cpu16 (data->sblock.uuid[3]), +- grub_be_to_cpu16 (data->sblock.uuid[4]), +- grub_be_to_cpu16 (data->sblock.uuid[5]), +- grub_be_to_cpu16 (data->sblock.uuid[6]), +- grub_be_to_cpu16 (data->sblock.uuid[7])); ++ *uuid = btrfs_unparse_uuid(data); + + grub_btrfs_unmount (data); + +@@ -2190,6 +2397,248 @@ grub_btrfs_embed (grub_device_t device _ + } + #endif + ++static grub_err_t ++grub_cmd_btrfs_info (grub_command_t cmd __attribute__ ((unused)), int argc, ++ char **argv) ++{ ++ grub_device_t dev; ++ char *devname; ++ struct grub_btrfs_data *data; ++ char *uuid; ++ ++ if (argc < 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); ++ ++ devname = grub_file_get_device_name(argv[0]); ++ ++ if (!devname) ++ return grub_errno; ++ ++ dev = grub_device_open (devname); ++ grub_free (devname); ++ if (!dev) ++ return grub_errno; ++ ++ data = grub_btrfs_mount (dev); ++ if (!data) ++ { ++ grub_device_close(dev); ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "failed to open fs"); ++ } ++ ++ if (data->sblock.label) ++ grub_printf("Label: '%s' ", data->sblock.label); ++ else ++ grub_printf("Label: none "); ++ ++ uuid = btrfs_unparse_uuid(data); ++ ++ grub_printf(" uuid: %s\n\tTotal devices %" PRIuGRUB_UINT64_T ++ " FS bytes used %" PRIuGRUB_UINT64_T "\n", ++ uuid, grub_cpu_to_le64(data->sblock.num_devices), ++ grub_cpu_to_le64(data->sblock.bytes_used)); ++ ++ grub_btrfs_unmount (data); ++ ++ return 0; ++} ++ ++static grub_err_t ++get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree, ++ grub_uint64_t objectid, grub_uint64_t offset, ++ grub_uint64_t *fs_root) ++{ ++ grub_err_t err; ++ struct grub_btrfs_key key_in = { ++ .object_id = objectid, ++ .type = GRUB_BTRFS_ROOT_ITEM_KEY, ++ .offset = offset, ++ }, key_out; ++ struct grub_btrfs_leaf_descriptor desc; ++ grub_disk_addr_t elemaddr; ++ grub_size_t elemsize; ++ struct grub_btrfs_root_item ri; ++ ++ err = lower_bound(data, &key_in, &key_out, tree, ++ &elemaddr, &elemsize, &desc, 0); ++ ++ if (err) ++ return err; ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM || elemaddr == 0) ++ return grub_error(GRUB_ERR_FILE_NOT_FOUND, ++ N_("can't find fs root for subvol %"PRIuGRUB_UINT64_T"\n"), ++ key_in.object_id); ++ ++ err = grub_btrfs_read_logical (data, elemaddr, &ri, sizeof (ri), 0); ++ if (err) ++ return err; ++ ++ *fs_root = ri.tree; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static const struct grub_arg_option options[] = { ++ {"output", 'o', 0, N_("Output to a variable instead of the console."), ++ N_("VARNAME"), ARG_TYPE_STRING}, ++ {"path-only", 'p', 0, N_("Show only the path of the subvolume."), 0, 0}, ++ {"id-only", 'i', 0, N_("Show only the id of the subvolume."), 0, 0}, ++ {0, 0, 0, 0, 0, 0} ++}; ++ ++static grub_err_t ++grub_cmd_btrfs_list_subvols (struct grub_extcmd_context *ctxt, ++ int argc, char **argv) ++{ ++ struct grub_btrfs_data *data; ++ grub_device_t dev; ++ char *devname; ++ grub_uint64_t tree; ++ struct grub_btrfs_key key_in = { ++ .object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_FS_TREE_OBJECTID), ++ .type = GRUB_BTRFS_ROOT_REF_KEY, ++ .offset = 0, ++ }, key_out; ++ struct grub_btrfs_leaf_descriptor desc; ++ grub_disk_addr_t elemaddr; ++ grub_uint64_t fs_root = 0; ++ grub_size_t elemsize; ++ grub_size_t allocated = 0; ++ int r = 0; ++ grub_err_t err; ++ char *buf = NULL; ++ int print = 1; ++ int path_only = ctxt->state[1].set; ++ int num_only = ctxt->state[2].set; ++ char *varname = NULL; ++ char *output = NULL; ++ ++ if (ctxt->state[0].set) { ++ varname = ctxt->state[0].arg; ++ print = 0; ++ } ++ ++ if (argc < 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); ++ ++ devname = grub_file_get_device_name(argv[0]); ++ if (!devname) ++ return grub_errno; ++ ++ dev = grub_device_open (devname); ++ grub_free (devname); ++ if (!dev) ++ return grub_errno; ++ ++ data = grub_btrfs_mount(dev); ++ if (!data) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "could not open device"); ++ ++ tree = data->sblock.root_tree; ++ err = get_fs_root(data, tree, grub_cpu_to_le64_compile_time (GRUB_BTRFS_FS_TREE_OBJECTID), ++ 0, &fs_root); ++ if (err) ++ goto out; ++ ++ err = lower_bound(data, &key_in, &key_out, tree, ++ &elemaddr, &elemsize, &desc, 0); ++ ++ if (err) ++ { ++ grub_btrfs_unmount(data); ++ return err; ++ } ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF || elemaddr == 0) ++ { ++ r = next(data, &desc, &elemaddr, &elemsize, &key_out); ++ } ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF) { ++ err = GRUB_ERR_FILE_NOT_FOUND; ++ grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("can't find root refs")); ++ goto out; ++ } ++ ++ do ++ { ++ struct grub_btrfs_root_ref *ref; ++ char *p = NULL; ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF) ++ { ++ r = 0; ++ break; ++ } ++ ++ if (elemsize > allocated) ++ { ++ grub_size_t sz; ++ ++ grub_free(buf); ++ ++ if (grub_mul (elemsize, 2, &allocated) || ++ grub_add (allocated, 1, &sz)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); ++ ++ buf = grub_malloc(sz); ++ if (!buf) ++ { ++ r = -grub_errno; ++ break; ++ } ++ } ++ ref = (struct grub_btrfs_root_ref *)buf; ++ ++ err = grub_btrfs_read_logical(data, elemaddr, buf, elemsize, 0); ++ if (err) ++ { ++ r = -err; ++ break; ++ } ++ buf[elemsize] = 0; ++ ++ find_pathname(data, ref->dirid, fs_root, ref->name, &p); ++ ++ if (print) ++ { ++ if (num_only) ++ grub_printf("ID %"PRIuGRUB_UINT64_T"\n", key_out.offset); ++ else if (path_only) ++ grub_printf("%s\n", p); ++ else ++ grub_printf("ID %"PRIuGRUB_UINT64_T" path %s\n", key_out.offset, p); ++ } else { ++ char *old = output; ++ if (num_only) ++ output = grub_xasprintf("%s%"PRIuGRUB_UINT64_T"\n", ++ old ?: "", key_out.offset); ++ else if (path_only) ++ output = grub_xasprintf("%s%s\n", old ?: "", p); ++ else ++ output = grub_xasprintf("%sID %"PRIuGRUB_UINT64_T" path %s\n", ++ old ?: "", key_out.offset, p); ++ ++ if (old) ++ grub_free(old); ++ } ++ ++ r = next(data, &desc, &elemaddr, &elemsize, &key_out); ++ } while(r > 0); ++ ++ if (output) ++ grub_env_set(varname, output); ++ ++out: ++ free_iterator(&desc); ++ grub_btrfs_unmount(data); ++ ++ grub_device_close (dev); ++ ++ return 0; ++} ++ + static struct grub_fs grub_btrfs_fs = { + .name = "btrfs", + .fs_dir = grub_btrfs_dir, +@@ -2205,12 +2654,88 @@ static struct grub_fs grub_btrfs_fs = { + #endif + }; + ++static grub_command_t cmd_info; ++static grub_extcmd_t cmd_list_subvols; ++ ++static char * ++subvolid_set_env (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val) ++{ ++ unsigned long long result = 0; ++ ++ grub_errno = GRUB_ERR_NONE; ++ if (*val) ++ { ++ result = grub_strtoull(val, NULL, 10); ++ if (grub_errno) ++ return NULL; ++ } ++ ++ grub_free (btrfs_default_subvol); ++ btrfs_default_subvol = NULL; ++ btrfs_default_subvolid = result; ++ return grub_strdup(val); ++} ++ ++static const char * ++subvolid_get_env (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ if (btrfs_default_subvol) ++ return grub_xasprintf("subvol:%s", btrfs_default_subvol); ++ else if (btrfs_default_subvolid) ++ return grub_xasprintf("%"PRIuGRUB_UINT64_T, btrfs_default_subvolid); ++ else ++ return ""; ++} ++ ++static char * ++subvol_set_env (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val) ++{ ++ grub_free (btrfs_default_subvol); ++ btrfs_default_subvol = grub_strdup (val); ++ btrfs_default_subvolid = 0; ++ return grub_strdup(val); ++} ++ ++static const char * ++subvol_get_env (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ if (btrfs_default_subvol) ++ return btrfs_default_subvol; ++ else if (btrfs_default_subvolid) ++ return grub_xasprintf("subvolid:%" PRIuGRUB_UINT64_T, ++ btrfs_default_subvolid); ++ else ++ return ""; ++} ++ + GRUB_MOD_INIT (btrfs) + { + grub_fs_register (&grub_btrfs_fs); ++ cmd_info = grub_register_command("btrfs-info", grub_cmd_btrfs_info, ++ "DEVICE", ++ "Print BtrFS info about DEVICE."); ++ cmd_list_subvols = grub_register_extcmd("btrfs-list-subvols", ++ grub_cmd_btrfs_list_subvols, 0, ++ "[-p|-n] [-o var] DEVICE", ++ "Print list of BtrFS subvolumes on " ++ "DEVICE.", options); ++ grub_register_variable_hook ("btrfs_subvol", subvol_get_env, ++ subvol_set_env); ++ grub_register_variable_hook ("btrfs_subvolid", subvolid_get_env, ++ subvolid_set_env); + } + + GRUB_MOD_FINI (btrfs) + { ++ grub_register_variable_hook ("btrfs_subvol", NULL, NULL); ++ grub_register_variable_hook ("btrfs_subvolid", NULL, NULL); ++ grub_unregister_command (cmd_info); ++ grub_unregister_extcmd (cmd_list_subvols); + grub_fs_unregister (&grub_btrfs_fs); + } ++ ++// vim: si et sw=2: +Index: grub-2.06~rc1/include/grub/btrfs.h +=================================================================== +--- grub-2.06~rc1.orig/include/grub/btrfs.h ++++ grub-2.06~rc1/include/grub/btrfs.h +@@ -29,6 +29,7 @@ enum + GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM = 0x84, + GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF = 0x90, + GRUB_BTRFS_ITEM_TYPE_DEVICE = 0xd8, ++ GRUB_BTRFS_ITEM_TYPE_ROOT_REF = 0x9c, + GRUB_BTRFS_ITEM_TYPE_CHUNK = 0xe4 + }; + diff --git a/grub2-btrfs-02-export-subvolume-envvars.patch b/grub2-btrfs-02-export-subvolume-envvars.patch new file mode 100644 index 0000000..68cc10b --- /dev/null +++ b/grub2-btrfs-02-export-subvolume-envvars.patch @@ -0,0 +1,21 @@ +From: Michael Chang +Subject: export btrfs_subvol and btrfs_subvolid + +We should export btrfs_subvol and btrfs_subvolid to have both visible +to subsidiary configuration files loaded using configfile. + +Signed-off-by: Michael Chang + +Index: grub-2.00/grub-core/fs/btrfs.c +=================================================================== +--- grub-2.00.orig/grub-core/fs/btrfs.c ++++ grub-2.00/grub-core/fs/btrfs.c +@@ -2252,6 +2252,8 @@ GRUB_MOD_INIT (btrfs) + subvol_set_env); + grub_register_variable_hook ("btrfs_subvolid", subvolid_get_env, + subvolid_set_env); ++ grub_env_export ("btrfs_subvol"); ++ grub_env_export ("btrfs_subvolid"); + } + + GRUB_MOD_FINI (btrfs) diff --git a/grub2-btrfs-03-follow_default.patch b/grub2-btrfs-03-follow_default.patch new file mode 100644 index 0000000..751cada --- /dev/null +++ b/grub2-btrfs-03-follow_default.patch @@ -0,0 +1,187 @@ +Index: grub-2.02~beta2/grub-core/fs/btrfs.c +=================================================================== +--- grub-2.02~beta2.orig/grub-core/fs/btrfs.c ++++ grub-2.02~beta2/grub-core/fs/btrfs.c +@@ -913,6 +913,7 @@ grub_btrfs_mount (grub_device_t dev) + { + struct grub_btrfs_data *data; + grub_err_t err; ++ const char *relpath = grub_env_get ("btrfs_relative_path"); + + if (!dev->disk) + { +@@ -943,11 +944,14 @@ grub_btrfs_mount (grub_device_t dev) + data->devices_attached[0].dev = dev; + data->devices_attached[0].id = data->sblock.this_device.device_id; + +- err = btrfs_handle_subvol (data); +- if (err) ++ if (relpath && (relpath[0] == '1' || relpath[0] == 'y')) + { +- grub_free (data); +- return NULL; ++ err = btrfs_handle_subvol (data); ++ if (err) ++ { ++ grub_free (data); ++ return NULL; ++ } + } + + return data; +@@ -1407,24 +1411,39 @@ find_path (struct grub_btrfs_data *data, + grub_size_t allocated = 0; + struct grub_btrfs_dir_item *direl = NULL; + struct grub_btrfs_key key_out; ++ int follow_default; + const char *ctoken; + grub_size_t ctokenlen; + char *path_alloc = NULL; + char *origpath = NULL; + unsigned symlinks_max = 32; ++ const char *relpath = grub_env_get ("btrfs_relative_path"); + ++ follow_default = 0; + origpath = grub_strdup (path); + if (!origpath) + return grub_errno; + +- if (data->fs_tree) ++ if (relpath && (relpath[0] == '1' || relpath[0] == 'y')) + { +- *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; +- *tree = data->fs_tree; +- /* This is a tree root, so everything starts at objectid 256 */ +- key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); +- key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; +- key->offset = 0; ++ if (data->fs_tree) ++ { ++ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; ++ *tree = data->fs_tree; ++ /* This is a tree root, so everything starts at objectid 256 */ ++ key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); ++ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; ++ key->offset = 0; ++ } ++ else ++ { ++ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; ++ *tree = data->sblock.root_tree; ++ key->object_id = data->sblock.root_dir_objectid; ++ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; ++ key->offset = 0; ++ follow_default = 1; ++ } + } + else + { +@@ -1435,15 +1454,23 @@ find_path (struct grub_btrfs_data *data, + + while (1) + { +- while (path[0] == '/') +- path++; +- if (!path[0]) +- break; +- slash = grub_strchr (path, '/'); +- if (!slash) +- slash = path + grub_strlen (path); +- ctoken = path; +- ctokenlen = slash - path; ++ if (!follow_default) ++ { ++ while (path[0] == '/') ++ path++; ++ if (!path[0]) ++ break; ++ slash = grub_strchr (path, '/'); ++ if (!slash) ++ slash = path + grub_strlen (path); ++ ctoken = path; ++ ctokenlen = slash - path; ++ } ++ else ++ { ++ ctoken = "default"; ++ ctokenlen = sizeof ("default") - 1; ++ } + + if (*type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY) + { +@@ -1454,7 +1481,9 @@ find_path (struct grub_btrfs_data *data, + + if (ctokenlen == 1 && ctoken[0] == '.') + { +- path = slash; ++ if (!follow_default) ++ path = slash; ++ follow_default = 0; + continue; + } + if (ctokenlen == 2 && ctoken[0] == '.' && ctoken[1] == '.') +@@ -1485,8 +1514,9 @@ find_path (struct grub_btrfs_data *data, + *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; + key->object_id = key_out.offset; + +- path = slash; +- ++ if (!follow_default) ++ path = slash; ++ follow_default = 0; + continue; + } + +@@ -1555,7 +1585,9 @@ find_path (struct grub_btrfs_data *data, + return err; + } + +- path = slash; ++ if (!follow_default) ++ path = slash; ++ follow_default = 0; + if (cdirel->type == GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK) + { + struct grub_btrfs_inode inode; +@@ -1605,14 +1637,26 @@ find_path (struct grub_btrfs_data *data, + path = path_alloc = tmp; + if (path[0] == '/') + { +- if (data->fs_tree) ++ if (relpath && (relpath[0] == '1' || relpath[0] == 'y')) + { +- *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; +- *tree = data->fs_tree; +- /* This is a tree root, so everything starts at objectid 256 */ +- key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); +- key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; +- key->offset = 0; ++ if (data->fs_tree) ++ { ++ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; ++ *tree = data->fs_tree; ++ /* This is a tree root, so everything starts at objectid 256 */ ++ key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); ++ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; ++ key->offset = 0; ++ } ++ else ++ { ++ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; ++ *tree = data->sblock.root_tree; ++ key->object_id = data->sblock.root_dir_objectid; ++ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; ++ key->offset = 0; ++ follow_default = 1; ++ } + } + else + { +@@ -2268,6 +2312,7 @@ GRUB_MOD_INIT (btrfs) + subvolid_set_env); + grub_env_export ("btrfs_subvol"); + grub_env_export ("btrfs_subvolid"); ++ grub_env_export ("btrfs_relative_path"); + } + + GRUB_MOD_FINI (btrfs) diff --git a/grub2-btrfs-04-grub2-install.patch b/grub2-btrfs-04-grub2-install.patch new file mode 100644 index 0000000..6ca71a2 --- /dev/null +++ b/grub2-btrfs-04-grub2-install.patch @@ -0,0 +1,160 @@ +Index: grub-2.02~rc1/grub-core/osdep/unix/config.c +=================================================================== +--- grub-2.02~rc1.orig/grub-core/osdep/unix/config.c ++++ grub-2.02~rc1/grub-core/osdep/unix/config.c +@@ -219,6 +219,19 @@ grub_util_load_config (struct grub_util_ + if (v) + cfg->grub_distributor = xstrdup (v); + ++ v = getenv ("SUSE_BTRFS_SNAPSHOT_BOOTING"); ++ if (v) ++ { ++ if (grub_strncmp(v, "true", sizeof ("true") - 1) == 0) ++ { ++ cfg->is_suse_btrfs_snapshot_enabled = 1; ++ } ++ else ++ { ++ cfg->is_suse_btrfs_snapshot_enabled = 0; ++ } ++ } ++ + cfgfile = grub_util_get_config_filename (); + if (!grub_util_is_regular (cfgfile)) + return; +@@ -242,8 +255,8 @@ grub_util_load_config (struct grub_util_ + *ptr++ = *iptr; + } + +- strcpy (ptr, "'; printf \"GRUB_ENABLE_CRYPTODISK=%s\\nGRUB_DISTRIBUTOR=%s\\n\" " +- "\"$GRUB_ENABLE_CRYPTODISK\" \"$GRUB_DISTRIBUTOR\""); ++ strcpy (ptr, "'; printf \"GRUB_ENABLE_CRYPTODISK=%s\\nGRUB_DISTRIBUTOR=%s\\nSUSE_BTRFS_SNAPSHOT_BOOTING=%s\\n\" " ++ "\"$GRUB_ENABLE_CRYPTODISK\" \"$GRUB_DISTRIBUTOR\" \"$SUSE_BTRFS_SNAPSHOT_BOOTING\""); + + argv[2] = script; + argv[3] = '\0'; +Index: grub-2.02~rc1/include/grub/emu/config.h +=================================================================== +--- grub-2.02~rc1.orig/include/grub/emu/config.h ++++ grub-2.02~rc1/include/grub/emu/config.h +@@ -37,6 +37,7 @@ struct grub_util_config + { + int is_cryptodisk_enabled; + char *grub_distributor; ++ int is_suse_btrfs_snapshot_enabled; + }; + + void +Index: grub-2.02~rc1/util/config.c +=================================================================== +--- grub-2.02~rc1.orig/util/config.c ++++ grub-2.02~rc1/util/config.c +@@ -42,6 +42,16 @@ grub_util_parse_config (FILE *f, struct + cfg->is_cryptodisk_enabled = 1; + continue; + } ++ if (grub_strncmp (ptr, "SUSE_BTRFS_SNAPSHOT_BOOTING=", ++ sizeof ("SUSE_BTRFS_SNAPSHOT_BOOTING=") - 1) == 0) ++ { ++ ptr += sizeof ("SUSE_BTRFS_SNAPSHOT_BOOTING=") - 1; ++ if (*ptr == '"' || *ptr == '\'') ++ ptr++; ++ if (grub_strncmp(ptr, "true", sizeof ("true") - 1) == 0) ++ cfg->is_suse_btrfs_snapshot_enabled = 1; ++ continue; ++ } + if (grub_strncmp (ptr, "GRUB_DISTRIBUTOR=", + sizeof ("GRUB_DISTRIBUTOR=") - 1) == 0) + { +Index: grub-2.02~rc1/util/grub-install.c +=================================================================== +--- grub-2.02~rc1.orig/util/grub-install.c ++++ grub-2.02~rc1/util/grub-install.c +@@ -828,6 +828,8 @@ fill_core_services (const char *core_ser + free (sysv_plist); + } + ++extern int use_relative_path_on_btrfs; ++ + int + main (int argc, char *argv[]) + { +@@ -861,6 +863,9 @@ main (int argc, char *argv[]) + + grub_util_load_config (&config); + ++ if (config.is_suse_btrfs_snapshot_enabled) ++ use_relative_path_on_btrfs = 1; ++ + if (!bootloader_id && config.grub_distributor) + { + char *ptr; +@@ -1347,6 +1352,16 @@ main (int argc, char *argv[]) + fprintf (load_cfg_f, "set debug='%s'\n", + debug_image); + } ++ ++ if (config.is_suse_btrfs_snapshot_enabled ++ && grub_strncmp(grub_fs->name, "btrfs", sizeof ("btrfs") - 1) == 0) ++ { ++ if (!load_cfg_f) ++ load_cfg_f = grub_util_fopen (load_cfg, "wb"); ++ have_load_cfg = 1; ++ fprintf (load_cfg_f, "set btrfs_relative_path='y'\n"); ++ } ++ + char *prefix_drive = NULL; + char *install_drive = NULL; + +Index: grub-2.02~rc1/grub-core/osdep/linux/getroot.c +=================================================================== +--- grub-2.02~rc1.orig/grub-core/osdep/linux/getroot.c ++++ grub-2.02~rc1/grub-core/osdep/linux/getroot.c +@@ -376,6 +376,7 @@ get_btrfs_fs_prefix (const char *mount_p + return NULL; + } + ++int use_relative_path_on_btrfs = 0; + + char ** + grub_find_root_devices_from_mountinfo (const char *dir, char **relroot) +@@ -519,6 +520,12 @@ again: + { + ret = grub_find_root_devices_from_btrfs (dir); + fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path); ++ if (use_relative_path_on_btrfs) ++ { ++ if (fs_prefix) ++ free (fs_prefix); ++ fs_prefix = xstrdup ("/"); ++ } + } + else if (!retry && grub_strcmp (entries[i].fstype, "autofs") == 0) + { +Index: grub-2.02~rc1/util/grub-mkrelpath.c +=================================================================== +--- grub-2.02~rc1.orig/util/grub-mkrelpath.c ++++ grub-2.02~rc1/util/grub-mkrelpath.c +@@ -40,9 +40,12 @@ struct arguments + }; + + static struct argp_option options[] = { ++ {"relative", 'r', 0, 0, "use relative path on btrfs", 0}, + { 0, 0, 0, 0, 0, 0 } + }; + ++extern int use_relative_path_on_btrfs; ++ + static error_t + argp_parser (int key, char *arg, struct argp_state *state) + { +@@ -52,6 +55,9 @@ argp_parser (int key, char *arg, struct + + switch (key) + { ++ case 'r': ++ use_relative_path_on_btrfs = 1; ++ break; + case ARGP_KEY_ARG: + if (state->arg_num == 0) + arguments->pathname = xstrdup (arg); diff --git a/grub2-btrfs-05-grub2-mkconfig.patch b/grub2-btrfs-05-grub2-mkconfig.patch new file mode 100644 index 0000000..3e0582c --- /dev/null +++ b/grub2-btrfs-05-grub2-mkconfig.patch @@ -0,0 +1,137 @@ + +Always declare path specification in case of inconsistent declaration +elsewhere. (bsc#1209165) + +--- + util/grub-mkconfig.in | 3 ++- + util/grub-mkconfig_lib.in | 4 ++++ + util/grub.d/00_header.in | 23 ++++++++++++++++++++++- + util/grub.d/10_linux.in | 11 ++++++++++- + util/grub.d/20_linux_xen.in | 4 ++++ + 5 files changed, 42 insertions(+), 3 deletions(-) + +--- a/util/grub-mkconfig_lib.in ++++ b/util/grub-mkconfig_lib.in +@@ -49,7 +49,11 @@ + + make_system_path_relative_to_its_root () + { ++ if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ] ; then ++ "${grub_mkrelpath}" -r "$1" ++ else + "${grub_mkrelpath}" "$1" ++ fi + } + + is_path_readable_by_grub () +--- a/util/grub.d/00_header.in ++++ b/util/grub.d/00_header.in +@@ -27,6 +27,21 @@ + + . "$pkgdatadir/grub-mkconfig_lib" + ++if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ] && ++ [ "x${GRUB_FS}" = "xbtrfs" ] ; then ++ cat </dev/null || true` +@@ -239,7 +243,12 @@ + if [ $PLATFORM != "emu" ]; then + hotkey=0 + else +- rel_dirname=$dirname ++ if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ] && ++ [ "x${GRUB_FS}" = "xbtrfs" ] ; then ++ rel_dirname="\${btrfs_subvol}$dirname" ++ else ++ rel_dirname="$dirname" ++ fi + fi + version=`echo $basename | sed -e "s,^[^0-9]*-,,g"` + alt_version=`echo $version | sed -e "s,\.old$,,g"` +--- a/util/grub.d/20_linux_xen.in ++++ b/util/grub.d/20_linux_xen.in +@@ -79,10 +79,14 @@ + + case x"$GRUB_FS" in + xbtrfs) ++ if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ]; then ++ GRUB_CMDLINE_LINUX="${GRUB_CMDLINE_LINUX} \${extra_cmdline}" ++ else + rootsubvol="`make_system_path_relative_to_its_root /`" + rootsubvol="${rootsubvol#/}" + if [ "x${rootsubvol}" != x ]; then + GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}" ++ fi + fi;; + xzfs) + rpool=`${grub_probe} --device ${GRUB_DEVICE} --target=fs_label 2>/dev/null || true` diff --git a/grub2-btrfs-06-subvol-mount.patch b/grub2-btrfs-06-subvol-mount.patch new file mode 100644 index 0000000..c791fd4 --- /dev/null +++ b/grub2-btrfs-06-subvol-mount.patch @@ -0,0 +1,529 @@ + +V2: +* Fix grub2-install --root-directory does not work for /boot/grub2/ on + separate btrfs subvolume (boo#1098420) + +v3: +* Fix executable stack on which function trampoline is constructed to support + closure (nested function). The closure sematic is replaced. + +Index: grub-2.04/grub-core/fs/btrfs.c +=================================================================== +--- grub-2.04.orig/grub-core/fs/btrfs.c ++++ grub-2.04/grub-core/fs/btrfs.c +@@ -43,6 +43,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -263,6 +264,12 @@ static grub_err_t + grub_btrfs_read_logical (struct grub_btrfs_data *data, + grub_disk_addr_t addr, void *buf, grub_size_t size, + int recursion_depth); ++static grub_err_t ++get_root (struct grub_btrfs_data *data, struct grub_btrfs_key *key, ++ grub_uint64_t *tree, grub_uint8_t *type); ++ ++grub_uint64_t ++find_mtab_subvol_tree (const char *path, char **path_in_subvol); + + static grub_err_t + read_sblock (grub_disk_t disk, struct grub_btrfs_superblock *sb) +@@ -1203,9 +1210,26 @@ lookup_root_by_name(struct grub_btrfs_da + grub_err_t err; + grub_uint64_t tree = 0; + grub_uint8_t type; ++ grub_uint64_t saved_tree; + struct grub_btrfs_key key; + ++ if (path[0] == '\0') ++ { ++ data->fs_tree = 0; ++ return GRUB_ERR_NONE; ++ } ++ ++ err = get_root (data, &key, &tree, &type); ++ if (err) ++ return err; ++ ++ saved_tree = data->fs_tree; ++ data->fs_tree = tree; ++ + err = find_path (data, path, &key, &tree, &type); ++ ++ data->fs_tree = saved_tree; ++ + if (err) + return grub_error(GRUB_ERR_FILE_NOT_FOUND, "couldn't locate %s\n", path); + +@@ -2179,11 +2203,20 @@ grub_btrfs_dir (grub_device_t device, co + int r = 0; + grub_uint64_t tree; + grub_uint8_t type; ++ char *new_path = NULL; + + if (!data) + return grub_errno; + +- err = find_path (data, path, &key_in, &tree, &type); ++ tree = find_mtab_subvol_tree (path, &new_path); ++ ++ if (tree) ++ data->fs_tree = tree; ++ ++ err = find_path (data, new_path ? new_path : path, &key_in, &tree, &type); ++ if (new_path) ++ grub_free (new_path); ++ + if (err) + { + grub_btrfs_unmount (data); +@@ -2285,11 +2318,21 @@ grub_btrfs_open (struct grub_file *file, + struct grub_btrfs_inode inode; + grub_uint8_t type; + struct grub_btrfs_key key_in; ++ grub_uint64_t tree; ++ char *new_path = NULL; + + if (!data) + return grub_errno; + +- err = find_path (data, name, &key_in, &data->tree, &type); ++ tree = find_mtab_subvol_tree (name, &new_path); ++ ++ if (tree) ++ data->fs_tree = tree; ++ ++ err = find_path (data, new_path ? new_path : name, &key_in, &data->tree, &type); ++ if (new_path) ++ grub_free (new_path); ++ + if (err) + { + grub_btrfs_unmount (data); +@@ -2460,6 +2503,150 @@ grub_cmd_btrfs_info (grub_command_t cmd + return 0; + } + ++struct grub_btrfs_mtab ++{ ++ struct grub_btrfs_mtab *next; ++ struct grub_btrfs_mtab **prev; ++ char *path; ++ char *subvol; ++ grub_uint64_t tree; ++}; ++ ++typedef struct grub_btrfs_mtab* grub_btrfs_mtab_t; ++ ++static struct grub_btrfs_mtab *btrfs_mtab; ++ ++#define FOR_GRUB_MTAB(var) FOR_LIST_ELEMENTS (var, btrfs_mtab) ++#define FOR_GRUB_MTAB_SAFE(var, next) FOR_LIST_ELEMENTS_SAFE((var), (next), btrfs_mtab) ++ ++static void ++add_mountpoint (const char *path, const char *subvol, grub_uint64_t tree) ++{ ++ grub_btrfs_mtab_t m = grub_malloc (sizeof (*m)); ++ ++ m->path = grub_strdup (path); ++ m->subvol = grub_strdup (subvol); ++ m->tree = tree; ++ grub_list_push (GRUB_AS_LIST_P (&btrfs_mtab), GRUB_AS_LIST (m)); ++} ++ ++static grub_err_t ++grub_cmd_btrfs_mount_subvol (grub_command_t cmd __attribute__ ((unused)), int argc, ++ char **argv) ++{ ++ char *devname, *dirname, *subvol; ++ struct grub_btrfs_key key_in; ++ grub_uint8_t type; ++ grub_uint64_t tree; ++ grub_uint64_t saved_tree; ++ grub_err_t err; ++ struct grub_btrfs_data *data = NULL; ++ grub_device_t dev = NULL; ++ ++ if (argc < 3) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "required and "); ++ ++ devname = grub_file_get_device_name(argv[0]); ++ dev = grub_device_open (devname); ++ grub_free (devname); ++ ++ if (!dev) ++ { ++ err = grub_errno; ++ goto err_out; ++ } ++ ++ dirname = argv[1]; ++ subvol = argv[2]; ++ ++ data = grub_btrfs_mount (dev); ++ if (!data) ++ { ++ err = grub_errno; ++ goto err_out; ++ } ++ ++ err = find_path (data, dirname, &key_in, &tree, &type); ++ if (err) ++ goto err_out; ++ ++ if (type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY) ++ { ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory")); ++ goto err_out; ++ } ++ ++ err = get_root (data, &key_in, &tree, &type); ++ ++ if (err) ++ goto err_out; ++ ++ saved_tree = data->fs_tree; ++ data->fs_tree = tree; ++ err = find_path (data, subvol, &key_in, &tree, &type); ++ data->fs_tree = saved_tree; ++ ++ if (err) ++ goto err_out; ++ ++ if (key_in.object_id != grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0) ++ { ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n", subvol); ++ goto err_out; ++ } ++ ++ grub_btrfs_unmount (data); ++ grub_device_close (dev); ++ add_mountpoint (dirname, subvol, tree); ++ ++ return GRUB_ERR_NONE; ++ ++err_out: ++ ++ if (data) ++ grub_btrfs_unmount (data); ++ ++ if (dev) ++ grub_device_close (dev); ++ ++ return err; ++} ++ ++grub_uint64_t ++find_mtab_subvol_tree (const char *path, char **path_in_subvol) ++{ ++ grub_btrfs_mtab_t m, cm; ++ grub_uint64_t tree; ++ ++ if (!path || !path_in_subvol) ++ return 0; ++ ++ *path_in_subvol = NULL; ++ tree = 0; ++ cm = NULL; ++ ++ FOR_GRUB_MTAB (m) ++ { ++ if (grub_strncmp (path, m->path, grub_strlen (m->path)) == 0) ++ { ++ if (!cm) ++ cm = m; ++ else ++ if (grub_strcmp (m->path, cm->path) > 0) ++ cm = m; ++ } ++ } ++ ++ if (cm) ++ { ++ const char *s = path + grub_strlen (cm->path); ++ *path_in_subvol = (s[0] == '\0') ? grub_strdup ("/") : grub_strdup (s); ++ tree = cm->tree; ++ } ++ ++ return tree; ++} ++ + static grub_err_t + get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree, + grub_uint64_t objectid, grub_uint64_t offset, +@@ -2666,6 +2853,7 @@ static struct grub_fs grub_btrfs_fs = { + }; + + static grub_command_t cmd_info; ++static grub_command_t cmd_mount_subvol; + static grub_extcmd_t cmd_list_subvols; + + static char * +@@ -2729,6 +2917,9 @@ GRUB_MOD_INIT (btrfs) + cmd_info = grub_register_command("btrfs-info", grub_cmd_btrfs_info, + "DEVICE", + "Print BtrFS info about DEVICE."); ++ cmd_mount_subvol = grub_register_command("btrfs-mount-subvol", grub_cmd_btrfs_mount_subvol, ++ "DEVICE DIRECTORY SUBVOL", ++ "Set btrfs DEVICE the DIRECTORY a mountpoint of SUBVOL."); + cmd_list_subvols = grub_register_extcmd("btrfs-list-subvols", + grub_cmd_btrfs_list_subvols, 0, + "[-p|-n] [-o var] DEVICE", +Index: grub-2.04/grub-core/osdep/linux/getroot.c +=================================================================== +--- grub-2.04.orig/grub-core/osdep/linux/getroot.c ++++ grub-2.04/grub-core/osdep/linux/getroot.c +@@ -107,6 +107,14 @@ struct btrfs_ioctl_search_key + grub_uint32_t unused[9]; + }; + ++struct btrfs_ioctl_search_header { ++ grub_uint64_t transid; ++ grub_uint64_t objectid; ++ grub_uint64_t offset; ++ grub_uint32_t type; ++ grub_uint32_t len; ++}; ++ + struct btrfs_ioctl_search_args { + struct btrfs_ioctl_search_key key; + grub_uint64_t buf[(4096 - sizeof(struct btrfs_ioctl_search_key)) +@@ -378,6 +386,109 @@ get_btrfs_fs_prefix (const char *mount_p + + int use_relative_path_on_btrfs = 0; + ++static char * ++get_btrfs_subvol (const char *path) ++{ ++ struct btrfs_ioctl_ino_lookup_args args; ++ grub_uint64_t tree_id; ++ int fd = -1; ++ char *ret = NULL; ++ ++ fd = open (path, O_RDONLY); ++ ++ if (fd < 0) ++ return NULL; ++ ++ memset (&args, 0, sizeof(args)); ++ args.objectid = GRUB_BTRFS_TREE_ROOT_OBJECTID; ++ ++ if (ioctl (fd, BTRFS_IOC_INO_LOOKUP, &args) < 0) ++ goto error; ++ ++ tree_id = args.treeid; ++ ++ while (tree_id != GRUB_BTRFS_ROOT_VOL_OBJECTID) ++ { ++ struct btrfs_ioctl_search_args sargs; ++ struct grub_btrfs_root_backref *br; ++ struct btrfs_ioctl_search_header *search_header; ++ char *old; ++ grub_uint16_t len; ++ grub_uint64_t inode_id; ++ ++ memset (&sargs, 0, sizeof(sargs)); ++ ++ sargs.key.tree_id = 1; ++ sargs.key.min_objectid = tree_id; ++ sargs.key.max_objectid = tree_id; ++ ++ sargs.key.min_offset = 0; ++ sargs.key.max_offset = ~0ULL; ++ sargs.key.min_transid = 0; ++ sargs.key.max_transid = ~0ULL; ++ sargs.key.min_type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF; ++ sargs.key.max_type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF; ++ ++ sargs.key.nr_items = 1; ++ ++ if (ioctl (fd, BTRFS_IOC_TREE_SEARCH, &sargs) < 0) ++ goto error; ++ ++ if (sargs.key.nr_items == 0) ++ goto error; ++ ++ search_header = (struct btrfs_ioctl_search_header *)sargs.buf; ++ br = (struct grub_btrfs_root_backref *) (search_header + 1); ++ ++ len = grub_le_to_cpu16 (br->n); ++ inode_id = grub_le_to_cpu64 (br->inode_id); ++ tree_id = search_header->offset; ++ ++ old = ret; ++ ret = malloc (len + 1); ++ memcpy (ret, br->name, len); ++ ret[len] = '\0'; ++ ++ if (inode_id != GRUB_BTRFS_TREE_ROOT_OBJECTID) ++ { ++ char *s; ++ ++ memset(&args, 0, sizeof(args)); ++ args.treeid = search_header->offset; ++ args.objectid = inode_id; ++ ++ if (ioctl (fd, BTRFS_IOC_INO_LOOKUP, &args) < 0) ++ goto error; ++ ++ s = xasprintf ("%s%s", args.name, ret); ++ free (ret); ++ ret = s; ++ } ++ ++ if (old) ++ { ++ char *s = xasprintf ("%s/%s", ret, old); ++ free (ret); ++ free (old); ++ ret = s; ++ } ++ } ++ ++ close (fd); ++ return ret; ++ ++error: ++ ++ if (fd >= 0) ++ close (fd); ++ if (ret) ++ free (ret); ++ ++ return NULL; ++} ++ ++static char *grub_btrfs_mount_path; ++ + char ** + grub_find_root_devices_from_mountinfo (const char *dir, char **relroot) + { +@@ -519,12 +630,17 @@ again: + else if (grub_strcmp (entries[i].fstype, "btrfs") == 0) + { + ret = grub_find_root_devices_from_btrfs (dir); +- fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path); + if (use_relative_path_on_btrfs) + { +- if (fs_prefix) +- free (fs_prefix); + fs_prefix = xstrdup ("/"); ++ ++ if (grub_btrfs_mount_path) ++ grub_free (grub_btrfs_mount_path); ++ grub_btrfs_mount_path = grub_strdup (entries[i].enc_path); ++ } ++ else ++ { ++ fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path); + } + } + else if (!retry && grub_strcmp (entries[i].fstype, "autofs") == 0) +@@ -1192,6 +1308,24 @@ grub_util_get_grub_dev_os (const char *o + return grub_dev; + } + ++ ++char * ++grub_util_get_btrfs_subvol (const char *path, char **mount_path) ++{ ++ if (mount_path) ++ *mount_path = NULL; ++ ++ grub_free (grub_find_root_devices_from_mountinfo (path, NULL)); ++ ++ if (!grub_btrfs_mount_path) ++ return NULL; ++ ++ if (mount_path) ++ *mount_path = grub_strdup (grub_btrfs_mount_path); ++ ++ return get_btrfs_subvol (grub_btrfs_mount_path); ++} ++ + char * + grub_make_system_path_relative_to_its_root_os (const char *path) + { +Index: grub-2.04/util/grub-install.c +=================================================================== +--- grub-2.04.orig/util/grub-install.c ++++ grub-2.04/util/grub-install.c +@@ -1591,6 +1591,58 @@ main (int argc, char *argv[]) + prefix_drive = xasprintf ("(%s)", grub_drives[0]); + } + ++#ifdef __linux__ ++ ++ if (config.is_suse_btrfs_snapshot_enabled ++ && grub_strncmp(grub_fs->name, "btrfs", sizeof ("btrfs") - 1) == 0) ++ { ++ char *subvol = NULL; ++ char *mount_path = NULL; ++ char **rootdir_devices = NULL; ++ char *t = grub_util_path_concat (2, "/", rootdir); ++ char *rootdir_path = grub_canonicalize_file_name (t); ++ ++ if (rootdir_path && grub_util_is_directory (rootdir_path)) ++ rootdir_devices = grub_guess_root_devices (rootdir_path); ++ ++ if (rootdir_devices && rootdir_devices[0]) ++ if (grub_strcmp (rootdir_devices[0], grub_devices[0]) == 0) ++ subvol = grub_util_get_btrfs_subvol (platdir, &mount_path); ++ ++ if (subvol && mount_path) ++ { ++ char *def_subvol; ++ ++ def_subvol = grub_util_get_btrfs_subvol (rootdir_path, NULL); ++ ++ if (def_subvol) ++ { ++ char *rootdir_mount_path = NULL; ++ if (!load_cfg_f) ++ load_cfg_f = grub_util_fopen (load_cfg, "wb"); ++ have_load_cfg = 1; ++ ++ if (grub_strncmp (rootdir_path, mount_path, grub_strlen (rootdir_path)) == 0) ++ rootdir_mount_path = grub_util_path_concat (2, "/", mount_path + grub_strlen (rootdir_path)); ++ ++ if (grub_strcmp (subvol, def_subvol) != 0 && rootdir_mount_path) ++ fprintf (load_cfg_f, "btrfs-mount-subvol ($root) %s %s\n", rootdir_mount_path, subvol); ++ free (rootdir_mount_path); ++ free (def_subvol); ++ } ++ } ++ ++ free (t); ++ free (rootdir_path); ++ for (curdev = rootdir_devices; *curdev; curdev++) ++ free (*curdev); ++ free (rootdir_devices); ++ free (subvol); ++ free (mount_path); ++ } ++ ++#endif ++ + char mkimage_target[200]; + const char *core_name = NULL; + +Index: grub-2.04/include/grub/emu/getroot.h +=================================================================== +--- grub-2.04.orig/include/grub/emu/getroot.h ++++ grub-2.04/include/grub/emu/getroot.h +@@ -53,6 +53,11 @@ char ** + grub_find_root_devices_from_mountinfo (const char *dir, char **relroot); + #endif + ++#ifdef __linux__ ++char * ++grub_util_get_btrfs_subvol (const char *path, char **mount_path); ++#endif ++ + /* Devmapper functions provided by getroot_devmapper.c. */ + void + grub_util_pull_devmapper (const char *os_dev); diff --git a/grub2-btrfs-07-subvol-fallback.patch b/grub2-btrfs-07-subvol-fallback.patch new file mode 100644 index 0000000..4255b50 --- /dev/null +++ b/grub2-btrfs-07-subvol-fallback.patch @@ -0,0 +1,46 @@ +Index: grub-2.02~beta3/grub-core/fs/btrfs.c +=================================================================== +--- grub-2.02~beta3.orig/grub-core/fs/btrfs.c ++++ grub-2.02~beta3/grub-core/fs/btrfs.c +@@ -925,10 +925,40 @@ lookup_root_by_name(struct grub_btrfs_da + } + + static grub_err_t ++lookup_root_by_name_fallback(struct grub_btrfs_data *data, const char *path) ++{ ++ grub_err_t err; ++ grub_uint64_t tree = 0; ++ grub_uint8_t type; ++ struct grub_btrfs_key key; ++ ++ err = find_path (data, path, &key, &tree, &type); ++ if (err) ++ return grub_error(GRUB_ERR_FILE_NOT_FOUND, "couldn't locate %s\n", path); ++ ++ if (key.object_id != grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0) ++ return grub_error(GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n", path); ++ ++ data->fs_tree = tree; ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t + btrfs_handle_subvol(struct grub_btrfs_data *data __attribute__ ((unused))) + { + if (btrfs_default_subvol) +- return lookup_root_by_name(data, btrfs_default_subvol); ++ { ++ grub_err_t err; ++ err = lookup_root_by_name(data, btrfs_default_subvol); ++ ++ /* Fallback to old schemes */ ++ if (err == GRUB_ERR_FILE_NOT_FOUND) ++ { ++ err = GRUB_ERR_NONE; ++ return lookup_root_by_name_fallback(data, btrfs_default_subvol); ++ } ++ return err; ++ } + + if (btrfs_default_subvolid) + return lookup_root_by_id(data, btrfs_default_subvolid); diff --git a/grub2-btrfs-08-workaround-snapshot-menu-default-entry.patch b/grub2-btrfs-08-workaround-snapshot-menu-default-entry.patch new file mode 100644 index 0000000..4ffedd8 --- /dev/null +++ b/grub2-btrfs-08-workaround-snapshot-menu-default-entry.patch @@ -0,0 +1,60 @@ + +v2: Add menuentry "Help on bootable snapshot" to be excluded as default entry. + +Index: grub-2.06/grub-core/normal/menu.c +=================================================================== +--- grub-2.06.orig/grub-core/normal/menu.c ++++ grub-2.06/grub-core/normal/menu.c +@@ -574,6 +574,43 @@ print_countdown (struct grub_term_coordi + grub_refresh (); + } + ++/* bsc#956046 - The first entry titled 'Bootable snapshot #$NUM' is inserted on ++ top at runtime to display current snapshot information. If default entry is ++ using number as key to index the entry, the result will be shifted so here we ++ add specical handling to shift it back. We apply this workaround until a better ++ solution can be found. */ ++static void ++workaround_snapshot_menu_default_entry (grub_menu_t menu, const char *name, int *default_entry) ++{ ++ grub_menu_entry_t entry; ++ if ((entry = grub_menu_get_entry (menu, 0)) && ++ ((entry->submenu && grub_strncmp (entry->title, "Bootable snapshot", sizeof("Bootable snapshot") - 1) == 0) || ++ (!entry->submenu && grub_strncmp (entry->title, "Help on bootable snapshot", sizeof("Help on bootable snapshot") - 1) == 0))) ++ { ++ const char *val; ++ ++ if (*default_entry == -1 && menu->size > 1) ++ { ++ *default_entry = 1; ++ return; ++ } ++ ++ val = grub_env_get (name); ++ ++ grub_error_push (); ++ ++ if (val) ++ grub_strtoul (val, 0, 0); ++ ++ if (*default_entry < (menu->size - 1) && grub_errno == GRUB_ERR_NONE) ++ ++(*default_entry); ++ ++ grub_error_pop (); ++ } ++ ++ return; ++} ++ + #define GRUB_MENU_PAGE_SIZE 10 + + /* Show the menu and handle menu entry selection. Returns the menu entry +@@ -592,6 +629,8 @@ run_menu (grub_menu_t menu, int nested, + + default_entry = get_entry_number (menu, "default"); + ++ workaround_snapshot_menu_default_entry (menu, "default", &default_entry); ++ + /* If DEFAULT_ENTRY is not within the menu entries, fall back to + the first entry. */ + if (default_entry < 0 || default_entry >= menu->size) diff --git a/grub2-btrfs-09-get-default-subvolume.patch b/grub2-btrfs-09-get-default-subvolume.patch new file mode 100644 index 0000000..776bf4b --- /dev/null +++ b/grub2-btrfs-09-get-default-subvolume.patch @@ -0,0 +1,284 @@ + +V1: + * Use overflow checking primitives where the arithmetic expression for + buffer allocations may include unvalidated data + +Index: grub-2.04/grub-core/fs/btrfs.c +=================================================================== +--- grub-2.04.orig/grub-core/fs/btrfs.c ++++ grub-2.04/grub-core/fs/btrfs.c +@@ -2880,6 +2880,254 @@ out: + return 0; + } + ++static grub_err_t ++grub_btrfs_get_parent_subvol_path (struct grub_btrfs_data *data, ++ grub_uint64_t child_id, ++ const char *child_path, ++ grub_uint64_t *parent_id, ++ char **path_out) ++{ ++ grub_uint64_t fs_root = 0; ++ struct grub_btrfs_key key_in = { ++ .object_id = child_id, ++ .type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF, ++ .offset = 0, ++ }, key_out; ++ struct grub_btrfs_root_ref *ref; ++ char *buf; ++ struct grub_btrfs_leaf_descriptor desc; ++ grub_size_t elemsize; ++ grub_disk_addr_t elemaddr; ++ grub_err_t err; ++ char *parent_path; ++ grub_size_t sz; ++ ++ *parent_id = 0; ++ *path_out = 0; ++ ++ err = lower_bound(data, &key_in, &key_out, data->sblock.root_tree, ++ &elemaddr, &elemsize, &desc, 0); ++ if (err) ++ return err; ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF || elemaddr == 0) ++ next(data, &desc, &elemaddr, &elemsize, &key_out); ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF) ++ { ++ free_iterator(&desc); ++ return grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("can't find root backrefs")); ++ } ++ ++ if (grub_add (elemsize, 1, &sz)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); ++ ++ buf = grub_malloc(sz); ++ if (!buf) ++ { ++ free_iterator(&desc); ++ return grub_errno; ++ } ++ ++ err = grub_btrfs_read_logical(data, elemaddr, buf, elemsize, 0); ++ if (err) ++ { ++ grub_free(buf); ++ free_iterator(&desc); ++ return err; ++ } ++ ++ buf[elemsize] = 0; ++ ref = (struct grub_btrfs_root_ref *)buf; ++ ++ err = get_fs_root(data, data->sblock.root_tree, grub_le_to_cpu64 (key_out.offset), ++ 0, &fs_root); ++ if (err) ++ { ++ grub_free(buf); ++ free_iterator(&desc); ++ return err; ++ } ++ ++ find_pathname(data, grub_le_to_cpu64 (ref->dirid), fs_root, ref->name, &parent_path); ++ ++ if (child_path) ++ { ++ *path_out = grub_xasprintf ("%s/%s", parent_path, child_path); ++ grub_free (parent_path); ++ } ++ else ++ *path_out = parent_path; ++ ++ *parent_id = grub_le_to_cpu64 (key_out.offset); ++ ++ grub_free(buf); ++ free_iterator(&desc); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_btrfs_get_default_subvolume_id (struct grub_btrfs_data *data, grub_uint64_t *id) ++{ ++ grub_err_t err; ++ grub_disk_addr_t elemaddr; ++ grub_size_t elemsize; ++ struct grub_btrfs_key key, key_out; ++ struct grub_btrfs_dir_item *direl = NULL; ++ const char *ctoken = "default"; ++ grub_size_t ctokenlen = sizeof ("default") - 1; ++ grub_size_t sz; ++ ++ *id = 0; ++ key.object_id = data->sblock.root_dir_objectid; ++ key.type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; ++ key.offset = grub_cpu_to_le64 (~grub_getcrc32c (1, ctoken, ctokenlen)); ++ err = lower_bound (data, &key, &key_out, data->sblock.root_tree, &elemaddr, &elemsize, ++ NULL, 0); ++ if (err) ++ return err; ++ ++ if (key_cmp (&key, &key_out) != 0) ++ return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found")); ++ ++ struct grub_btrfs_dir_item *cdirel; ++ ++ if (grub_add (elemsize, 1, &sz)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); ++ ++ direl = grub_malloc (sz); ++ if (!direl) ++ return grub_errno; ++ ++ err = grub_btrfs_read_logical (data, elemaddr, direl, elemsize, 0); ++ if (err) ++ { ++ grub_free (direl); ++ return err; ++ } ++ for (cdirel = direl; ++ (grub_uint8_t *) cdirel - (grub_uint8_t *) direl ++ < (grub_ssize_t) elemsize; ++ cdirel = (void *) ((grub_uint8_t *) (direl + 1) ++ + grub_le_to_cpu16 (cdirel->n) ++ + grub_le_to_cpu16 (cdirel->m))) ++ { ++ if (ctokenlen == grub_le_to_cpu16 (cdirel->n) ++ && grub_memcmp (cdirel->name, ctoken, ctokenlen) == 0) ++ break; ++ } ++ if ((grub_uint8_t *) cdirel - (grub_uint8_t *) direl ++ >= (grub_ssize_t) elemsize) ++ { ++ grub_free (direl); ++ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found")); ++ return err; ++ } ++ ++ if (cdirel->key.type != GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM) ++ { ++ grub_free (direl); ++ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found")); ++ return err; ++ } ++ ++ *id = grub_le_to_cpu64 (cdirel->key.object_id); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_btrfs_get_default_subvol (struct grub_extcmd_context *ctxt, ++ int argc, char **argv) ++{ ++ char *devname; ++ grub_device_t dev; ++ struct grub_btrfs_data *data; ++ grub_err_t err; ++ grub_uint64_t id; ++ char *subvol = NULL; ++ grub_uint64_t subvolid = 0; ++ char *varname = NULL; ++ char *output = NULL; ++ int path_only = ctxt->state[1].set; ++ int num_only = ctxt->state[2].set; ++ ++ if (ctxt->state[0].set) ++ varname = ctxt->state[0].arg; ++ ++ if (argc < 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); ++ ++ devname = grub_file_get_device_name(argv[0]); ++ if (!devname) ++ return grub_errno; ++ ++ dev = grub_device_open (devname); ++ grub_free (devname); ++ if (!dev) ++ return grub_errno; ++ ++ data = grub_btrfs_mount(dev); ++ if (!data) ++ { ++ grub_device_close (dev); ++ grub_dprintf ("btrfs", "failed to open fs\n"); ++ grub_errno = GRUB_ERR_NONE; ++ return 0; ++ } ++ ++ err = grub_btrfs_get_default_subvolume_id (data, &subvolid); ++ if (err) ++ { ++ grub_btrfs_unmount (data); ++ grub_device_close (dev); ++ return err; ++ } ++ ++ id = subvolid; ++ ++ if (id == GRUB_BTRFS_ROOT_VOL_OBJECTID) ++ subvol = grub_strdup (""); ++ else ++ while (id != GRUB_BTRFS_ROOT_VOL_OBJECTID) ++ { ++ grub_uint64_t parent_id; ++ char *path_out; ++ ++ err = grub_btrfs_get_parent_subvol_path (data, grub_cpu_to_le64 (id), subvol, &parent_id, &path_out); ++ if (err) ++ { ++ grub_btrfs_unmount (data); ++ grub_device_close (dev); ++ return err; ++ } ++ ++ if (subvol) ++ grub_free (subvol); ++ subvol = path_out; ++ id = parent_id; ++ } ++ ++ if (num_only && path_only) ++ output = grub_xasprintf ("%"PRIuGRUB_UINT64_T" /%s", subvolid, subvol); ++ else if (num_only) ++ output = grub_xasprintf ("%"PRIuGRUB_UINT64_T, subvolid); ++ else ++ output = grub_xasprintf ("/%s", subvol); ++ ++ if (varname) ++ grub_env_set(varname, output); ++ else ++ grub_printf ("%s\n", output); ++ ++ grub_free (output); ++ grub_free (subvol); ++ ++ grub_btrfs_unmount (data); ++ grub_device_close (dev); ++ ++ return GRUB_ERR_NONE; ++} ++ + static struct grub_fs grub_btrfs_fs = { + .name = "btrfs", + .fs_dir = grub_btrfs_dir, +@@ -2898,6 +3146,7 @@ static struct grub_fs grub_btrfs_fs = { + static grub_command_t cmd_info; + static grub_command_t cmd_mount_subvol; + static grub_extcmd_t cmd_list_subvols; ++static grub_extcmd_t cmd_get_default_subvol; + + static char * + subvolid_set_env (struct grub_env_var *var __attribute__ ((unused)), +@@ -2968,6 +3217,11 @@ GRUB_MOD_INIT (btrfs) + "[-p|-n] [-o var] DEVICE", + "Print list of BtrFS subvolumes on " + "DEVICE.", options); ++ cmd_get_default_subvol = grub_register_extcmd("btrfs-get-default-subvol", ++ grub_cmd_btrfs_get_default_subvol, 0, ++ "[-p|-n] [-o var] DEVICE", ++ "Print default BtrFS subvolume on " ++ "DEVICE.", options); + grub_register_variable_hook ("btrfs_subvol", subvol_get_env, + subvol_set_env); + grub_register_variable_hook ("btrfs_subvolid", subvolid_get_env, diff --git a/grub2-btrfs-10-config-directory.patch b/grub2-btrfs-10-config-directory.patch new file mode 100644 index 0000000..0246a3f --- /dev/null +++ b/grub2-btrfs-10-config-directory.patch @@ -0,0 +1,255 @@ +v1: +References: bsc#1063443 + +v2: +References: bsc#1106381 +Fix outputting invalid btrfs subvol path on non btrfs filesystem due to bogus +return code handling. + +Index: grub-2.02/grub-core/fs/btrfs.c +=================================================================== +--- grub-2.02.orig/grub-core/fs/btrfs.c ++++ grub-2.02/grub-core/fs/btrfs.c +@@ -2590,8 +2590,7 @@ grub_btrfs_get_default_subvolume_id (str + } + + static grub_err_t +-grub_cmd_btrfs_get_default_subvol (struct grub_extcmd_context *ctxt, +- int argc, char **argv) ++grub_btrfs_get_default_subvol (const char *name, grub_uint64_t *ret_subvolid, char **ret_subvol) + { + char *devname; + grub_device_t dev; +@@ -2600,21 +2599,8 @@ grub_cmd_btrfs_get_default_subvol (struc + grub_uint64_t id; + char *subvol = NULL; + grub_uint64_t subvolid = 0; +- char *varname = NULL; +- char *output = NULL; +- int path_only = ctxt->state[1].set; +- int num_only = ctxt->state[2].set; +- +- if (ctxt->state[0].set) +- varname = ctxt->state[0].arg; +- +- if (argc < 1) +- return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); +- +- devname = grub_file_get_device_name(argv[0]); +- if (!devname) +- return grub_errno; + ++ devname = grub_file_get_device_name(name); + dev = grub_device_open (devname); + grub_free (devname); + if (!dev) +@@ -2625,8 +2611,7 @@ grub_cmd_btrfs_get_default_subvol (struc + { + grub_device_close (dev); + grub_dprintf ("btrfs", "failed to open fs\n"); +- grub_errno = GRUB_ERR_NONE; +- return 0; ++ return grub_errno; + } + + err = grub_btrfs_get_default_subvolume_id (data, &subvolid); +@@ -2655,12 +2640,47 @@ grub_cmd_btrfs_get_default_subvol (struc + return err; + } + +- if (subvol) +- grub_free (subvol); ++ grub_free (subvol); + subvol = path_out; + id = parent_id; + } + ++ if (ret_subvolid) ++ *ret_subvolid = subvolid; ++ if (ret_subvol) ++ *ret_subvol = subvol; ++ ++ grub_btrfs_unmount (data); ++ grub_device_close (dev); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_btrfs_get_default_subvol (struct grub_extcmd_context *ctxt, ++ int argc, char **argv) ++{ ++ grub_err_t err; ++ char *subvol = NULL; ++ grub_uint64_t subvolid = 0; ++ char *varname = NULL; ++ char *output = NULL; ++ int path_only = ctxt->state[1].set; ++ int num_only = ctxt->state[2].set; ++ ++ if (ctxt->state[0].set) ++ varname = ctxt->state[0].arg; ++ ++ if (argc < 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); ++ ++ if ((err = grub_btrfs_get_default_subvol (argv[0], &subvolid, &subvol)) != GRUB_ERR_NONE) ++ { ++ if (err == GRUB_ERR_BAD_FS) ++ err = grub_errno = GRUB_ERR_NONE; ++ return err; ++ } ++ + if (num_only && path_only) + output = grub_xasprintf ("%"PRIuGRUB_UINT64_T" /%s", subvolid, subvol); + else if (num_only) +@@ -2676,9 +2696,6 @@ grub_cmd_btrfs_get_default_subvol (struc + grub_free (output); + grub_free (subvol); + +- grub_btrfs_unmount (data); +- grub_device_close (dev); +- + return GRUB_ERR_NONE; + } + +@@ -2757,6 +2774,122 @@ subvol_get_env (struct grub_env_var *var + return ""; + } + ++ ++static char * ++grub_btrfs_path_to_abs (const char *path) ++{ ++ grub_err_t err; ++ char *device_name = NULL; ++ char *subvol = NULL; ++ const char *file_name; ++ char *ret; ++ ++ if (!path) ++ return NULL; ++ ++ if ((err = grub_btrfs_get_default_subvol (path, 0, &subvol)) != GRUB_ERR_NONE) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ return NULL; ++ } ++ ++ if (!subvol || *subvol == '\0') ++ return NULL; ++ ++ file_name = (path[0] == '(') ? grub_strchr (path, ')') : NULL; ++ if (file_name) ++ file_name++; ++ else ++ file_name = path; ++ device_name = grub_file_get_device_name (path); ++ if (device_name) ++ ret = grub_xasprintf ("(%s)/%s%s", device_name, subvol, file_name); ++ else ++ ret = grub_xasprintf ("/%s%s", subvol, file_name); ++ ++ grub_free (device_name); ++ grub_free (subvol); ++ ++ return ret; ++} ++ ++static char * ++grub_btrfs_path_to_rel (const char *path) ++{ ++ grub_err_t err; ++ char *subvol = NULL; ++ const char *file_name; ++ ++ if (!path) ++ return NULL; ++ ++ if ((err = grub_btrfs_get_default_subvol (path, 0, &subvol)) != GRUB_ERR_NONE) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ return NULL; ++ } ++ ++ if (!subvol || *subvol == '\0') ++ return NULL; ++ ++ file_name = (path[0] == '(') ? grub_strchr (path, ')') : NULL; ++ if (file_name) ++ file_name++; ++ else ++ file_name = path; ++ ++ if (*file_name == '/') ++ file_name++; ++ ++ if (grub_strncmp (file_name, subvol, grub_strlen (subvol)) == 0) ++ { ++ char *device_name; ++ char *ret; ++ ++ device_name = grub_file_get_device_name (path); ++ file_name += grub_strlen (subvol); ++ if (device_name) ++ ret = grub_xasprintf ("(%s)%s", device_name, file_name); ++ else ++ ret = grub_strdup (file_name); ++ grub_free (device_name); ++ grub_free (subvol); ++ return ret; ++ } ++ ++ grub_free (subvol); ++ return NULL; ++} ++ ++static char * ++relpath_set_env (struct grub_env_var *var, ++ const char *val) ++{ ++ int new_val, old_val; ++ new_val = (val[0] == '1' || val[0] == 'y') ? 1 : 0; ++ old_val = (var->value[0] == '1' || var->value[0] == 'y') ? 1 : 0; ++ ++ if (new_val != old_val) ++ { ++ const char **n; ++ char * (*path_to_xxx) (const char *); ++ const char *envname[] = {"config_file", "config_directory", NULL}; ++ ++ path_to_xxx = (new_val == 1) ? grub_btrfs_path_to_rel : grub_btrfs_path_to_abs; ++ for (n = envname; *n; n++) ++ { ++ char *ctmp = path_to_xxx (grub_env_get (*n)); ++ if (ctmp) ++ { ++ grub_env_set (*n, ctmp); ++ grub_free (ctmp); ++ } ++ } ++ } ++ ++ return grub_strdup (val); ++} ++ + GRUB_MOD_INIT (btrfs) + { + grub_fs_register (&grub_btrfs_fs); +@@ -2780,6 +2913,8 @@ GRUB_MOD_INIT (btrfs) + subvol_set_env); + grub_register_variable_hook ("btrfs_subvolid", subvolid_get_env, + subvolid_set_env); ++ grub_register_variable_hook ("btrfs_relative_path", NULL, ++ relpath_set_env); + grub_env_export ("btrfs_subvol"); + grub_env_export ("btrfs_subvolid"); + grub_env_export ("btrfs_relative_path"); +@@ -2789,6 +2924,7 @@ GRUB_MOD_FINI (btrfs) + { + grub_register_variable_hook ("btrfs_subvol", NULL, NULL); + grub_register_variable_hook ("btrfs_subvolid", NULL, NULL); ++ grub_register_variable_hook ("btrfs_relative_path", NULL, NULL); + grub_unregister_command (cmd_info); + grub_unregister_extcmd (cmd_list_subvols); + grub_fs_unregister (&grub_btrfs_fs); diff --git a/grub2-btrfs-help-on-snapper-rollback.patch b/grub2-btrfs-help-on-snapper-rollback.patch new file mode 100644 index 0000000..3a8858e --- /dev/null +++ b/grub2-btrfs-help-on-snapper-rollback.patch @@ -0,0 +1,21 @@ +Index: grub-2.02/util/grub.d/00_header.in +=================================================================== +--- grub-2.02.orig/util/grub.d/00_header.in ++++ grub-2.02/util/grub.d/00_header.in +@@ -417,8 +417,14 @@ if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = + # Note: No $snapshot_num on *read-only* rollback! (bsc#901487) + cat </!d' -e '/>.*$/s///'` + + if [ -n "$FALLBACK_MATCH" ]; then + for i in $MENU_ENTRIES; do + if expr match "$i" "^$FALLBACK_MATCH" >/dev/null ; then + echo "$i" + return 0 + fi + done + fi + return 0 +} + +run_command () { + [ x"$DEBUG_RUN" = x1 ] && echo $@ || $@ +} + +debug_print () { + [ x"$DEBUG_RUN" = x1 ] && echo $@ || true +} + +case $1 in +-d|--debug) + DEBUG_RUN=1 + ;; +esac + +GRUB_EDITENV="/usr/bin/grub2-editenv" +GRUB_SET_DEFAULT="/usr/sbin/grub2-set-default" + +SAVED_ENTRY=`${GRUB_EDITENV} list | sed -ne "/^saved_entry=/s///p"` + +debug_print "SAVED_ENTRY=$SAVED_ENTRY" + +if [ -z "$SAVED_ENTRY" ] || expr match "$SAVED_ENTRY" "^[0-9]\+$" >/dev/null; then + exit 0 +fi + +MENU_ENTRIES=`awk ' + BEGIN { + bracket = 0 + } + { + patsplit($0, words, "([^[:blank:]]+)|(\"[^\"]+\")|('\''[^'\'']*'\'')", sep) + + cmd = words[1] + arg1 = words[2] + + if (substr(arg1, 1, 1) == "\"" || substr(arg1, 1, 1) == "'\''") { + len = length(arg1) + arg1 = substr(arg1, 2, len - 2) + } + + if (cmd == "submenu") { + submenu[bracket] = arg1 + } else if (cmd == "menuentry") { + title = "" + for (i = 0; i < bracket; i++) { + if (i in submenu) + title = title submenu[i] ">" + } + print title arg1 + } + + for (w in words) { + if (words[w] == "{") { + bracket++ + } else if (words[w] == "}") { + bracket-- + } + } + } +' /boot/grub2/grub.cfg` + +IFS=$'\n' + +debug_print "MENU_ENTRIES=" +for i in $MENU_ENTRIES; do + debug_print "$i" +done + +for i in $MENU_ENTRIES; do + if [ "$SAVED_ENTRY" = "$i" ]; then + exit 0 + fi +done + +FALLBACK=`fallback_entry $SAVED_ENTRY` + +if [ -n "$FALLBACK" ]; then + run_command ${GRUB_SET_DEFAULT} "$FALLBACK" + exit 0 +fi + +for i in /etc/os-release /usr/lib/os-release ; do + if [ -f "$i" ]; then + OS_RELEASE="$i" + break + fi +done + +if [ -z "$OS_RELEASE" ]; then + debug_print "No os-release file present" + exit 0 +fi + +debug_print "Applying settings from $OS_RELEASE" +source "$OS_RELEASE" + +if [ -z "$VERSION" ]; then + debug_print "No os-release version tag present, assuming rolling release" + exit 0 +fi + +NEW_SAVED_ENTRY=`echo $SAVED_ENTRY | sed -ne "s/$NAME [0-9a-zA-Z_.-]\{1,\}/$NAME $VERSION/pg"` + +debug_print "NEW_SAVED_ENTRY=$NEW_SAVED_ENTRY" + +if [ -z "$NEW_SAVED_ENTRY" -o "$NEW_SAVED_ENTRY" = "$SAVED_ENTRY" ]; then + exit 0 +fi + +IFS=$'\n' +for i in $MENU_ENTRIES; do + if [ "$NEW_SAVED_ENTRY" = "$i" ]; then + run_command ${GRUB_SET_DEFAULT} "$NEW_SAVED_ENTRY" + exit 0 + fi +done + +FALLBACK=`fallback_entry $NEW_SAVED_ENTRY` + +if [ -n "$FALLBACK" ]; then + run_command ${GRUB_SET_DEFAULT} "$FALLBACK" + exit 0 +fi + +exit 0 diff --git a/grub2-commands-introduce-read_file-subcommand.patch b/grub2-commands-introduce-read_file-subcommand.patch new file mode 100644 index 0000000..80a8656 --- /dev/null +++ b/grub2-commands-introduce-read_file-subcommand.patch @@ -0,0 +1,88 @@ +From: Raymund Will +Subject: Introduce a 'read_file' sub-command. +References: bsc#892852, bsc#891946 +Patch-Mainline: not yet + +Needed to allow s390x-emu to be telecontrolled via LOADPARM. + +v2: Added GRUB_FILE_TYPE_READ_ENVVAR as file type by read_file sub-command +tracked by verifier framework. + +--- + grub-core/commands/read.c | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +Index: grub-2.04~rc1/grub-core/commands/read.c +=================================================================== +--- grub-2.04~rc1.orig/grub-core/commands/read.c ++++ grub-2.04~rc1/grub-core/commands/read.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -77,16 +78,49 @@ grub_cmd_read (grub_command_t cmd __attr + return 0; + } + ++static grub_err_t ++grub_cmd_read_from_file (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) ++{ ++ char *line; ++ int i = 0; ++ grub_file_t file; ++ ++ if (argc < 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("file name expected")); ++ if (argc < 2) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("variable name expected")); ++ file = grub_file_open (args[i++], GRUB_FILE_TYPE_READ_ENVVAR); ++ if (! file) ++ return grub_errno; ++ while ( i < argc ) ++ { ++ line = grub_file_getline (file); ++ if ( !line ) ++ break; ++ grub_env_set (args[i++], line); ++ grub_free (line); ++ } ++ grub_file_close (file); ++ if (i != argc) ++ return GRUB_ERR_OUT_OF_RANGE; ++ return 0; ++} ++ + static grub_command_t cmd; ++static grub_command_t cme; + + GRUB_MOD_INIT(read) + { + cmd = grub_register_command ("read", grub_cmd_read, + N_("[ENVVAR]"), + N_("Set variable with user input.")); ++ cme = grub_register_command ("read_file", grub_cmd_read_from_file, ++ N_("FILE ENVVAR [...]"), ++ N_("Set variable(s) with line(s) from FILE.")); + } + + GRUB_MOD_FINI(read) + { + grub_unregister_command (cmd); ++ grub_unregister_command (cme); + } +Index: grub-2.04~rc1/include/grub/file.h +=================================================================== +--- grub-2.04~rc1.orig/include/grub/file.h ++++ grub-2.04~rc1/include/grub/file.h +@@ -122,6 +122,7 @@ enum grub_file_type + GRUB_FILE_TYPE_FS_SEARCH, + GRUB_FILE_TYPE_AUDIO, + GRUB_FILE_TYPE_VBE_DUMP, ++ GRUB_FILE_TYPE_READ_ENVVAR, + + GRUB_FILE_TYPE_LOADENV, + GRUB_FILE_TYPE_SAVEENV, diff --git a/grub2-default-distributor.patch b/grub2-default-distributor.patch new file mode 100644 index 0000000..a882a34 --- /dev/null +++ b/grub2-default-distributor.patch @@ -0,0 +1,201 @@ +v1: +As long as VERSION in /etc/os-release has been commented out for rolling +release, we can replace openSUSE Tumbleweed specific handling for grub +distributor with a generic one. + +v2: +Use /usr/lib/os-release as fallback to /etc/os-release + +Index: grub-2.06/grub-core/osdep/unix/config.c +=================================================================== +--- grub-2.06.orig/grub-core/osdep/unix/config.c ++++ grub-2.06/grub-core/osdep/unix/config.c +@@ -61,6 +61,131 @@ grub_util_get_localedir (void) + return LOCALEDIR; + } + ++#ifdef __linux__ ++static char * ++os_release_get_val (const char *buf, const char *key) ++{ ++ const char *ptr = buf; ++ char *ret; ++ ++ while (*ptr && grub_isspace(*ptr)) ++ ptr++; ++ ++ if (*ptr == '#') ++ return NULL; ++ ++ if (grub_strncmp (ptr, key, grub_strlen (key)) != 0) ++ return NULL; ++ ++ ptr += grub_strlen (key); ++ if (*ptr++ != '=' || *ptr == '\0') ++ return NULL; ++ ++ if (*ptr == '"' || *ptr == '\'') ++ { ++ char c = *ptr; ++ int i = 0; ++ char *tmp, *ptmp; ++ ++ if (*++ptr == '\0') ++ return NULL; ++ ++ tmp = grub_strdup (ptr); ++ if ((ptmp = grub_strrchr (tmp, c))) ++ *ptmp = '\0'; ++ ++ ret = malloc (grub_strlen (tmp) + 1); ++ ptmp = tmp; ++ while (*ptmp) ++ { ++ if (*ptmp != '\\' || *(ptmp + 1) != c) ++ ret[i++] = *ptmp; ++ ++ptmp; ++ } ++ ++ grub_free (tmp); ++ ret[i] = '\0'; ++ } ++ else ++ { ++ char *pret; ++ ++ ret = grub_strdup (ptr); ++ if ((pret = grub_strchr (ret, ' '))) ++ *pret = '\0'; ++ } ++ ++ return ret; ++} ++ ++static char* ++grub_util_default_distributor (void) ++{ ++ char *cfgfile; ++ char buf[1024]; ++ FILE *fp = NULL; ++ char *os_name = NULL; ++ char *os_version = NULL; ++ ++ cfgfile = grub_util_path_concat (2, GRUB_SYSCONFDIR, "os-release"); ++ if (!grub_util_is_regular (cfgfile)) ++ { ++ grub_free (cfgfile); ++ cfgfile = grub_util_path_concat (2, "/usr/lib", "os-release"); ++ if (!grub_util_is_regular (cfgfile)) ++ { ++ grub_free (cfgfile); ++ return NULL; ++ } ++ } ++ ++ fp = grub_util_fopen (cfgfile, "r"); ++ ++ if (!fp) ++ { ++ grub_util_warn (_("cannot open configuration file `%s': %s"), ++ cfgfile, strerror (errno)); ++ grub_free (cfgfile); ++ return NULL; ++ } ++ ++ grub_free (cfgfile); ++ ++ while (fgets (buf, sizeof (buf), fp)) ++ { ++ if (buf[grub_strlen(buf) - 1] == '\n') ++ buf[grub_strlen(buf) - 1] = '\0'; ++ ++ if (!os_name ++ && (os_name = os_release_get_val (buf, "NAME"))) ++ continue; ++ if (!os_version ++ && (os_version = os_release_get_val (buf, "VERSION"))) ++ continue; ++ if (os_name && os_version) ++ break; ++ } ++ ++ fclose (fp); ++ ++ if (os_name && os_version) ++ { ++ char *os_name_version; ++ ++ os_name_version = grub_xasprintf ("%s %s", os_name, os_version); ++ ++ grub_free (os_name); ++ grub_free (os_version); ++ ++ return os_name_version; ++ } ++ ++ grub_free (os_version); ++ ++ return os_name; ++} ++#endif ++ + void + grub_util_load_config (struct grub_util_config *cfg) + { +@@ -125,7 +250,17 @@ grub_util_load_config (struct grub_util_ + waitpid (pid, NULL, 0); + } + if (f) +- return; ++ { ++#ifdef __linux__ ++ if (!cfg->grub_distributor || cfg->grub_distributor[0] == '\0') ++ { ++ if (cfg->grub_distributor) ++ grub_free (cfg->grub_distributor); ++ cfg->grub_distributor = grub_util_default_distributor (); ++ } ++#endif ++ return; ++ } + + f = grub_util_fopen (cfgfile, "r"); + if (f) +@@ -136,4 +271,13 @@ grub_util_load_config (struct grub_util_ + else + grub_util_warn (_("cannot open configuration file `%s': %s"), + cfgfile, strerror (errno)); ++ ++#ifdef __linux__ ++ if (!cfg->grub_distributor || cfg->grub_distributor[0] == '\0') ++ { ++ if (cfg->grub_distributor) ++ grub_free (cfg->grub_distributor); ++ cfg->grub_distributor = grub_util_default_distributor (); ++ } ++#endif + } +Index: grub-2.06/util/grub-mkconfig.in +=================================================================== +--- grub-2.06.orig/util/grub-mkconfig.in ++++ grub-2.06/util/grub-mkconfig.in +@@ -225,6 +225,19 @@ GRUB_ACTUAL_DEFAULT="$GRUB_DEFAULT" + + if [ "x${GRUB_ACTUAL_DEFAULT}" = "xsaved" ] ; then GRUB_ACTUAL_DEFAULT="`"${grub_editenv}" - list | sed -n '/^saved_entry=/ s,^saved_entry=,,p'`" ; fi + ++if [ x"${GRUB_DISTRIBUTOR}" = x ] ; then ++ for i in "${sysconfdir}/os-release" "/usr/lib/os-release" ; do ++ if [ -f "$i" ] ; then ++ . "$i" ++ break ++ fi ++ done ++ if [ x"${NAME}" != x ] && [ x"${VERSION}" != x ] ; then ++ GRUB_DISTRIBUTOR="${NAME} ${VERSION}" ++ else ++ GRUB_DISTRIBUTOR="${NAME}" ++ fi ++fi + + # These are defined in this script, export them here so that user can + # override them. diff --git a/grub2-diskfilter-support-pv-without-metadatacopies.patch b/grub2-diskfilter-support-pv-without-metadatacopies.patch new file mode 100644 index 0000000..ea7522f --- /dev/null +++ b/grub2-diskfilter-support-pv-without-metadatacopies.patch @@ -0,0 +1,223 @@ +From a28bc19400b4e70725ce5532bc5e4c374c72d7a9 Mon Sep 17 00:00:00 2001 +From: Lidong Zhong +Date: Wed, 26 Apr 2017 15:52:40 +0800 +Subject: [PATCH] diskfilter: implementation of processing no metadata recorded + in PV + +If one PV underlying the root LV is created with no metadata, such as + +pvcreate --metadatacopies 0 /dev/sda + +then we could get a lot of error messages when generating a new +configuration file. + +Generating grub configuration file ... +error: unknown LVM metadata header. +error: unknown LVM metadata header. +/usr/sbin/grub2-probe: warning: Couldn't find physical volume `pv1'. +Some modules may be missing from core image.. +(For details, please refer to + https://bugzilla.suse.com/show_bug.cgi?id=1027526) + +When one labelled PV which dose not have any metadata is found, we put +it into a global grub_detached_pv list. and we search all the PVs in the +current array list to check if it is a member of grub_detached_pv list. +So we can know if the PV is really missing or just without metadata. + +Signed-off-by: Lidong Zhong +--- + grub-core/disk/diskfilter.c | 112 +++++++++++++++++++++++++++++++++++++++++++- + grub-core/disk/lvm.c | 15 ++++-- + 2 files changed, 121 insertions(+), 6 deletions(-) + +Index: grub-2.06~rc1/grub-core/disk/diskfilter.c +=================================================================== +--- grub-2.06~rc1.orig/grub-core/disk/diskfilter.c ++++ grub-2.06~rc1/grub-core/disk/diskfilter.c +@@ -28,6 +28,7 @@ + #include + #include + #endif ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -43,7 +44,17 @@ static struct grub_diskfilter_lv * + find_lv (const char *name); + static int is_lv_readable (struct grub_diskfilter_lv *lv, int easily); + +- ++struct grub_detached_pv { ++ struct grub_detached_pv *next; ++ struct grub_detached_pv **prev; ++ struct grub_diskfilter_pv_id id; ++ grub_disk_t disk; ++ grub_diskfilter_t diskfilter; ++} ; ++ ++static struct grub_detached_pv *detached_pv_list; ++ ++#define FOR_DETACHED_PVS(var) for (var = detached_pv_list; var; var = var->next) + + static grub_err_t + is_node_readable (const struct grub_diskfilter_node *node, int easily) +@@ -132,6 +143,7 @@ scan_disk_partition_iter (grub_disk_t di + grub_disk_addr_t start_sector; + struct grub_diskfilter_pv_id id; + grub_diskfilter_t diskfilter; ++ struct grub_detached_pv *pv; + + grub_dprintf ("diskfilter", "Scanning for DISKFILTER devices on disk %s\n", + name); +@@ -168,6 +180,28 @@ scan_disk_partition_iter (grub_disk_t di + grub_free (id.uuid); + return 0; + } ++ /*insert the special LVM PV into detached_pv_list*/ ++ if (!arr && (id.uuidlen > 0) && (grub_strcmp(diskfilter->name, "lvm") == 0)) ++ { ++ pv = grub_zalloc(sizeof(*pv)); ++ if (!pv) ++ return 1; ++ pv->id.uuidlen = GRUB_LVM_ID_STRLEN; ++ pv->id.uuid = grub_malloc(GRUB_LVM_ID_STRLEN); ++ if (!pv->id.uuid) ++ goto fail_id; ++ grub_memcpy(pv->id.uuid, id.uuid, GRUB_LVM_ID_STRLEN); ++ /*It's safe to save disk into this standalone pv list*/ ++ pv->disk = grub_disk_open(name); ++ if (!pv->disk) ++ goto fail_id; ++ pv->diskfilter = diskfilter; ++ grub_list_push (GRUB_AS_LIST_P (&detached_pv_list), ++ GRUB_AS_LIST(pv)); ++#ifdef GRUB_UTIL ++ grub_util_info ("adding disk %s into detached pv list", name); ++#endif ++ } + if (arr && id.uuidlen) + grub_free (id.uuid); + +@@ -180,6 +214,65 @@ scan_disk_partition_iter (grub_disk_t di + } + + return 0; ++fail_id: ++ if (pv->id.uuidlen) ++ grub_free(pv->id.uuid); ++ grub_free(pv); ++ return 1; ++} ++ ++static int ++process_detached_pv_list(void) ++{ ++ struct grub_diskfilter_vg *arr; ++ struct grub_diskfilter_pv *pv1; ++ struct grub_detached_pv *pv2; ++ unsigned found = 0; ++ ++ for (arr = array_list; arr != NULL; arr = arr->next) ++ { ++ for (pv1 = arr->pvs; pv1; pv1 = pv1->next) ++ { ++ if (pv1->disk) ++ continue; ++ FOR_DETACHED_PVS(pv2) ++ { ++ if (pv2->id.uuidlen == pv1->id.uuidlen && ++ !grub_memcmp(pv2->id.uuid, pv1->id.uuid, pv1->id.uuidlen)) ++ { ++ if (insert_array(pv2->disk, &(pv2->id), arr, -1, pv2->diskfilter)) ++ return grub_errno; ++ else ++ { ++#ifdef GRUB_UTIL ++ grub_util_info ("found disk %s in detached pv list", pv1->disk->name); ++#endif ++ found = 1; ++ break; ++ } ++ } ++ } ++ /*remove pv2 from the list*/ ++ if (found) ++ { ++#ifdef GRUB_UTIL ++ grub_util_info ("removing disk %s from detached pv list", pv1->disk->name); ++#endif ++ grub_list_remove(GRUB_AS_LIST (pv2)); ++ if (pv2->id.uuidlen) ++ { ++ pv2->id.uuidlen = 0; ++ grub_free(pv2->id.uuid); ++ } ++ grub_disk_close(pv2->disk); ++ grub_free(pv2); ++ break; ++ } ++ } ++ if (found) ++ break; ++ } ++ return 0; + } + + static int +@@ -206,6 +299,9 @@ scan_disk (const char *name, int accept_ + grub_partition_iterate (disk, scan_disk_partition_iter, (void *) name); + grub_disk_close (disk); + scan_depth--; ++ ++ /*process the detached_pv_list*/ ++ process_detached_pv_list(); + return 0; + } + +@@ -1250,6 +1346,20 @@ insert_array (grub_disk_t disk, const st + static void + free_array (void) + { ++ while(detached_pv_list) ++ { ++ struct grub_detached_pv *pv; ++ pv = detached_pv_list; ++ detached_pv_list = detached_pv_list->next; ++#ifdef GRUB_UTIL ++ grub_util_warn (_("Couldn't find disk for physical volume `%s'." ++ "Some LVs may not work normally."),pv->disk->name); ++#endif ++ if (pv->id.uuidlen) ++ grub_free(pv->id.uuid); ++ grub_disk_close(pv->disk); ++ grub_free(pv); ++ } + while (array_list) + { + struct grub_diskfilter_vg *vg; +Index: grub-2.06~rc1/grub-core/disk/lvm.c +=================================================================== +--- grub-2.06~rc1.orig/grub-core/disk/lvm.c ++++ grub-2.06~rc1/grub-core/disk/lvm.c +@@ -235,11 +235,16 @@ grub_lvm_detect (grub_disk_t disk, + sizeof (mdah->magic))) + || (grub_le_to_cpu32 (mdah->version) != GRUB_LVM_FMTT_VERSION)) + { +- grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, +- "unknown LVM metadata header"); +-#ifdef GRUB_UTIL +- grub_util_info ("unknown LVM metadata header"); +-#endif ++ /* ++ * It's not necessarily an error. There is no metadata recorded when ++ * PV is created with pvmetadatacopies set to zero. We need to process ++ * this kind of PV seperately. ++ */ ++ id->uuid = grub_malloc(GRUB_LVM_ID_STRLEN); ++ if (!id->uuid) ++ goto fail; ++ grub_memcpy(id->uuid, pv_id, GRUB_LVM_ID_STRLEN); ++ id->uuidlen = GRUB_LVM_ID_STRLEN; + goto fail; + } + diff --git a/grub2-efi-HP-workaround.patch b/grub2-efi-HP-workaround.patch new file mode 100644 index 0000000..0ec7f6f --- /dev/null +++ b/grub2-efi-HP-workaround.patch @@ -0,0 +1,97 @@ + +v2: Add GRUB_FILE_TYPE_CONFIG to grub_file_open, see also upstream commit +ca0a4f689 verifiers: File type for fine-grained signature-verification controlling + +Index: grub-2.06~rc1/grub-core/kern/efi/init.c +=================================================================== +--- grub-2.06~rc1.orig/grub-core/kern/efi/init.c ++++ grub-2.06~rc1/grub-core/kern/efi/init.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include + + #ifdef GRUB_STACK_PROTECTOR +@@ -114,6 +115,67 @@ grub_efi_init (void) + void (*grub_efi_net_config) (grub_efi_handle_t hnd, + char **device, + char **path); ++static char * ++workaround_efi_firmware_path (const char *device, const char *path) ++{ ++ char *config = NULL;; ++ char *config_upper = NULL; ++ char *path_upper = NULL; ++ char *ret_path = NULL; ++ grub_file_t config_fd = NULL; ++ char *s; ++ ++ if (!device || !path) ++ return NULL; ++ ++ /* only workaround if booting off from cd device */ ++ if (grub_strncmp (device, "cd", 2) != 0) ++ goto quit; ++ ++ config = grub_xasprintf ("(%s)%s/grub.cfg", device, path); ++ config_fd = grub_file_open (config, GRUB_FILE_TYPE_CONFIG); ++ ++ /* everything's fine, so quit the workaround */ ++ if (config_fd) ++ goto quit; ++ ++ /* reset grub error state because noone else does... */ ++ grub_errno = GRUB_ERR_NONE; ++ ++ /* try again, this time upper case path */ ++ path_upper = grub_strdup (path); ++ if (! path_upper) ++ goto quit; ++ ++ s = path_upper; ++ for (; *s; s++) *s = grub_toupper(*s); ++ ++ config_upper = grub_xasprintf ("(%s)%s/grub.cfg", device, path_upper); ++ if (! config_upper) ++ goto quit; ++ ++ config_fd = grub_file_open (config_upper, GRUB_FILE_TYPE_CONFIG); ++ ++ /* if config can be found by the upper case path, return it */ ++ if (config_fd) ++ ret_path = grub_strdup (path_upper); ++ ++quit: ++ ++ if (config_fd) ++ grub_file_close (config_fd); ++ ++ if (grub_errno) ++ grub_errno = GRUB_ERR_NONE; ++ ++ if (config) ++ grub_free (config); ++ ++ if (config_upper) ++ grub_free (config_upper); ++ ++ return ret_path; ++} + + void + grub_machine_get_bootlocation (char **device, char **path) +@@ -138,6 +200,12 @@ grub_machine_get_bootlocation (char **de + p = grub_strrchr (*path, '/'); + if (p) + *p = '\0'; ++ ++ if ((p = workaround_efi_firmware_path (*device, *path))) ++ { ++ grub_free (*path); ++ *path = p; ++ } + } + } + diff --git a/grub2-efi-chainload-harder.patch b/grub2-efi-chainload-harder.patch new file mode 100644 index 0000000..fa673fb --- /dev/null +++ b/grub2-efi-chainload-harder.patch @@ -0,0 +1,107 @@ + +v2: +Use grub_efi_get_secureboot to get secure boot status + +--- + grub-core/loader/efi/chainloader.c | 62 +++++++++++++++++++++---------------- + 1 file changed, 36 insertions(+), 26 deletions(-) + +Index: grub-2.04/grub-core/loader/efi/chainloader.c +=================================================================== +--- grub-2.04.orig/grub-core/loader/efi/chainloader.c ++++ grub-2.04/grub-core/loader/efi/chainloader.c +@@ -286,40 +286,41 @@ grub_secure_validate (void *data, grub_e + static grub_efi_boolean_t + read_header (void *data, grub_efi_uint32_t size, pe_coff_loader_image_context_t *context) + { +- grub_efi_guid_t guid = SHIM_LOCK_GUID; +- grub_efi_shim_lock_t *shim_lock; +- grub_efi_status_t status; +- +- shim_lock = grub_efi_locate_protocol (&guid, NULL); ++ char *msdos = (char *)data; ++ struct grub_pe32_header_no_msdos_stub *pe32 = (struct grub_pe32_header_no_msdos_stub *)data; + +- if (!shim_lock) ++ if (size < sizeof (*pe32)) + { +- grub_error (GRUB_ERR_BAD_ARGUMENT, "no shim lock protocol"); ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid image"); + return 0; + } + +- status = shim_lock->context (data, size, context); +- +- if (status == GRUB_EFI_SUCCESS) ++ if (grub_memcmp (msdos, "MZ", 2) == 0) + { +- grub_dprintf ("chain", "context success\n"); +- return 1; ++ grub_uint32_t off = *((grub_uint32_t *) (msdos + 0x3c)); ++ pe32 = (struct grub_pe32_header_no_msdos_stub *) ((char *)data + off); + } + +- switch (status) ++ if (grub_memcmp (pe32->signature, "PE\0\0", 4) != 0 || ++ pe32->coff_header.machine != GRUB_PE32_MACHINE_X86_64 || ++ pe32->optional_header.magic != GRUB_PE32_PE64_MAGIC) + { +- case GRUB_EFI_UNSUPPORTED: +- grub_error (GRUB_ERR_BAD_ARGUMENT, "context error unsupported"); +- break; +- case GRUB_EFI_INVALID_PARAMETER: +- grub_error (GRUB_ERR_BAD_ARGUMENT, "context error invalid parameter"); +- break; +- default: +- grub_error (GRUB_ERR_BAD_ARGUMENT, "context error code"); +- break; ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "Not supported image"); ++ return 0; + } + +- return 0; ++ context->number_of_rva_and_sizes = pe32->optional_header.num_data_directories; ++ context->size_of_headers = pe32->optional_header.header_size; ++ context->image_size = pe32->optional_header.image_size; ++ context->image_address = pe32->optional_header.image_base; ++ context->entry_point = pe32->optional_header.entry_addr; ++ context->reloc_dir = &pe32->optional_header.base_relocation_table; ++ context->sec_dir = &pe32->optional_header.certificate_table; ++ context->number_of_sections = pe32->coff_header.num_sections; ++ context->pe_hdr = pe32; ++ context->first_section = (struct grub_pe32_section_table *)((char *)(&pe32->optional_header) + pe32->coff_header.optional_header_size); ++ ++ return 1; + } + + static void* +@@ -583,6 +584,9 @@ error_exit: + if (buffer) + efi_call_1 (b->free_pool, buffer); + ++ if (grub_errno) ++ grub_print_error (); ++ + return 0; + + } +@@ -790,6 +794,19 @@ grub_cmd_chainloader (grub_command_t cmd + status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path, + boot_image, fsize, + &image_handle); ++#ifdef SUPPORT_SECURE_BOOT ++ if (status == GRUB_EFI_SECURITY_VIOLATION && grub_efi_get_secureboot () != GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ { ++ /* If it failed with security violation while not in secure boot mode, ++ the firmware might be broken. We try to workaround on that by forcing ++ the SB method! (bsc#887793) */ ++ grub_dprintf ("chain", "Possible firmware flaw! Security violation while not in secure boot mode.\n"); ++ grub_file_close (file); ++ grub_loader_set (grub_secureboot_chainloader_boot, ++ grub_secureboot_chainloader_unload, 0); ++ return 0; ++ } ++#endif + if (status != GRUB_EFI_SUCCESS) + { + if (status == GRUB_EFI_OUT_OF_RESOURCES) diff --git a/grub2-efi-chainloader-root.patch b/grub2-efi-chainloader-root.patch new file mode 100644 index 0000000..9ef6fe7 --- /dev/null +++ b/grub2-efi-chainloader-root.patch @@ -0,0 +1,39 @@ +From: Raymund Will +Subject: Use device part of chainloader target, if present. +References: bnc#871857, bnc#880177 +Patch-Mainline: no + +Otherwise chainloading is restricted to '$root', which might not even +be readable by EFI! + +v1. use grub_file_get_device_name() to get device name + +Signed-off-by: Michael Chang + +--- + grub-core/loader/efi/chainloader.c | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +Index: grub-2.04~rc1/grub-core/loader/efi/chainloader.c +=================================================================== +--- grub-2.04~rc1.orig/grub-core/loader/efi/chainloader.c ++++ grub-2.04~rc1/grub-core/loader/efi/chainloader.c +@@ -714,12 +714,16 @@ grub_cmd_chainloader (grub_command_t cmd + *(--p16) = 0; + } + ++ grub_dprintf ("chain", "cmd='%s'\n", filename); + file = grub_file_open (filename, GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE); + if (! file) + goto fail; + +- /* Get the root device's device path. */ +- dev = grub_device_open (0); ++ /* Get the device path from filename. */ ++ char *devname = grub_file_get_device_name (filename); ++ dev = grub_device_open (devname); ++ if (devname) ++ grub_free (devname); + if (! dev) + goto fail; + diff --git a/grub2-efi-disable-video-cirrus-and-bochus.patch b/grub2-efi-disable-video-cirrus-and-bochus.patch new file mode 100644 index 0000000..f8f80f8 --- /dev/null +++ b/grub2-efi-disable-video-cirrus-and-bochus.patch @@ -0,0 +1,35 @@ +Index: grub-2.02~beta2/grub-core/Makefile.core.def +=================================================================== +--- grub-2.02~beta2.orig/grub-core/Makefile.core.def ++++ grub-2.02~beta2/grub-core/Makefile.core.def +@@ -1921,13 +1921,13 @@ module = { + module = { + name = video_cirrus; + x86 = video/cirrus.c; +- enable = x86; ++ enable = x86_noefi; + }; + + module = { + name = video_bochs; + x86 = video/bochs.c; +- enable = x86; ++ enable = x86_noefi; + }; + + module = { +Index: grub-2.02~beta2/gentpl.py +=================================================================== +--- grub-2.02~beta2.orig/gentpl.py ++++ grub-2.02~beta2/gentpl.py +@@ -80,6 +80,10 @@ GROUPS["fdt"] = [ "arm64_efi", "arm_uboo + GROUPS["i386_coreboot_multiboot_qemu"] = ["i386_coreboot", "i386_multiboot", "i386_qemu"] + GROUPS["nopc"] = GRUB_PLATFORMS[:]; GROUPS["nopc"].remove("i386_pc") + ++# x86 without efi ++GROUPS["x86_noefi"] = GROUPS["x86"][:] ++GROUPS["x86_noefi"].remove("i386_efi"); GROUPS["x86_noefi"].remove("x86_64_efi"); ++ + # + # Create platform => groups reverse map, where groups covering that + # platform are ordered by their sizes diff --git a/grub2-efi-xen-cfg-unquote.patch b/grub2-efi-xen-cfg-unquote.patch new file mode 100644 index 0000000..14bad50 --- /dev/null +++ b/grub2-efi-xen-cfg-unquote.patch @@ -0,0 +1,92 @@ +From: Petr Tesarik +Subject: Unquote parameters written to Xen EFI config file +References: bsc#900418 +Patch-mainline: not yet + +The GRUB_CMDLINE_* value is copied verbatim to grub.conf, so it is first +parsed by GRUB2 before being passed down to the kernel. OTOH Xen EFI loader +takes the config file options verbatim. This means that any special GRUB2 +syntax must be evaluated when generating that file. + +Of course, some things are not even possible (e.g. substituting GRUB runtime +variables), but let's call them known limitations. + +Signed-off-by: Petr Tesarik + +--- + util/grub.d/20_linux_xen.in | 54 ++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 52 insertions(+), 2 deletions(-) + +Index: grub-2.06~rc1/util/grub.d/20_linux_xen.in +=================================================================== +--- grub-2.06~rc1.orig/util/grub.d/20_linux_xen.in ++++ grub-2.06~rc1/util/grub.d/20_linux_xen.in +@@ -137,6 +137,52 @@ else + is_efi=false + fi + ++grub2_unquote () ++{ ++ awk ' ++ BEGIN { ++ bare = "[^{}|&$;<> \t\n'\''\"\\\\]+" ++ esc = "\\\\." ++ id = "[[:alpha:]_][[:alnum:]_]*|[[:digit:]]+|[?#*@]" ++ var = "\\$("id")|\\$\\{("id")\\}" ++ dqesc = "\\\\[$\"\\\\]" ++ dqstr = "\\$?\"([^\"]|"var"|"dqesc")*\"" ++ sqstr = "'\''[^'\'']*'\''" ++ pat = bare"|"esc"|"var"|"dqstr"|"sqstr ++ ORS = "" ++ } ++ { ++ patsplit($0, words, pat, sep) ++ print sep[0] ++ for (i in words) { ++ w = words[i] ++ if (w ~ /^\$?"/) { ++ # Double-quoted string ++ patsplit(w, segs, var"|"dqesc, ssep) ++ print ssep[0] ++ for (j in segs) { ++ if (segs[j] ~ /^\\/) ++ print substr(segs[j], 2) ++ print ssep[j] ++ } ++ } else if (w ~ /^'\''/) { ++ # Single-quoted string ++ print substr(w, 2, length(w)-2) ++ } else if (w ~ /^\\/) { ++ # Escape sequence ++ print substr(w, 2) ++ } else if (w ~ /^\$/) { ++ # Variable expansion ++ } else { ++ # Bare word ++ print w ++ } ++ print sep[i] ++ } ++ print "\n" ++ }' ++} ++ + linux_entry () + { + linux_entry_xsm "$@" false +@@ -205,11 +251,13 @@ linux_entry_xsm () + else + section="failsafe.$section_count" + fi ++ xen_args_unq=$(echo $xen_args | grub2_unquote) ++ args_unq=$(echo $args | grub2_unquote) + cat <<-EOF >> $grub_dir/$xen_cfg + + [$section] +- options=${xen_args} +- kernel=${basename} root=${linux_root_device_thisversion} ${args} ++ options=${xen_args_unq} ++ kernel=${basename} root=${linux_root_device_thisversion} ${args_unq} + ramdisk=${initrd_real} + EOF + message="$(gettext_printf "Loading Xen %s with Linux %s ..." ${xen_version} ${version})" diff --git a/grub2-efi-xen-chainload.patch b/grub2-efi-xen-chainload.patch new file mode 100644 index 0000000..06d3d30 --- /dev/null +++ b/grub2-efi-xen-chainload.patch @@ -0,0 +1,198 @@ +From: Raymund Will +Subject: Use chainloader to boot xen.efi under UEFI. +References: bnc#871857, bnc#879148 +Patch-Mainline: no + +As XEN on SLE12 is not multiboot2 ready, some very dirty hacking +is necessary to boot via xen.efi and separate configfile snippets +(as done in SLE11SP3 secureboot). + +To that end said configfile snippets, xen efi-binaries, kernels and initrds +need to copied to the EFI system partition during 'grub2-mkconfig'! + +V0: +- first, somewhat fragile version, without any sort of cleanup for ESP. +V1: +- add missing whitespace. (bnc879148) +V2: +- second, much less fragile version, using only one config file per + XEN hypervisor version with sections for different kernels, avoiding + useless duplicates for sym-linked hypervisors. and removing previously + installed files from ESP. +V3: +- support move to '/usr/share/efi/$machine' for EFI-binaries. (bsc#1122563) + +--- + util/grub.d/20_linux_xen.in | 109 +++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 97 insertions(+), 12 deletions(-) + +Index: grub-2.06~rc1/util/grub.d/20_linux_xen.in +=================================================================== +--- grub-2.06~rc1.orig/util/grub.d/20_linux_xen.in ++++ grub-2.06~rc1/util/grub.d/20_linux_xen.in +@@ -21,6 +21,8 @@ prefix="@prefix@" + exec_prefix="@exec_prefix@" + datarootdir="@datarootdir@" + ++ME=$(basename $0) ++ + . "$pkgdatadir/grub-mkconfig_lib" + + export TEXTDOMAIN=@PACKAGE@ +@@ -36,11 +38,23 @@ CLASS="--class gnu-linux --class gnu --c + + if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then + OS=GNU/Linux ++ os=linux + else + OS="${GRUB_DISTRIBUTOR}" +- CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1|LC_ALL=C sed 's,[^[:alnum:]_],_,g') ${CLASS}" ++ os="$(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1)" ++ CLASS="--class ${os} ${CLASS}" + fi + ++machine=`uname -m` ++ ++case "$machine" in ++ i?86) GENKERNEL_ARCH="x86" ;; ++ mips|mips64) GENKERNEL_ARCH="mips" ;; ++ mipsel|mips64el) GENKERNEL_ARCH="mipsel" ;; ++ arm*) GENKERNEL_ARCH="arm" ;; ++ *) GENKERNEL_ARCH="$machine" ;; ++esac ++ + # loop-AES arranges things so that /dev/loop/X can be our root device, but + # the initrds that Linux uses don't like that. + case ${GRUB_DEVICE} in +@@ -97,6 +111,32 @@ esac + + title_correction_code= + ++if [ -d /sys/firmware/efi ]; then ++ is_efi=true ++ err_msg="" ++ efi_dir="/boot/efi/efi/${os}" ++ grub_dir=/boot/@PACKAGE@ ++ xen_dir=/usr/share/efi/$machine ++ [ -d $xen_dir ] || xen_dir=/usr/lib64/efi ++ for d in $grub_dir $efi_dir $xen_dir; do ++ [ ! -d "$d" ] || continue ++ err_msg="${err_msg}$ME: Essential directory '$d' not found!\n" ++ done ++ if ! [ -d "$efi_dir" -a -d "$grub_dir" -a -d "$xen_dir" ]; then ++ err_msg="${err_msg}$ME: XEN configuration skipped!\n" ++ else ++ rm -f $grub_dir/xen*.cfg ++ if [ -s $efi_dir/grub.xen-files ]; then ++ for f in $(sort $efi_dir/grub.xen-files| uniq); do ++ rm -f $efi_dir/$f ++ done ++ : > $efi_dir/grub.xen-files ++ fi ++ fi ++else ++ is_efi=false ++fi ++ + linux_entry () + { + linux_entry_xsm "$@" false +@@ -150,6 +190,40 @@ linux_entry_xsm () + save_default_entry | grub_add_tab | sed "s/^/$submenu_indentation/" + fi + ++ if $is_efi; then ++ xen_cfg=${xen_basename/.efi/.cfg} ++ if [ "$section_count" = 0 ]; then ++ cat <<-EOF > $grub_dir/$xen_cfg ++ # disclaimer ++ [global] ++ #default= ++ EOF ++ fi ++ section_count=$(expr $section_count + 1) ++ if [ x$type != xrecovery ] ; then ++ section="config.$section_count" ++ else ++ section="failsafe.$section_count" ++ fi ++ cat <<-EOF >> $grub_dir/$xen_cfg ++ ++ [$section] ++ options=${xen_args} ++ kernel=${basename} root=${linux_root_device_thisversion} ${args} ++ ramdisk=${initrd_real} ++ EOF ++ message="$(gettext_printf "Loading Xen %s with Linux %s ..." ${xen_version} ${version})" ++ sed "s/^/$submenu_indentation/" <<-EOF ++ echo '$(echo "$message" | grub_quote)' ++ chainloader \$cmdpath/${xen_basename} ${xen_basename} $section ++ } ++ EOF ++ for f in ${grub_dir}/$xen_cfg ${xen_dir}/${xen_basename} ${dirname}/${basename} ${dirname}/${initrd_real}; do ++ cp --preserve=timestamps $f $efi_dir ++ echo $(basename $f) >> $efi_dir/grub.xen-files ++ done ++ return ++ fi + if [ -z "${prepare_boot_cache}" ]; then + prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | grub_add_tab)" + fi +@@ -241,16 +315,6 @@ boot_device_id= + + title_correction_code= + +-machine=`uname -m` +- +-case "$machine" in +- i?86) GENKERNEL_ARCH="x86" ;; +- mips|mips64) GENKERNEL_ARCH="mips" ;; +- mipsel|mips64el) GENKERNEL_ARCH="mipsel" ;; +- arm*) GENKERNEL_ARCH="arm" ;; +- *) GENKERNEL_ARCH="$machine" ;; +-esac +- + # Extra indentation to add to menu entries in a submenu. We're not in a submenu + # yet, so it's empty. In a submenu it will be equal to '\t' (one tab). + submenu_indentation="" +@@ -264,6 +328,24 @@ while [ "x${xen_list}" != "x" ] ; do + xen_dirname=`dirname ${current_xen}` + rel_xen_dirname=`make_system_path_relative_to_its_root $xen_dirname` + xen_version=`echo $xen_basename | sed -e "s,.gz$,,g;s,^xen-,,g"` ++ xen_list=`echo $xen_list | tr ' ' '\n' | grep -vx $current_xen | tr '\n' ' '` ++ if $is_efi; then ++ xen_basename=${xen_basename/.gz/.efi} ++ if ! [ -f ${xen_dir}/${xen_basename} ]; then ++ echo "Skip missing hypervisor $xen_dir/$xen_basename" >&2 ++ continue ++ elif [ -L ${xen_dir}/${xen_basename} ]; then ++ xen_target=$(basename $(readlink -e ${xen_dir}/${xen_basename})) ++ if [ -f ${efi_dir}/${xen_target} ]; then ++ echo "Skip duplicate $xen_dir/$xen_basename for $xen_target" >&2 ++ continue ++ fi ++ elif [ -n "$err_msg" ]; then ++ break ++ fi ++ gettext_printf "Found hypervisor: %s\n" "$current_xen" >&2 ++ section_count=0 ++ fi + if [ -z "$boot_device_id" ]; then + boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" + fi +@@ -373,7 +455,6 @@ while [ "x${xen_list}" != "x" ] ; do + if [ x"$is_top_level" != xtrue ]; then + echo ' }' + fi +- xen_list=`echo $xen_list | tr ' ' '\n' | fgrep -vx "$current_xen" | tr '\n' ' '` + done + + # If at least one kernel was found, then we need to +@@ -383,3 +464,7 @@ if [ x"$is_top_level" != xtrue ]; then + fi + + echo "$title_correction_code" ++ ++if [ -n "$err_msg" ]; then ++ echo -en "$err_msg" >&2 ++fi diff --git a/grub2-efi-xen-cmdline.patch b/grub2-efi-xen-cmdline.patch new file mode 100644 index 0000000..0512301 --- /dev/null +++ b/grub2-efi-xen-cmdline.patch @@ -0,0 +1,23 @@ +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -295,7 +295,8 @@ + GRUB_OS_PROBER_SKIP_LIST \ + GRUB_DISABLE_SUBMENU \ + GRUB_CMDLINE_LINUX_RECOVERY \ +- SUSE_BTRFS_SNAPSHOT_BOOTING ++ SUSE_BTRFS_SNAPSHOT_BOOTING \ ++ SUSE_CMDLINE_XENEFI + + if test "x${grub_cfg}" != "x"; then + rm -f "${grub_cfg}.new" +--- a/util/grub.d/20_linux_xen.in ++++ b/util/grub.d/20_linux_xen.in +@@ -216,7 +216,7 @@ + message="$(gettext_printf "Loading Xen %s with Linux %s ..." ${xen_version} ${version})" + sed "s/^/$submenu_indentation/" <<-EOF + echo '$(echo "$message" | grub_quote)' +- chainloader \$cmdpath/${xen_basename} ${xen_basename} $section ++ chainloader \$cmdpath/${xen_basename} ${xen_basename} ${SUSE_CMDLINE_XENEFI} $section + } + EOF + for f in ${grub_dir}/$xen_cfg ${xen_dir}/${xen_basename} ${dirname}/${basename} ${dirname}/${initrd_real}; do diff --git a/grub2-efi-xen-removable.patch b/grub2-efi-xen-removable.patch new file mode 100644 index 0000000..695a01c --- /dev/null +++ b/grub2-efi-xen-removable.patch @@ -0,0 +1,117 @@ +From: Michael Chang +References: bsc#1085842 +Patch-Mainline: no + +The grub can be installed with removable option to support booting from +removable media with standard UEFI default file path of the form: + \EFI\BOOT\BOOT{machine type short-name}.EFI + +It does not make use of distributor directory, which becomes a problem for UEFI +Xen installation as it requires that directory to be present for storing xen +stuff like chainloaded hypervisor, xen kernel and so on. Moreover it makes bad +assumption that hypervisor will be chainloaded by grub under the same +directory, which is also not always true. + +This patch fixes the problem by ensuring the directory available to Xen +installation if any Xen hypervisor found and independent to grub boot path +$cmdpath to work. + +--- + util/grub.d/20_linux_xen.in | 62 ++++++++++++++++++++++++-------------------- + 1 file changed, 35 insertions(+), 27 deletions(-) + +--- a/util/grub.d/20_linux_xen.in ++++ b/util/grub.d/20_linux_xen.in +@@ -101,32 +101,6 @@ esac + + title_correction_code= + +-if [ -d /sys/firmware/efi ]; then +- is_efi=true +- err_msg="" +- efi_dir="/boot/efi/efi/${os}" +- grub_dir=/boot/@PACKAGE@ +- xen_dir=/usr/share/efi/$machine +- [ -d $xen_dir ] || xen_dir=/usr/lib64/efi +- for d in $grub_dir $efi_dir $xen_dir; do +- [ ! -d "$d" ] || continue +- err_msg="${err_msg}$ME: Essential directory '$d' not found!\n" +- done +- if ! [ -d "$efi_dir" -a -d "$grub_dir" -a -d "$xen_dir" ]; then +- err_msg="${err_msg}$ME: XEN configuration skipped!\n" +- else +- rm -f $grub_dir/xen*.cfg +- if [ -s $efi_dir/grub.xen-files ]; then +- for f in $(sort $efi_dir/grub.xen-files| uniq); do +- rm -f $efi_dir/$f +- done +- : > $efi_dir/grub.xen-files +- fi +- fi +-else +- is_efi=false +-fi +- + grub2_unquote () + { + awk ' +@@ -234,10 +208,15 @@ linux_entry () + kernel=${basename} root=${linux_root_device_thisversion} ${args_unq} + ramdisk=${initrd_real} + EOF ++ if [ -z "${prepare_efi_cache}" ]; then ++ grub_device_efi="`${grub_probe} --target=device /boot/efi`" ++ prepare_efi_cache="$(prepare_grub_to_access_device ${grub_device_efi} | grub_add_tab)" ++ fi ++ printf '%s\n' "${prepare_efi_cache}" | sed "s/^/$submenu_indentation/" + message="$(gettext_printf "Loading Xen %s with Linux %s ..." ${xen_version} ${version})" + sed "s/^/$submenu_indentation/" <<-EOF + echo '$(echo "$message" | grub_quote)' +- chainloader \$cmdpath/${xen_basename} ${xen_basename} ${SUSE_CMDLINE_XENEFI} $section ++ chainloader ${rel_efi_dir}/${xen_basename} ${xen_basename} ${SUSE_CMDLINE_XENEFI} $section + } + EOF + for f in ${grub_dir}/$xen_cfg ${xen_dir}/${xen_basename} ${dirname}/${basename} ${dirname}/${initrd_real}; do +@@ -318,6 +297,7 @@ else + done + fi + prepare_boot_cache= ++prepare_efi_cache= + boot_device_id= + + title_correction_code= +@@ -328,6 +308,34 @@ submenu_indentation="" + + is_top_level=true + ++if [ -d /sys/firmware/efi ] && [ "x${xen_list}" != "x" ]; then ++ is_efi=true ++ err_msg="" ++ efi_dir="/boot/efi/efi/${os}" ++ grub_dir=/boot/grub2 ++ xen_dir=/usr/share/efi/$machine ++ [ -d $xen_dir ] || xen_dir=/usr/lib64/efi ++ for d in $grub_dir $xen_dir; do ++ [ ! -d "$d" ] || continue ++ err_msg="${err_msg}$ME: Essential directory '$d' not found!\n" ++ done ++ if ! [ -d "$grub_dir" -a -d "$xen_dir" ]; then ++ err_msg="${err_msg}$ME: XEN configuration skipped!\n" ++ else ++ mkdir -p $efi_dir ++ rel_efi_dir=`make_system_path_relative_to_its_root $efi_dir` ++ rm -f $grub_dir/xen*.cfg ++ if [ -s $efi_dir/grub.xen-files ]; then ++ for f in $(sort $efi_dir/grub.xen-files| uniq); do ++ rm -f $efi_dir/$f ++ done ++ : > $efi_dir/grub.xen-files ++ fi ++ fi ++else ++ is_efi=false ++fi ++ + while [ "x${xen_list}" != "x" ] ; do + list="${linux_list}" + current_xen=`version_find_latest $xen_list` diff --git a/grub2-efi_gop-avoid-low-resolution.patch b/grub2-efi_gop-avoid-low-resolution.patch new file mode 100644 index 0000000..484cee1 --- /dev/null +++ b/grub2-efi_gop-avoid-low-resolution.patch @@ -0,0 +1,39 @@ +--- + grub-core/video/efi_gop.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +--- a/grub-core/video/efi_gop.c ++++ b/grub-core/video/efi_gop.c +@@ -358,6 +358,7 @@ grub_video_gop_setup (unsigned int width + grub_err_t err; + unsigned bpp; + int found = 0; ++ int avoid_low_resolution = 1; + unsigned long long best_volume = 0; + unsigned int preferred_width = 0, preferred_height = 0; + grub_uint8_t *buffer; +@@ -376,8 +377,11 @@ grub_video_gop_setup (unsigned int width + } + } + ++again: + /* Keep current mode if possible. */ +- if (gop->mode->info) ++ if (gop->mode->info && ++ (!avoid_low_resolution || ++ (gop->mode->info->width >= 800 && gop->mode->info->height >= 600))) + { + bpp = grub_video_gop_get_bpp (gop->mode->info); + if (bpp && ((width == gop->mode->info->width +@@ -450,6 +454,11 @@ grub_video_gop_setup (unsigned int width + + if (!found) + { ++ if (avoid_low_resolution && gop->mode->info) ++ { ++ avoid_low_resolution = 0; ++ goto again; ++ } + grub_dprintf ("video", "GOP: no mode found\n"); + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching mode found"); + } diff --git a/grub2-emu-4-all.patch b/grub2-emu-4-all.patch new file mode 100644 index 0000000..ba94f3e --- /dev/null +++ b/grub2-emu-4-all.patch @@ -0,0 +1,170 @@ +--- + Makefile.util.def | 10 +++++----- + configure.ac | 1 + + grub-core/Makefile.core.def | 14 +++++--------- + grub-core/osdep/unix/emuconsole.c | 5 +++-- + 4 files changed, 14 insertions(+), 16 deletions(-) + +Index: grub-2.04~rc1/Makefile.util.def +=================================================================== +--- grub-2.04~rc1.orig/Makefile.util.def ++++ grub-2.04~rc1/Makefile.util.def +@@ -362,7 +362,7 @@ program = { + ldadd = grub-core/lib/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; + cppflags = '-DGRUB_SETUP_FUNC=grub_util_bios_setup'; +- emu_condition = COND_NOT_s390x; ++ emu_condition = COND_NOT_emu; + }; + + program = { +@@ -383,7 +383,7 @@ program = { + ldadd = grub-core/lib/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; + cppflags = '-DGRUB_SETUP_FUNC=grub_util_sparc_setup'; +- emu_condition = COND_NOT_s390x; ++ emu_condition = COND_NOT_emu; + }; + + program = { +@@ -399,7 +399,7 @@ program = { + ldadd = libgrubkern.a; + ldadd = grub-core/lib/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; +- emu_condition = COND_NOT_s390x; ++ emu_condition = COND_NOT_emu; + }; + + program = { +@@ -430,7 +430,7 @@ program = { + ldadd = libgrubkern.a; + ldadd = grub-core/lib/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; +- emu_condition = COND_NOT_s390x; ++ emu_condition = COND_NOT_emu; + }; + + data = { +@@ -1361,7 +1361,7 @@ program = { + ldadd = libgrubkern.a; + ldadd = grub-core/lib/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; +- emu_condition = COND_NOT_s390x; ++ emu_condition = COND_NOT_emu; + }; + + program = { +Index: grub-2.04~rc1/grub-core/Makefile.core.def +=================================================================== +--- grub-2.04~rc1.orig/grub-core/Makefile.core.def ++++ grub-2.04~rc1/grub-core/Makefile.core.def +@@ -1139,7 +1139,7 @@ module = { + module = { + name = videotest; + common = commands/videotest.c; +- emu_condition = COND_NOT_s390x; ++ emu_condition = COND_NOT_emu; + }; + + module = { +@@ -1572,7 +1572,7 @@ module = { + common = gfxmenu/gui_progress_bar.c; + common = gfxmenu/gui_util.c; + common = gfxmenu/gui_string_util.c; +- emu_condition = COND_NOT_s390x; ++ emu_condition = COND_NOT_emu; + }; + + module = { +@@ -2008,13 +2008,13 @@ module = { + name = gfxterm; + common = term/gfxterm.c; + enable = videomodules; +- emu_condition = COND_NOT_s390x; ++ emu_condition = COND_NOT_emu; + }; + + module = { + name = gfxterm_background; + common = term/gfxterm_background.c; +- emu_condition = COND_NOT_s390x; ++ emu_condition = COND_NOT_emu; + }; + + module = { +@@ -2133,9 +2133,7 @@ module = { + enable = i386_xen_pvh; + enable = i386_efi; + enable = x86_64_efi; +- enable = emu; + enable = xen; +- emu_condition = COND_NOT_s390x; + }; + + module = { +@@ -2182,7 +2180,7 @@ module = { + module = { + name = gfxterm_menu; + common = tests/gfxterm_menu.c; +- emu_condition = COND_NOT_s390x; ++ emu_condition = COND_NOT_emu; + }; + + module = { +@@ -2334,9 +2332,7 @@ module = { + enable = i386_xen_pvh; + enable = i386_efi; + enable = x86_64_efi; +- enable = emu; + enable = xen; +- emu_condition = COND_NOT_s390x; + }; + + module = { +Index: grub-2.04~rc1/configure.ac +=================================================================== +--- grub-2.04~rc1.orig/configure.ac ++++ grub-2.04~rc1/configure.ac +@@ -1911,6 +1911,7 @@ AC_SUBST(BUILD_LIBM) + + AM_CONDITIONAL([COND_real_platform], [test x$platform != xnone]) + AM_CONDITIONAL([COND_emu], [test x$platform = xemu]) ++AM_CONDITIONAL([COND_NOT_emu], [test x$platform != xemu]) + AM_CONDITIONAL([COND_i386_pc], [test x$target_cpu = xi386 -a x$platform = xpc]) + AM_CONDITIONAL([COND_i386_efi], [test x$target_cpu = xi386 -a x$platform = xefi]) + AM_CONDITIONAL([COND_ia64_efi], [test x$target_cpu = xia64 -a x$platform = xefi]) +Index: grub-2.04~rc1/grub-core/osdep/unix/emuconsole.c +=================================================================== +--- grub-2.04~rc1.orig/grub-core/osdep/unix/emuconsole.c ++++ grub-2.04~rc1/grub-core/osdep/unix/emuconsole.c +@@ -50,13 +50,12 @@ static struct termios new_tty; + static int console_mode = 0; + + #define MAX_LEN 1023 +-#if defined(__s390x__) ++ + static int + dummy (void) + { + return 0; + } +-#endif + #if 0 + static char msg[MAX_LEN+1]; + static void +@@ -128,6 +127,7 @@ readkey (struct grub_term_input *term) + return -1; + } + ++#if defined(__s390x__) + #define NO_KEY ((grub_uint8_t)-1) + static int + readkey_dumb (struct grub_term_input *term) +@@ -158,6 +158,7 @@ readkey_dumb (struct grub_term_input *te + p = c; + return c; + } ++#endif + + static void + grub_dumb_putchar (struct grub_term_output *term, diff --git a/grub2-fix-error-terminal-gfxterm-isn-t-found.patch b/grub2-fix-error-terminal-gfxterm-isn-t-found.patch new file mode 100644 index 0000000..b7ce563 --- /dev/null +++ b/grub2-fix-error-terminal-gfxterm-isn-t-found.patch @@ -0,0 +1,34 @@ +From e2e0fe44cf2a03744e96f886f95ab2c2a8aed331 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Wed, 18 Jul 2012 14:54:32 +0800 +Subject: [PATCH] fix error: terminal 'gfxterm' isn't found + +References: bnc#771393 +Patch-Mainline: no + +If set GRUB_TERMINAL="gfxterm", the error message "terminal +'gfxterm' isn't found" will be logged to screen. This is caused +by GRUB_TERMINAL_INPUT erroneously set to gfxterm. This patch +fixes the issue by not setting it. + +v2: +Fix error gfxterm isn't found with multiple terminals (bsc#1187565) + +--- + util/grub-mkconfig.in | 6 +++++- + 1 files changed, 5 insertions(+), 1 deletions(-) + +Index: grub-2.06/util/grub-mkconfig.in +=================================================================== +--- grub-2.06.orig/util/grub-mkconfig.in ++++ grub-2.06/util/grub-mkconfig.in +@@ -172,7 +172,8 @@ fi + + # XXX: should this be deprecated at some point? + if [ "x${GRUB_TERMINAL}" != "x" ] ; then +- GRUB_TERMINAL_INPUT="${GRUB_TERMINAL}" ++# bnc#771393, bsc#1187565 - fix error: terminal 'gfxterm' isn't found. ++ GRUB_TERMINAL_INPUT="`echo ${GRUB_TERMINAL} | sed -e '/\bgfxterm\b/{s/\bconsole\b//g;s/\bgfxterm\b/console/}'`" + GRUB_TERMINAL_OUTPUT="${GRUB_TERMINAL}" + fi + diff --git a/grub2-fix-menu-in-xen-host-server.patch b/grub2-fix-menu-in-xen-host-server.patch new file mode 100644 index 0000000..c2eea6c --- /dev/null +++ b/grub2-fix-menu-in-xen-host-server.patch @@ -0,0 +1,130 @@ +From b411dc88b46890400a2e1ba0aa8650e00f738c23 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Thu, 19 Jul 2012 18:43:55 +0800 +Subject: [PATCH] fix menu in xen host server + +References: bnc#771689, bnc#757895 +Patch-Mainline: no + +When system is configred as "Xen Virtual Machines Host Server", the +grub2 menu is not well organized. We could see some issues on it. + + - Many duplicated xen entries generated by links to xen hypervisor + - Non bootable kernel entries trying to boot xen kernel natively + - The -dbg xen hypervisor takes precedence over release version + +This patch fixes above three issues. + +v2: +References: bnc#877040 +Create only hypervisor pointed by /boot/xen.gz symlink to not clutter +the menu with multiple versions and also not include -dbg. Use custom.cfg +if you need any other custom entries. + +--- + util/grub-mkconfig_lib.in | 5 +++++ + util/grub.d/10_linux.in | 12 ++++++++++-- + util/grub.d/20_linux_xen.in | 6 ++++-- + 3 files changed, 19 insertions(+), 4 deletions(-) + +Index: grub-2.06~rc1/util/grub-mkconfig_lib.in +=================================================================== +--- grub-2.06~rc1.orig/util/grub-mkconfig_lib.in ++++ grub-2.06~rc1/util/grub-mkconfig_lib.in +@@ -253,6 +253,11 @@ version_test_gt () + *.old:*.old) ;; + *.old:*) version_test_gt_a="`echo "$version_test_gt_a" | sed -e 's/\.old$//'`" ; version_test_gt_cmp=gt ;; + *:*.old) version_test_gt_b="`echo "$version_test_gt_b" | sed -e 's/\.old$//'`" ; version_test_gt_cmp=ge ;; ++# bnc#757895 - Grub2 menu items incorrect when "Xen Virtual Machines Host Server" selected ++# The dbg version should be placed after release version ++ dbg-*:dbg-*) ;; ++ dbg-*:*) version_test_gt_a="" ;; ++ *:dbg-*) version_test_gt_b="" ;; + esac + version_test_numeric "$version_test_gt_a" "$version_test_gt_cmp" "$version_test_gt_b" + return "$?" +Index: grub-2.06~rc1/util/grub.d/20_linux_xen.in +=================================================================== +--- grub-2.06~rc1.orig/util/grub.d/20_linux_xen.in ++++ grub-2.06~rc1/util/grub.d/20_linux_xen.in +@@ -26,6 +26,12 @@ datarootdir="@datarootdir@" + export TEXTDOMAIN=@PACKAGE@ + export TEXTDOMAINDIR="@localedir@" + ++if [ ! -e /proc/xen/xsd_port -a -e /proc/xen ]; then ++# we're running on xen domU guest ++# prevent setting up nested virt on HVM or PV domU guest ++ exit 0 ++fi ++ + CLASS="--class gnu-linux --class gnu --class os --class xen" + + if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then +@@ -210,10 +216,18 @@ file_is_not_xen_garbage () { + esac + } + +-xen_list= +-for i in /boot/xen*; do +- if grub_file_is_not_garbage "$i" && file_is_not_xen_garbage "$i" ; then xen_list="$xen_list $i" ; fi +-done ++# bnc#877040 - Duplicate entries for boot menu created ++# only create /boot/xen.gz symlink boot entry ++if test -L /boot/xen.gz; then ++ xen_list=`readlink -f /boot/xen.gz` ++else ++ # bnc#757895 - Grub2 menu items incorrect when "Xen Virtual Machines Host Server" selected ++ # wildcard expasion with correct suffix (.gz) for not generating many duplicated menu entries ++ xen_list= ++ for i in /boot/xen*.gz; do ++ if grub_file_is_not_garbage "$i" && file_is_not_sym "$i" ; then xen_list="$xen_list $i" ; fi ++ done ++fi + prepare_boot_cache= + boot_device_id= + +Index: grub-2.06~rc1/util/grub.d/10_linux.in +=================================================================== +--- grub-2.06~rc1.orig/util/grub.d/10_linux.in ++++ grub-2.06~rc1/util/grub.d/10_linux.in +@@ -244,6 +244,40 @@ while [ "x$list" != "x" ] ; do + fi + done + ++ # try to get the kernel config if $linux is a symlink ++ if test -z "${config}" ; then ++ lnk_version=`basename \`readlink -f $linux\` | sed -e "s,^[^0-9]*-,,g"` ++ if (test -n ${lnk_version} && test -e "${dirname}/config-${lnk_version}") ; then ++ config="${dirname}/config-${lnk_version}" ++ fi ++ fi ++ ++ # check if we are in xen domU ++ if [ ! -e /proc/xen/xsd_port -a -e /proc/xen ]; then ++ # we're running on xen domU guest ++ dmi=/sys/class/dmi/id ++ if [ -r "${dmi}/product_name" -a -r "${dmi}/sys_vendor" ]; then ++ product_name=`cat ${dmi}/product_name` ++ sys_vendor=`cat ${dmi}/sys_vendor` ++ if test "${sys_vendor}" = "Xen" -a "${product_name}" = "HVM domU"; then ++ # xen HVM guest ++ xen_pv_domU=false ++ fi ++ fi ++ else ++ # we're running on baremetal or xen dom0 ++ xen_pv_domU=false ++ fi ++ ++ if test "$xen_pv_domU" = "false" ; then ++ # prevent xen kernel without pv_opt support from booting ++ if (grep -qx "CONFIG_XEN=y" "${config}" 2> /dev/null && ! grep -qx "CONFIG_PARAVIRT=y" "${config}" 2> /dev/null); then ++ echo "Skip xenlinux kernel $linux" >&2 ++ list=`echo $list | tr ' ' '\n' | grep -vx $linux | tr '\n' ' '` ++ continue ++ fi ++ fi ++ + initramfs= + if test -n "${config}" ; then + initramfs=`grep CONFIG_INITRAMFS_SOURCE= "${config}" | cut -f2 -d= | tr -d \"` diff --git a/grub2-getroot-scan-disk-pv.patch b/grub2-getroot-scan-disk-pv.patch new file mode 100644 index 0000000..e323238 --- /dev/null +++ b/grub2-getroot-scan-disk-pv.patch @@ -0,0 +1,43 @@ +From: Michael Chang +Subject: Fix grub2-mkconfig warning when disk is LVM PV +References: bsc#1071239 + +When a disk device was found in grub_util_biosdisk_get_grub_dev, its grub +hostdisk device name just returned. Since the disk could also be used as PV +disk, use grub_util_get_ldm to kick scanning of on disk metadata and adding it +to VG array. + +--- +Index: grub-2.02/util/getroot.c +=================================================================== +--- grub-2.02.orig/util/getroot.c ++++ grub-2.02/util/getroot.c +@@ -272,8 +272,28 @@ grub_util_biosdisk_get_grub_dev (const c + grub_util_info ("%s is a parent of %s", sys_disk, os_dev); + if (!is_part) + { ++#if defined(__APPLE__) + free (sys_disk); + return make_device_name (drive); ++#else ++ char *name, *ldm_name; ++ grub_disk_t disk; ++ ++ free (sys_disk); ++ name = make_device_name (drive); ++ disk = grub_disk_open (name); ++ if (!disk) ++ return name; ++ ldm_name = grub_util_get_ldm (disk, 0); ++ if (ldm_name) ++ { ++ grub_disk_close (disk); ++ grub_free (name); ++ return ldm_name; ++ } ++ grub_disk_close (disk); ++ return name; ++#endif + } + free (sys_disk); + diff --git a/grub2-getroot-support-nvdimm.patch b/grub2-getroot-support-nvdimm.patch new file mode 100644 index 0000000..bd7b6e5 --- /dev/null +++ b/grub2-getroot-support-nvdimm.patch @@ -0,0 +1,71 @@ +From 889c0894d358e48c02f8225426893094f20004e5 Mon Sep 17 00:00:00 2001 +From: Gary Lin +Date: Thu, 4 Oct 2018 10:32:07 +0800 +Subject: [PATCH] linux/getroot: Support NVDIMM device names + +There are two types of NVDIMM block devices in linux: fsdax and blk. +For fsdax, the device name would be /dev/pmemXpY, /dev/pmemXsY, +/dev/pmemX.YpZ, or /dev/pmemX.YsZ. +For blk, the name would be /dev/ndblkX.YpZ or /dev/ndblkX.YsZ +--- + grub-core/osdep/linux/getroot.c | 44 +++++++++++++++++++++++++++++++++ + 1 file changed, 44 insertions(+) + +diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c +index 8776009..d2ab60f 100644 +--- a/grub-core/osdep/linux/getroot.c ++++ b/grub-core/osdep/linux/getroot.c +@@ -1082,6 +1082,50 @@ grub_util_part_to_disk (const char *os_dev, struct stat *st, + *pp = '\0'; + return path; + } ++ ++ /* If this is a NVDIMM device in fsdax mode */ ++ if (strncmp ("pmem", p, 4) == 0 && p[4] >= '0' && p[4] <= '9') ++ { ++ /* /dev/pmem[0-9]+(\.[0-9]+)?((p[0-9]+)?|s[0-9]*) */ ++ char *pp = strchr (p + 4, 'p'); ++ if (pp) ++ { ++ *is_part = 1; ++ *pp = '\0'; ++ } ++ else ++ { ++ pp = strchr (p + 4, 's'); ++ if (pp && pp[1] >= '0' && pp[1] <= '9') ++ { ++ *is_part = 1; ++ pp[1] = '\0'; ++ } ++ } ++ return path; ++ } ++ ++ /* If this is a NVDIMM device in block mode */ ++ if (strncmp ("ndblk", p, 5) == 0 && p[5] >= '0' && p[5] <= '9') ++ { ++ /* /dev/ndblk[0-9]+\.[0-9]+((p[0-9]+)?|s[0-9]*) */ ++ char *pp = strchr (p + 5, 'p'); ++ if (pp) ++ { ++ *is_part = 1; ++ *pp = '\0'; ++ } ++ else ++ { ++ pp = strchr (p + 5, 's'); ++ if (pp && pp[1] >= '0' && pp[1] <= '9') ++ { ++ *is_part = 1; ++ pp[1] = '\0'; ++ } ++ } ++ return path; ++ } + } + + return path; +-- +2.19.0 + diff --git a/grub2-getroot-treat-mdadm-ddf-as-simple-device.patch b/grub2-getroot-treat-mdadm-ddf-as-simple-device.patch new file mode 100644 index 0000000..ec06e18 --- /dev/null +++ b/grub2-getroot-treat-mdadm-ddf-as-simple-device.patch @@ -0,0 +1,68 @@ +From: Michael Chang +Subject: treat mdadm ddf fakeraid as simple device +References: bnc#872360 +Patch-Mainline: no + +Index: grub-2.02~beta2/grub-core/osdep/linux/getroot.c +=================================================================== +--- grub-2.02~beta2.orig/grub-core/osdep/linux/getroot.c ++++ grub-2.02~beta2/grub-core/osdep/linux/getroot.c +@@ -117,7 +117,7 @@ struct btrfs_ioctl_search_args { + struct btrfs_ioctl_fs_info_args) + + static int +-grub_util_is_imsm (const char *os_dev); ++grub_util_is_imsm_or_ddf (const char *os_dev); + + + #define ESCAPED_PATH_MAX (4 * PATH_MAX) +@@ -603,10 +603,10 @@ out: + } + + static int +-grub_util_is_imsm (const char *os_dev) ++grub_util_is_imsm_or_ddf (const char *os_dev) + { + int retry; +- int is_imsm = 0; ++ int is_imsm_or_ddf = 0; + int container_seen = 0; + const char *dev = os_dev; + +@@ -667,10 +667,17 @@ grub_util_is_imsm (const char *os_dev) + if (strncmp (buf, "MD_METADATA=imsm", + sizeof ("MD_METADATA=imsm") - 1) == 0) + { +- is_imsm = 1; ++ is_imsm_or_ddf = 1; + grub_util_info ("%s is imsm", dev); + break; + } ++ if (strncmp (buf, "MD_METADATA=ddf", ++ sizeof ("MD_METADATA=ddf") - 1) == 0) ++ { ++ is_imsm_or_ddf = 1; ++ grub_util_info ("%s is ddf", dev); ++ break; ++ } + } + + free (buf); +@@ -681,7 +688,7 @@ grub_util_is_imsm (const char *os_dev) + + if (dev != os_dev) + free ((void *) dev); +- return is_imsm; ++ return is_imsm_or_ddf; + } + + char * +@@ -1018,7 +1025,7 @@ grub_util_get_dev_abstraction_os (const + + /* Check for RAID. */ + if (!strncmp (os_dev, "/dev/md", 7) && ! grub_util_device_is_mapped (os_dev) +- && !grub_util_is_imsm (os_dev)) ++ && !grub_util_is_imsm_or_ddf (os_dev)) + return GRUB_DEV_ABSTRACTION_RAID; + return GRUB_DEV_ABSTRACTION_NONE; + } diff --git a/grub2-gfxmenu-support-scrolling-menu-entry-s-text.patch b/grub2-gfxmenu-support-scrolling-menu-entry-s-text.patch new file mode 100644 index 0000000..073ffc9 --- /dev/null +++ b/grub2-gfxmenu-support-scrolling-menu-entry-s-text.patch @@ -0,0 +1,283 @@ +From b4c5f80fbfaf912553eca1b12da6fc49de4ae37f Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Mon, 7 Jan 2019 17:55:05 +0800 +Subject: [PATCH] gfxmenu: support scrolling menu entry's text + +If menu entry's title text is longer than its display width, the +overlong text simply get truncated. The only possible way to view the +full text is through the menu editing mode, but is a hassle switching +over the mode back and forth. Also menu editing mode could be password +protected which makes it not generally available to everyone. + +This patch implemented scrolling text support to the title of grub's +gfxmenu to make it convenient for viewing the truncated text by pressing +the ctrl+l and ctrl+r to scroll the highlighted text left and right. The +scrolled result will remain in place to help memorizing it after +changing highlight to other entry. + +V1: + * Use grub_calloc for overflow check and return NULL when it would + occur. +--- + grub-core/gfxmenu/gfxmenu.c | 3 +++ + grub-core/gfxmenu/gui_label.c | 2 ++ + grub-core/gfxmenu/gui_list.c | 38 ++++++++++++++++++++++++++++++++++ + grub-core/gfxmenu/view.c | 48 +++++++++++++++++++++++++++++++++++++++++++ + grub-core/normal/menu.c | 16 +++++++++++++++ + include/grub/gfxmenu_view.h | 4 ++++ + include/grub/menu_viewer.h | 1 + + 7 files changed, 112 insertions(+) + +Index: grub-2.06~rc1/grub-core/gfxmenu/gfxmenu.c +=================================================================== +--- grub-2.06~rc1.orig/grub-core/gfxmenu/gfxmenu.c ++++ grub-2.06~rc1/grub-core/gfxmenu/gfxmenu.c +@@ -108,6 +108,15 @@ grub_gfxmenu_try (int entry, grub_menu_t + view->menu = menu; + view->nested = nested; + view->first_timeout = -1; ++ if (menu->size) ++ { ++ view->menu_title_offset = grub_calloc (menu->size, sizeof (*view->menu_title_offset)); ++ if (!view->menu_title_offset) ++ { ++ grub_free (instance); ++ return grub_errno; ++ } ++ } + + grub_video_set_viewport (0, 0, mode_info.width, mode_info.height); + if (view->double_repaint) +@@ -123,6 +132,7 @@ grub_gfxmenu_try (int entry, grub_menu_t + instance->fini = grub_gfxmenu_viewer_fini; + instance->print_timeout = grub_gfxmenu_print_timeout; + instance->clear_timeout = grub_gfxmenu_clear_timeout; ++ instance->scroll_chosen_entry = grub_gfxmenu_scroll_chosen_entry; + + grub_menu_register_viewer (instance); + +Index: grub-2.06~rc1/grub-core/gfxmenu/gui_label.c +=================================================================== +--- grub-2.06~rc1.orig/grub-core/gfxmenu/gui_label.c ++++ grub-2.06~rc1/grub-core/gfxmenu/gui_label.c +@@ -192,6 +192,8 @@ label_set_property (void *vself, const c + "or `c' for a command-line."); + else if (grub_strcmp (value, "@KEYMAP_SHORT@") == 0) + value = _("enter: boot, `e': options, `c': cmd-line"); ++ else if (grub_strcmp (value, "@SUSE_KEYMAP_SCROLL_ENTRY@") == 0) ++ value = _("ctrl+l: scroll entry left, ctrl+r: scroll entry right"); + /* FIXME: Add more templates here if needed. */ + + if (grub_printf_fmt_check(value, "%d") != GRUB_ERR_NONE) +Index: grub-2.06~rc1/grub-core/gfxmenu/gui_list.c +=================================================================== +--- grub-2.06~rc1.orig/grub-core/gfxmenu/gui_list.c ++++ grub-2.06~rc1/grub-core/gfxmenu/gui_list.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + enum scrollbar_slice_mode { + SCROLLBAR_SLICE_WEST, +@@ -314,6 +315,33 @@ draw_scrollbar (list_impl_t self, + thumb->draw (thumb, thumbx, thumby); + } + ++static const char * ++grub_utf8_offset_code (const char *src, grub_size_t srcsize, int num) ++{ ++ int count = 0; ++ grub_uint32_t code = 0; ++ ++ while (srcsize && num) ++ { ++ if (srcsize != (grub_size_t)-1) ++ srcsize--; ++ if (!grub_utf8_process ((grub_uint8_t)*src++, &code, &count)) ++ return 0; ++ if (count != 0) ++ continue; ++ if (code == 0) ++ return 0; ++ if (code > GRUB_UNICODE_LAST_VALID) ++ return 0; ++ --num; ++ } ++ ++ if (!num) ++ return src; ++ ++ return 0; ++} ++ + /* Draw the list of items. */ + static void + draw_menu (list_impl_t self, int num_shown_items) +@@ -433,6 +461,16 @@ draw_menu (list_impl_t self, int num_sho + const char *item_title = + grub_menu_get_entry (self->view->menu, menu_index)->title; + ++ { ++ int off = self->view->menu_title_offset[menu_index]; ++ const char *scrolled_title; ++ ++ scrolled_title = grub_utf8_offset_code (item_title, grub_strlen (item_title), off); ++ ++ if (scrolled_title) ++ item_title = scrolled_title; ++ } ++ + sviewport.y = item_top + top_pad; + sviewport.width = viewport_width; + grub_gui_set_viewport (&sviewport, &svpsave); +Index: grub-2.06~rc1/grub-core/gfxmenu/view.c +=================================================================== +--- grub-2.06~rc1.orig/grub-core/gfxmenu/view.c ++++ grub-2.06~rc1/grub-core/gfxmenu/view.c +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + + static void + init_terminal (grub_gfxmenu_view_t view); +@@ -103,6 +104,7 @@ grub_gfxmenu_view_new (const char *theme + view->title_text = grub_strdup (_("GRUB Boot Menu")); + view->progress_message_text = 0; + view->theme_path = 0; ++ view->menu_title_offset = 0; + + /* Set the timeout bar's frame. */ + view->progress_message_frame.width = view->screen.width * 4 / 5; +@@ -142,6 +144,7 @@ grub_gfxmenu_view_destroy (grub_gfxmenu_ + grub_free (view->title_text); + grub_free (view->progress_message_text); + grub_free (view->theme_path); ++ grub_free (view->menu_title_offset); + if (view->canvas) + view->canvas->component.ops->destroy (view->canvas); + grub_free (view); +@@ -410,6 +413,52 @@ grub_gfxmenu_set_chosen_entry (int entry + grub_gfxmenu_redraw_menu (view); + } + ++static int ++grub_utf8_get_num_code (const char *src, grub_size_t srcsize) ++{ ++ int count = 0; ++ grub_uint32_t code = 0; ++ int num = 0; ++ ++ while (srcsize) ++ { ++ if (srcsize != (grub_size_t)-1) ++ srcsize--; ++ if (!grub_utf8_process ((grub_uint8_t)*src++, &code, &count)) ++ return 0; ++ if (count != 0) ++ continue; ++ if (code == 0) ++ return num; ++ if (code > GRUB_UNICODE_LAST_VALID) ++ return 0; ++ ++num; ++ } ++ ++ return num; ++} ++ ++void ++grub_gfxmenu_scroll_chosen_entry (void *data, int diren) ++{ ++ grub_gfxmenu_view_t view = data; ++ const char *item_title; ++ int off; ++ ++ if (!view->menu->size) ++ return; ++ ++ item_title =grub_menu_get_entry (view->menu, view->selected)->title; ++ off = view->menu_title_offset[view->selected] + diren; ++ ++ if (off < 0 ++ || off > grub_utf8_get_num_code (item_title, grub_strlen(item_title))) ++ return; ++ ++ view->menu_title_offset[view->selected] = off; ++ grub_gfxmenu_redraw_menu (view); ++} ++ + static void + grub_gfxmenu_draw_terminal_box (void) + { +Index: grub-2.06~rc1/grub-core/normal/menu.c +=================================================================== +--- grub-2.06~rc1.orig/grub-core/normal/menu.c ++++ grub-2.06~rc1/grub-core/normal/menu.c +@@ -400,6 +400,15 @@ menu_set_chosen_entry (int entry) + } + + static void ++menu_scroll_chosen_entry (int diren) ++{ ++ struct grub_menu_viewer *cur; ++ for (cur = viewers; cur; cur = cur->next) ++ if (cur->scroll_chosen_entry) ++ cur->scroll_chosen_entry (cur->data, diren); ++} ++ ++static void + menu_print_timeout (int timeout) + { + struct grub_menu_viewer *cur; +@@ -827,6 +836,13 @@ run_menu (grub_menu_t menu, int nested, + menu_set_chosen_entry (current_entry); + break; + ++ case GRUB_TERM_CTRL | 'l': ++ menu_scroll_chosen_entry (1); ++ break; ++ case GRUB_TERM_CTRL | 'r': ++ menu_scroll_chosen_entry (-1); ++ break; ++ + case '\n': + case '\r': + case GRUB_TERM_KEY_RIGHT: +Index: grub-2.06~rc1/include/grub/gfxmenu_view.h +=================================================================== +--- grub-2.06~rc1.orig/include/grub/gfxmenu_view.h ++++ grub-2.06~rc1/include/grub/gfxmenu_view.h +@@ -61,6 +61,8 @@ void + grub_gfxmenu_print_timeout (int timeout, void *data); + void + grub_gfxmenu_set_chosen_entry (int entry, void *data); ++void ++grub_gfxmenu_scroll_chosen_entry (void *data, int diren); + + grub_err_t grub_font_draw_string (const char *str, + grub_font_t font, +@@ -119,6 +121,8 @@ struct grub_gfxmenu_view + int nested; + + int first_timeout; ++ ++ int *menu_title_offset; + }; + + #endif /* ! GRUB_GFXMENU_VIEW_HEADER */ +Index: grub-2.06~rc1/include/grub/menu_viewer.h +=================================================================== +--- grub-2.06~rc1.orig/include/grub/menu_viewer.h ++++ grub-2.06~rc1/include/grub/menu_viewer.h +@@ -33,6 +33,7 @@ struct grub_menu_viewer + void (*set_chosen_entry) (int entry, void *data); + void (*print_timeout) (int timeout, void *data); + void (*clear_timeout) (void *data); ++ void (*scroll_chosen_entry) (void *data, int diren); + void (*fini) (void *fini); + }; + diff --git a/grub2-grubenv-in-btrfs-header.patch b/grub2-grubenv-in-btrfs-header.patch new file mode 100644 index 0000000..4be1cc9 --- /dev/null +++ b/grub2-grubenv-in-btrfs-header.patch @@ -0,0 +1,504 @@ +GRUB cannot write Btrfs file systems from the bootloader, so it cannot +modify values set from userspace (e.g. "next_entry" set by grub2-once). +As a workaround use the Btrfs header to store known data of the GRUB environment +block. + +v2: export env_block and make sure to use the device of grubenv + +v3: + * Use xcalloc for overflow check and return NULL when it would + occur. + +--- +Index: grub-2.04/grub-core/kern/fs.c +=================================================================== +--- grub-2.04.orig/grub-core/kern/fs.c ++++ grub-2.04/grub-core/kern/fs.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + grub_fs_t grub_fs_list = 0; + +@@ -228,6 +229,13 @@ grub_fs_blocklist_read (grub_file_t file + size, buf) != GRUB_ERR_NONE) + return -1; + ++ if (file->read_hook) ++ { ++ grub_disk_addr_t part_start; ++ ++ part_start = grub_partition_get_start (file->device->disk->partition); ++ file->read_hook (p->offset + sector + part_start, (unsigned)offset, (unsigned)size, file->read_hook_data); ++ } + ret += size; + len -= size; + sector -= ((size + offset) >> GRUB_DISK_SECTOR_BITS); +Index: grub-2.04/util/grub-editenv.c +=================================================================== +--- grub-2.04.orig/util/grub-editenv.c ++++ grub-2.04/util/grub-editenv.c +@@ -23,8 +23,11 @@ + #include + #include + #include +-#include ++#include + #include ++#include ++#include ++#include + + #include + #include +@@ -120,6 +123,140 @@ block, use `rm %s'."), + NULL, help_filter, NULL + }; + ++struct fs_envblk_spec { ++ const char *fs_name; ++ int offset; ++ int size; ++} fs_envblk_spec[] = { ++ { "btrfs", 256 * 1024, GRUB_DISK_SECTOR_SIZE }, ++ { NULL, 0, 0 } ++}; ++ ++struct fs_envblk { ++ struct fs_envblk_spec *spec; ++ const char *dev; ++}; ++ ++typedef struct fs_envblk_spec *fs_envblk_spec_t; ++typedef struct fs_envblk *fs_envblk_t; ++ ++fs_envblk_t fs_envblk = NULL; ++ ++static int ++read_envblk_fs (const char *varname, const char *value, void *hook_data) ++{ ++ grub_envblk_t *p_envblk = (grub_envblk_t *)hook_data; ++ ++ if (!p_envblk || !fs_envblk) ++ return 0; ++ ++ if (strcmp (varname, "env_block") == 0) ++ { ++ int off, sz; ++ char *p; ++ ++ off = strtol (value, &p, 10); ++ if (*p == '+') ++ sz = strtol (p+1, &p, 10); ++ ++ if (*p == '\0') ++ { ++ FILE *fp; ++ char *buf; ++ ++ off <<= GRUB_DISK_SECTOR_BITS; ++ sz <<= GRUB_DISK_SECTOR_BITS; ++ ++ fp = grub_util_fopen (fs_envblk->dev, "rb"); ++ if (! fp) ++ grub_util_error (_("cannot open `%s': %s"), fs_envblk->dev, ++ strerror (errno)); ++ ++ ++ if (fseek (fp, off, SEEK_SET) < 0) ++ grub_util_error (_("cannot seek `%s': %s"), fs_envblk->dev, ++ strerror (errno)); ++ ++ buf = xmalloc (sz); ++ if ((fread (buf, 1, sz, fp)) != sz) ++ grub_util_error (_("cannot read `%s': %s"), fs_envblk->dev, ++ strerror (errno)); ++ ++ fclose (fp); ++ ++ *p_envblk = grub_envblk_open (buf, sz); ++ } ++ } ++ ++ return 0; ++} ++ ++static void ++create_envblk_fs (void) ++{ ++ FILE *fp; ++ char *buf; ++ const char *device; ++ int offset, size; ++ ++ if (!fs_envblk) ++ return; ++ ++ device = fs_envblk->dev; ++ offset = fs_envblk->spec->offset; ++ size = fs_envblk->spec->size; ++ ++ fp = grub_util_fopen (device, "r+b"); ++ if (! fp) ++ grub_util_error (_("cannot open `%s': %s"), device, strerror (errno)); ++ ++ buf = xmalloc (size); ++ memcpy (buf, GRUB_ENVBLK_SIGNATURE, sizeof (GRUB_ENVBLK_SIGNATURE) - 1); ++ memset (buf + sizeof (GRUB_ENVBLK_SIGNATURE) - 1, '#', size - sizeof (GRUB_ENVBLK_SIGNATURE) + 1); ++ ++ if (fseek (fp, offset, SEEK_SET) < 0) ++ grub_util_error (_("cannot seek `%s': %s"), device, strerror (errno)); ++ ++ if (fwrite (buf, 1, size, fp) != size) ++ grub_util_error (_("cannot write to `%s': %s"), device, strerror (errno)); ++ ++ grub_util_file_sync (fp); ++ free (buf); ++ fclose (fp); ++} ++ ++static grub_envblk_t ++open_envblk_fs (grub_envblk_t envblk) ++{ ++ grub_envblk_t envblk_fs = NULL; ++ char *val; ++ int offset, size; ++ ++ if (!fs_envblk) ++ return NULL; ++ ++ offset = fs_envblk->spec->offset; ++ size = fs_envblk->spec->size; ++ ++ grub_envblk_iterate (envblk, &envblk_fs, read_envblk_fs); ++ ++ if (envblk_fs && grub_envblk_size (envblk_fs) == size) ++ return envblk_fs; ++ ++ create_envblk_fs (); ++ ++ offset = offset >> GRUB_DISK_SECTOR_BITS; ++ size = (size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS; ++ ++ val = xasprintf ("%d+%d", offset, size); ++ if (! grub_envblk_set (envblk, "env_block", val)) ++ grub_util_error ("%s", _("environment block too small")); ++ grub_envblk_iterate (envblk, &envblk_fs, read_envblk_fs); ++ free (val); ++ ++ return envblk_fs; ++} ++ + static grub_envblk_t + open_envblk_file (const char *name) + { +@@ -176,10 +313,17 @@ static void + list_variables (const char *name) + { + grub_envblk_t envblk; ++ grub_envblk_t envblk_fs = NULL; + + envblk = open_envblk_file (name); ++ grub_envblk_iterate (envblk, &envblk_fs, read_envblk_fs); + grub_envblk_iterate (envblk, NULL, print_var); + grub_envblk_close (envblk); ++ if (envblk_fs) ++ { ++ grub_envblk_iterate (envblk_fs, NULL, print_var); ++ grub_envblk_close (envblk_fs); ++ } + } + + static void +@@ -203,6 +347,38 @@ write_envblk (const char *name, grub_env + } + + static void ++write_envblk_fs (grub_envblk_t envblk) ++{ ++ FILE *fp; ++ const char *device; ++ int offset, size; ++ ++ if (!fs_envblk) ++ return; ++ ++ device = fs_envblk->dev; ++ offset = fs_envblk->spec->offset; ++ size = fs_envblk->spec->size; ++ ++ if (grub_envblk_size (envblk) > size) ++ grub_util_error ("%s", _("environment block too small")); ++ ++ fp = grub_util_fopen (device, "r+b"); ++ ++ if (! fp) ++ grub_util_error (_("cannot open `%s': %s"), device, strerror (errno)); ++ ++ if (fseek (fp, offset, SEEK_SET) < 0) ++ grub_util_error (_("cannot seek `%s': %s"), device, strerror (errno)); ++ ++ if (fwrite (grub_envblk_buffer (envblk), 1, grub_envblk_size (envblk), fp) != grub_envblk_size (envblk)) ++ grub_util_error (_("cannot write to `%s': %s"), device, strerror (errno)); ++ ++ grub_util_file_sync (fp); ++ fclose (fp); ++} ++ ++static void + set_variables (const char *name, int argc, char *argv[]) + { + grub_envblk_t envblk; +@@ -218,8 +394,27 @@ set_variables (const char *name, int arg + + *(p++) = 0; + +- if (! grub_envblk_set (envblk, argv[0], p)) +- grub_util_error ("%s", _("environment block too small")); ++ if ((strcmp (argv[0], "next_entry") == 0 || ++ strcmp (argv[0], "health_checker_flag") == 0) && fs_envblk) ++ { ++ grub_envblk_t envblk_fs; ++ envblk_fs = open_envblk_fs (envblk); ++ if (!envblk_fs) ++ grub_util_error ("%s", _("can't open fs environment block")); ++ if (! grub_envblk_set (envblk_fs, argv[0], p)) ++ grub_util_error ("%s", _("environment block too small")); ++ write_envblk_fs (envblk_fs); ++ grub_envblk_close (envblk_fs); ++ } ++ else if (strcmp (argv[0], "env_block") == 0) ++ { ++ grub_util_warn ("can't set env_block as it's read-only"); ++ } ++ else ++ { ++ if (! grub_envblk_set (envblk, argv[0], p)) ++ grub_util_error ("%s", _("environment block too small")); ++ } + + argc--; + argv++; +@@ -227,26 +422,158 @@ set_variables (const char *name, int arg + + write_envblk (name, envblk); + grub_envblk_close (envblk); ++ + } + + static void + unset_variables (const char *name, int argc, char *argv[]) + { + grub_envblk_t envblk; ++ grub_envblk_t envblk_fs; + + envblk = open_envblk_file (name); ++ ++ envblk_fs = NULL; ++ if (fs_envblk) ++ envblk_fs = open_envblk_fs (envblk); ++ + while (argc) + { + grub_envblk_delete (envblk, argv[0]); + ++ if (envblk_fs) ++ grub_envblk_delete (envblk_fs, argv[0]); ++ + argc--; + argv++; + } + + write_envblk (name, envblk); + grub_envblk_close (envblk); ++ ++ if (envblk_fs) ++ { ++ write_envblk_fs (envblk_fs); ++ grub_envblk_close (envblk_fs); ++ } ++} ++ ++int have_abstraction = 0; ++static void ++probe_abstraction (grub_disk_t disk) ++{ ++ if (disk->partition == NULL) ++ grub_util_info ("no partition map found for %s", disk->name); ++ ++ if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID || ++ disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID) ++ { ++ have_abstraction = 1; ++ } + } + ++static fs_envblk_t ++probe_fs_envblk (fs_envblk_spec_t spec) ++{ ++ char **grub_devices; ++ char **curdev, **curdrive; ++ size_t ndev = 0; ++ char **grub_drives; ++ grub_device_t grub_dev = NULL; ++ grub_fs_t grub_fs; ++ const char *fs_envblk_device; ++ ++#ifdef __s390x__ ++ return NULL; ++#endif ++ ++ grub_util_biosdisk_init (DEFAULT_DEVICE_MAP); ++ grub_init_all (); ++ grub_gcry_init_all (); ++ ++ grub_lvm_fini (); ++ grub_mdraid09_fini (); ++ grub_mdraid1x_fini (); ++ grub_diskfilter_fini (); ++ grub_diskfilter_init (); ++ grub_mdraid09_init (); ++ grub_mdraid1x_init (); ++ grub_lvm_init (); ++ ++ grub_devices = grub_guess_root_devices (DEFAULT_DIRECTORY); ++ ++ if (!grub_devices || !grub_devices[0]) ++ grub_util_error (_("cannot find a device for %s (is /dev mounted?)"), DEFAULT_DIRECTORY); ++ ++ fs_envblk_device = grub_devices[0]; ++ ++ for (curdev = grub_devices; *curdev; curdev++) ++ { ++ grub_util_pull_device (*curdev); ++ ndev++; ++ } ++ ++ grub_drives = xcalloc ((ndev + 1), sizeof (grub_drives[0])); ++ ++ for (curdev = grub_devices, curdrive = grub_drives; *curdev; curdev++, ++ curdrive++) ++ { ++ *curdrive = grub_util_get_grub_dev (*curdev); ++ if (! *curdrive) ++ grub_util_error (_("cannot find a GRUB drive for %s. Check your device.map"), ++ *curdev); ++ } ++ *curdrive = 0; ++ ++ grub_dev = grub_device_open (grub_drives[0]); ++ if (! grub_dev) ++ grub_util_error ("%s", grub_errmsg); ++ ++ grub_fs = grub_fs_probe (grub_dev); ++ if (! grub_fs) ++ grub_util_error ("%s", grub_errmsg); ++ ++ if (grub_dev->disk) ++ { ++ probe_abstraction (grub_dev->disk); ++ } ++ for (curdrive = grub_drives + 1; *curdrive; curdrive++) ++ { ++ grub_device_t dev = grub_device_open (*curdrive); ++ if (!dev) ++ continue; ++ if (dev->disk) ++ probe_abstraction (dev->disk); ++ grub_device_close (dev); ++ } ++ ++ free (grub_drives); ++ grub_device_close (grub_dev); ++ grub_gcry_fini_all (); ++ grub_fini_all (); ++ grub_util_biosdisk_fini (); ++ ++ fs_envblk_spec_t p; ++ ++ for (p = spec; p->fs_name; p++) ++ { ++ if (strcmp (grub_fs->name, p->fs_name) == 0 && !have_abstraction) ++ { ++ if (p->offset % GRUB_DISK_SECTOR_SIZE == 0 && ++ p->size % GRUB_DISK_SECTOR_SIZE == 0) ++ { ++ fs_envblk = xmalloc (sizeof (fs_envblk_t)); ++ fs_envblk->spec = p; ++ fs_envblk->dev = strdup(fs_envblk_device); ++ return fs_envblk; ++ } ++ } ++ } ++ ++ return NULL; ++} ++ ++ + int + main (int argc, char *argv[]) + { +@@ -278,6 +605,9 @@ main (int argc, char *argv[]) + command = argv[curindex++]; + } + ++ if (strcmp (filename, DEFAULT_ENVBLK_PATH) == 0) ++ fs_envblk = probe_fs_envblk (fs_envblk_spec); ++ + if (strcmp (command, "create") == 0) + grub_util_create_envblk_file (filename); + else if (strcmp (command, "list") == 0) +Index: grub-2.04/util/grub.d/00_header.in +=================================================================== +--- grub-2.04.orig/util/grub.d/00_header.in ++++ grub-2.04/util/grub.d/00_header.in +@@ -46,6 +46,13 @@ cat << EOF + if [ -s \$prefix/grubenv ]; then + load_env + fi ++ ++if [ "\${env_block}" ] ; then ++ set env_block="(\${root})\${env_block}" ++ export env_block ++ load_env -f "\${env_block}" ++fi ++ + EOF + if [ "x$GRUB_BUTTON_CMOS_ADDRESS" != "x" ]; then + cat < +Subject: Makefile.am: makes sure that ext2/3/4 is tried before minix +References: boo#1161641 + +I recently came across a strange grub2-install error when building kiwi images +in OBS. The reason is a bug in the minix file system detection. I filed +upstream bug [1]. + +Note I experienced this on SLES15-SP1. The bug is still present in current +Tumbleweed [2]. This bug thus needs fixing in all supported openSUSE releases. + +The reproducer-script is called as root like + + bash ./grub-bug-57652-reproduce-suse.sh /tmp/grub-test.img /mnt + +/tmp needs 1GB of free storage to store the image. + +Maybe this would be good enough as a minimal-intrusive fix. It does not fix the +minix detection code, but instead makes sure that ext[234] is tried before +minix. + +[1] https://savannah.gnu.org/bugs/index.php?57652 +[2] https://bugzilla.opensuse.org/attachment.cgi?id=828118 + +Index: grub-2.04/Makefile.am +=================================================================== +--- grub-2.04.orig/Makefile.am ++++ grub-2.04/Makefile.am +@@ -42,8 +42,11 @@ libgrub.pp: grub_script.tab.h grub_scrip + -D'GRUB_MOD_INIT(x)=@MARKER@x@' $^ > $@ || (rm -f $@; exit 1) + CLEANFILES += libgrub.pp + ++# the grep/sed ensures that ext2 gets initialized before minix* ++# see https://savannah.gnu.org/bugs/?57652 + libgrub_a_init.lst: libgrub.pp + cat $< | grep '@MARKER@' | sed 's/@MARKER@\(.*\)@/\1/g' | sort -u > $@ || (rm -f $@; exit 1) ++ if grep ^ext2 $@ >/dev/null; then sed '/ext2/d;/newc/iext2' < $@ > $@.tmp && mv $@.tmp $@; fi + CLEANFILES += libgrub_a_init.lst + + libgrub_a_init.c: libgrub_a_init.lst $(top_srcdir)/geninit.sh diff --git a/grub2-install-remove-useless-check-PReP-partition-is-empty.patch b/grub2-install-remove-useless-check-PReP-partition-is-empty.patch new file mode 100644 index 0000000..e2f9c20 --- /dev/null +++ b/grub2-install-remove-useless-check-PReP-partition-is-empty.patch @@ -0,0 +1,76 @@ +From b57af595c94db6d7babb7623c1530ee4f5b956f0 Mon Sep 17 00:00:00 2001 +From: Michal Suchanek +Date: Tue, 31 Oct 2017 14:28:54 +0100 +Subject: [PATCH] grub-install: remove useless check PReP partition is empty. + +References: bsc#1065738 + +The grub-install rewrite in commit cd46aa6cefab checks that the PPeP +partition does not install an ELF binary before writing grub to it. This +causes regression in installer scripts that expect to be able to +reinstall bootloaders without first witping the partition by hand. + +Fixes: cd46aa6cefab ("Rewrite grub-install, grub-mkrescue, + grub-mkstandalone and grub-mknetdir ") +--- + util/grub-install.c | 39 ++------------------------------------- + 1 file changed, 2 insertions(+), 37 deletions(-) + +Index: grub-2.06~rc1/util/grub-install.c +=================================================================== +--- grub-2.06~rc1.orig/util/grub-install.c ++++ grub-2.06~rc1/util/grub-install.c +@@ -756,34 +756,6 @@ is_prep_partition (grub_device_t dev) + return 0; + } + +-static int +-is_prep_empty (grub_device_t dev) +-{ +- grub_disk_addr_t dsize, addr; +- grub_uint32_t buffer[32768]; +- +- dsize = grub_disk_native_sectors (dev->disk); +- for (addr = 0; addr < dsize; +- addr += sizeof (buffer) / GRUB_DISK_SECTOR_SIZE) +- { +- grub_size_t sz = sizeof (buffer); +- grub_uint32_t *ptr; +- +- if (sizeof (buffer) / GRUB_DISK_SECTOR_SIZE > dsize - addr) +- sz = (dsize - addr) * GRUB_DISK_SECTOR_SIZE; +- grub_disk_read (dev->disk, addr, 0, sz, buffer); +- +- if (addr == 0 && grub_memcmp (buffer, ELFMAG, SELFMAG) == 0) +- return 1; +- +- for (ptr = buffer; ptr < buffer + sz / sizeof (*buffer); ptr++) +- if (*ptr) +- return 0; +- } +- +- return 1; +-} +- + static void + bless (grub_device_t dev, const char *path, int x86) + { +@@ -1923,16 +1895,9 @@ main (int argc, char *argv[]) + { + grub_util_error ("%s", _("the chosen partition is not a PReP partition")); + } +- if (is_prep_empty (ins_dev)) +- { +- if (write_to_disk (ins_dev, imgfile)) +- grub_util_error ("%s", _("failed to copy Grub to the PReP partition")); +- } +- else ++ if (write_to_disk (ins_dev, imgfile)) + { +- char *s = xasprintf ("dd if=/dev/zero of=%s", install_device); +- grub_util_error (_("the PReP partition is not empty. If you are sure you want to use it, run dd to clear it: `%s'"), +- s); ++ grub_util_error ("%s", _("failed to copy Grub to the PReP partition")); + } + grub_device_close (ins_dev); + if (update_nvram) diff --git a/grub2-instdev-fixup.pl b/grub2-instdev-fixup.pl new file mode 100644 index 0000000..411a0d9 --- /dev/null +++ b/grub2-instdev-fixup.pl @@ -0,0 +1,336 @@ +#!/usr/bin/perl + +use strict; +use integer; +use bytes; +eval 'use File::Copy qw(copy move)'; +eval 'use File::Temp qw(mkstemp mktemp)'; +eval 'use POSIX qw(uname)'; +eval 'use Cwd qw(realpath)'; + +my $device; +my $diskboot; +my $instdev; +my $diskboot_start; +my $default_backup; +my $default = "/etc/default/grub_installdevice"; +my $debug = 0; + +$debug = 1 if ($ARGV[0] =~ m/^(--debug|-d)$/); + +sub is_part ($) { + my ($dev) = @_; + my $ret; + + $dev = realpath($dev); + if ($dev =~ qr{/dev/(.+)}) { + $ret = 1 if (-e "/sys/class/block/$1/partition"); + } + $ret; +} + +sub is_abstraction ($) { + my ($path) = @_; + my @abs; + + chomp( @abs = qx{grub2-probe --target=abstraction $path} ); + die "Failed to probe $path for target abstraction\n" if ($? != 0); + @abs; +} + +sub default_installdevice () { + my $ret; + + if ( -w $default ) { + open( IN, "< $default") || return; + while ( ) { + chomp; + (m{^/dev}) && ($ret = $_, last); + } + close ( IN ); + } + $ret; +} + +sub new_installdevice ($) { + my ($dev) = @_; + my $cfg; + + die unless (open( IN, "< $default")); + + while ( ) { + if (m{^/dev}) { + $cfg .= "${dev}\n"; + } else { + $cfg .= $_; + } + } + close ( IN ); + + my ($out, $newf) = mkstemp('/tmp/grub.installdevice.XXXXX'); + die unless (print ( $out $cfg)); + close ( $out ); + + $default_backup = mktemp("${default}.old.XXXXX"); + copy($default, $default_backup); + move($newf, $default); +} + +sub is_grub_drive ($$$) { + my ( $prefix, $path, $isdev ) = @_; + my $tgt; + my ($td, $tp); + my ($pd, $pp); + my $pattern = qr{\((hd[0-9]+)?,?((?:gpt|msdos)[0-9]+)?\)}; + + if ($isdev) { + chomp( $tgt = qx{grub2-probe --target=drive -d $path} ); + } else { + chomp( $tgt = qx{grub2-probe --target=drive $path} ); + } + + die "Failed to probe $path for target drive\n" if ($? != 0); + ( $tgt =~ $pattern ) && (($td, $tp) = ($1, $2)) || return ; + ( $prefix =~ $pattern ) && (($pd, $pp) = ($1, $2)) || return ; + return if ($pd && $pd ne $td); + return 1 unless ($tp); + ($pp eq $tp) ? 1 : 0; +} + +sub embed_part_start ($){ + my ($dev) = @_; + my @blk; + my $ret; + + chomp (@blk = qx{lsblk --list --ascii --noheadings --output PATH,PTTYPE,PARTTYPE $dev}); + die "Failed to get block device information for $dev\n" if ($? != 0); + foreach (@blk) { + my ($path, $pttype, $parttype) = split /\s+/; + if ($pttype eq 'dos') { + $ret = 1; + last; + } elsif ($pttype eq 'gpt' && $parttype eq '21686148-6449-6e6f-744e-656564454649') { + if ($path =~ qr{/dev/(.+)}) { + if ( -r "/sys/class/block/$1/start" ) { + chomp ($ret = qx{cat /sys/class/block/$1/start}); + last; + } + } + } + } + + $ret; +} + +sub check_mbr ($) { + my ($dev) = @_; + my $devh; + my $mbr; + + open( $devh, "< $dev" ) or die "$0: cannot open $dev: $!\n"; + sysread( $devh, $mbr, 512 ) == 512 or die "$0: $dev: read error\n"; + close( $devh ); + my( $magic ) = unpack('H4', $mbr); + return if ($magic ne 'eb63'); + + my( $version ) = unpack('x128H4', $mbr); + return if ($version ne '0020'); + + my( $sector_nr ) = unpack('x92L<', $mbr); + return if ($sector_nr ne embed_part_start($dev)); + + my( $drive_nr ) = unpack('x100H2', $mbr); + return if ($drive_nr ne 'ff'); + + $sector_nr; +} + +sub check_diskboot ($$) { + my ($dev, $sector_nr) = @_; + my $devh; + my $diskboot; + my @ret; + + open($devh, "< $dev" ) or die "$0: cannot open $dev: $!\n"; + # print "looks at sector $sector_nr of the same hard drive for core.img\n"; + sysseek($devh, $sector_nr*512, 0) or die "$0: $dev: $!\n"; + # grub-core/boot/i386/pc/diskboot.S + sysread($devh, $diskboot, 512 ) == 512 or die "$0: $dev: read error\n"; + close($devh); + + my( $magic ) = unpack('H8', $diskboot); + # print $magic , "\n"; + + # 5256be1b - upstream diskboot.S + # 5256be63 - trustedgrub2 1.4 + # 5256be56 - diskboot.S with mjg TPM patches (e.g. in openSUSE Tumbleweed) + return if ($magic !~ m/(5256be1b|5256be63|5256be56)/); + + for (1..3) { + my $nr; + my $s = 512 - 12 * $_; + my( $nr_low, $nr_high, $size ) = unpack("x${s}L 8192) ? 8192 : $size; + # Find the last 6 bytes of lzma_decode to find the offset of the lzma_stream: + $off = index( unpack( "H".($r<<1), $core ), 'd1e9dffeffff' ); + if ($off != -1) { + $off >>= 1; + $off += 8; + $off = (($off + 0b1111) >> 4) << 4; + } +} + +sub decomp_lzma ($$) { + my ($core, $off) = @_; + my $comp_size; + my $decomp_size; + my $lzma; + my $lzmah; + my $unlzma; + + # grub-core/boot/i386/pc/startup_raw.S + my $tmpf = "/tmp/lzma_grub.lzma"; + ($comp_size, $decomp_size) = unpack ("x8VV", $core); + $lzma = pack( "CVVx4", 0x5d, 0x00010000, $decomp_size ); + $lzma .= substr( $core, $off, $comp_size ); + + open($lzmah, "> $tmpf") or die "$0: cannot open $tmpf : $!\n"; + binmode $lzmah; + print $lzmah $lzma; + close($lzmah); + + $unlzma = qx{lzcat $tmpf}; + die if ($? != 0); + die "decompressed size mismatch\n" if (length($unlzma) != $decomp_size); + + ($unlzma, $decomp_size); +} + +sub search_prefix (@) { + my ($unlzma, $decomp_size) = @_; + + my ($mod_base) = unpack("x19V", $unlzma); + my ($mod_magic, $mod_off, $mod_sz) = unpack("x$mod_base A4 L< L<", $unlzma); + die "module magic mismatch\n" if ( $mod_magic ne "mimg" ); + die "module out of bound" if ($mod_base + $mod_sz > $decomp_size); + my $mod_start = $mod_base + $mod_off; + my $mod_end = $mod_base + $mod_sz; + my $embed; + my $prefix; + while ($mod_start < ($mod_end - 8)) { + my ($type, $sz) = unpack("x${mod_start} L< L<", $unlzma); + last if ($mod_start + $sz > $mod_end); + last if ($sz < 8); + if ($type == 2) { + ($embed) = unpack(join('', 'x', $mod_start + 8, 'A', $sz - 8), $unlzma); + } elsif ($type == 3) { + ($prefix) = unpack(join('', 'x', $mod_start + 8, 'A', $sz - 8), $unlzma); + } + $sz = (($sz + 0b11) >> 2) << 2; + $mod_start += $sz; + } + + $prefix; +} + +sub part_to_disk ($) { + my ($dev) = @_; + my $ret; + + if ($dev =~ m{/dev/disk/by-uuid/}) { + $dev = realpath($dev); + } + + my @regexp = ( + qr{(/dev/disk/(?:by-id|by-path)/.+)-part[0-9]+}, + qr{(/dev/[a-z]+d[a-z])[0-9]+}, + qr{(/dev/nvme[0-9]+n[0-9]+)p[0-9]+} + ); + + foreach (@regexp) { + if ($dev =~ $_) { + $ret = $1; + last; + } + } + + $ret; +} + +sub get_prefix ($@) { + my ($dev, ($sector_nr, $size)) = @_; + my $devh; + my $core; + my $off; + my $prefix; + + $size <<= 9; + $sector_nr <<= 9; + + open( $devh, "< $dev" ) or die "$0: cannot open $dev: $!\n"; + sysseek( $devh, $sector_nr, 0) or die "$0: $dev: $!\n"; + sysread( $devh, $core, $size ) == $size or die "$0: $dev: read error\n"; + close( $devh ); + + $off = lzma_start($core, $size); + return if ($off == -1); + + $prefix = search_prefix( decomp_lzma($core, $off) ); +} + +eval { + +my @uname = uname(); +die "machine hardware is not x86_64\n" if ($uname[4] ne 'x86_64'); + +die "no install device config or no permission to alter it\n" unless ($instdev = default_installdevice()); +die "/boot is abstraction\n" if (is_abstraction("/boot")); +die "$instdev is NOT partition\n" unless (is_part($instdev)); + +chomp ( $device = qx{grub2-probe --target=disk /boot} ); +die "no disk for /boot\n" unless ( $device ); + +my $sector_nr = check_mbr($device); + +die "$device mbr is not used for suse grub embedding\n" unless ($sector_nr); + +my @core_sectors = check_diskboot($device, $sector_nr); + +die "core image is not single continuous chunk\n" if (@core_sectors != 2); + +die "starting sector of startup_raw $core_sectors[0]" . +" did not follow diskboot $sector_nr\n" if ($core_sectors[0] != $sector_nr + 1); + +my $prefix = get_prefix($device, @core_sectors); + +die "$prefix is not pointing to /boot" unless ($prefix && is_grub_drive ($prefix, '/boot', 0)); + +my $instdisk = part_to_disk($instdev); + +die "cannot determine disk device for $instdev" unless ($instdisk); +die "$instdisk is not grub disk" unless (is_grub_drive($prefix, $instdisk, 1)); + +new_installdevice($instdisk); + +print "The system has been detected using grub in master boot record for booting this updated system with \$prefix=$prefix. However the $default has the install device set to the partition, $instdev. To avoid potential breakage in the application binary interface between grub image and modules, the install device of grub has been changed to use the disk device, $instdisk, to update the master boot record with new grub in order to keep up with the new binary.\n"; + +print "The backup of the original file is $default_backup\n"; + +}; + +print "No fixup required: $@" if ($debug && $@); diff --git a/grub2-iterate-and-hook-for-extended-partition.patch b/grub2-iterate-and-hook-for-extended-partition.patch new file mode 100644 index 0000000..73170c0 --- /dev/null +++ b/grub2-iterate-and-hook-for-extended-partition.patch @@ -0,0 +1,48 @@ +From: Michael Chang + +The same as in the previous patch, add a support for installing grub +into an extended partition. + +Here, we do not ignore extended partitions anymore. Instead we call a +hook that makes sure we have the partition when installing. + +Signed-off-by: Jiri Slaby +References: https://bugzilla.novell.com/show_bug.cgi?id=750897 + +From: Andrey Borzenkov + +Apply this logic only to primary extended partition. Ignore extended +partitions that are used to link together logical partitions. + +References: https://bugzilla.novell.com/show_bug.cgi?id=785341 +--- +Index: grub-2.00/grub-core/partmap/msdos.c +=================================================================== +--- grub-2.00.orig/grub-core/partmap/msdos.c ++++ grub-2.00/grub-core/partmap/msdos.c +@@ -188,13 +188,20 @@ grub_partition_msdos_iterate (grub_disk_ + (unsigned long long) p.len); + + /* If this partition is a normal one, call the hook. */ +- if (! grub_msdos_partition_is_empty (e->type) +- && ! grub_msdos_partition_is_extended (e->type)) ++ if (! grub_msdos_partition_is_empty (e->type)) + { +- p.number++; ++ if (!grub_msdos_partition_is_extended (e->type) || p.number < 3) ++ { ++ p.number++; + +- if (hook (disk, &p, hook_data)) +- return grub_errno; ++ /* prevent someone doing mkfs or mkswap on an ++ extended partition, but leave room for LILO */ ++ if (grub_msdos_partition_is_extended (e->type)) ++ p.len = 2; ++ ++ if (hook (disk, &p, hook_data)) ++ return grub_errno; ++ } + } + else if (p.number < 3) + /* If this partition is a logical one, shouldn't increase the diff --git a/grub2-linguas.sh-no-rsync.patch b/grub2-linguas.sh-no-rsync.patch new file mode 100644 index 0000000..e63fe10 --- /dev/null +++ b/grub2-linguas.sh-no-rsync.patch @@ -0,0 +1,21 @@ +From: Andrey Borzenkov +Subject: disable rsync to make it possible to use in RPM build + +We need to create po/LINGUAS to generate message catalogs. Use +linguas.sh to ensure we always use the same rules as upstream, but +disable rsync. +Index: grub-2.02~rc2/linguas.sh +=================================================================== +--- grub-2.02~rc2.orig/linguas.sh ++++ grub-2.02~rc2/linguas.sh +@@ -1,8 +1,8 @@ + #!/bin/sh + +-rsync -Lrtvz translationproject.org::tp/latest/grub/ po ++#rsync -Lrtvz translationproject.org::tp/latest/grub/ po + +-autogenerated="en@quot en@hebrew de@hebrew en@cyrillic en@greek en@arabic en@piglatin de_CH" ++autogenerated="en@quot" # en@hebrew de@hebrew en@cyrillic en@greek en@arabic en@piglatin de_CH" + + + for x in $autogenerated; do diff --git a/grub2-linux.patch b/grub2-linux.patch new file mode 100644 index 0000000..b123700 --- /dev/null +++ b/grub2-linux.patch @@ -0,0 +1,44 @@ +Index: grub-2.04rc1/util/grub.d/10_linux.in +=================================================================== +--- grub-2.04rc1.orig/util/grub.d/10_linux.in ++++ grub-2.04rc1/util/grub.d/10_linux.in +@@ -31,7 +31,7 @@ CLASS="--class gnu-linux --class gnu --c + if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then + OS=GNU/Linux + else +- OS="${GRUB_DISTRIBUTOR} GNU/Linux" ++ OS="${GRUB_DISTRIBUTOR}" + CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1|LC_ALL=C sed 's,[^[:alnum:]_],_,g') ${CLASS}" + fi + +@@ -141,7 +141,7 @@ linux_entry () + message="$(gettext_printf "Loading Linux %s ..." ${version})" + sed "s/^/$submenu_indentation/" << EOF + echo '$(echo "$message" | grub_quote)' +- linux ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args} ++ linux ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ${args} + EOF + if test -n "${initrd}" ; then + # TRANSLATORS: ramdisk isn't identifier. Should be translated. +Index: grub-2.04rc1/util/grub.d/20_linux_xen.in +=================================================================== +--- grub-2.04rc1.orig/util/grub.d/20_linux_xen.in ++++ grub-2.04rc1/util/grub.d/20_linux_xen.in +@@ -31,7 +31,7 @@ CLASS="--class gnu-linux --class gnu --c + if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then + OS=GNU/Linux + else +- OS="${GRUB_DISTRIBUTOR} GNU/Linux" ++ OS="${GRUB_DISTRIBUTOR}" + CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1|LC_ALL=C sed 's,[^[:alnum:]_],_,g') ${CLASS}" + fi + +@@ -134,7 +134,7 @@ linux_entry () + fi + ${xen_loader} ${rel_xen_dirname}/${xen_basename} placeholder ${xen_args} \${xen_rm_opts} + echo '$(echo "$lmessage" | grub_quote)' +- ${module_loader} ${rel_dirname}/${basename} placeholder root=${linux_root_device_thisversion} ro ${args} ++ ${module_loader} ${rel_dirname}/${basename} placeholder root=${linux_root_device_thisversion} ${args} + EOF + if test -n "${initrd}" ; then + # TRANSLATORS: ramdisk isn't identifier. Should be translated. diff --git a/grub2-linuxefi-fix-boot-params.patch b/grub2-linuxefi-fix-boot-params.patch new file mode 100644 index 0000000..f49b6a2 --- /dev/null +++ b/grub2-linuxefi-fix-boot-params.patch @@ -0,0 +1,20 @@ +Index: grub-2.02~rc1/grub-core/loader/i386/efi/linux.c +=================================================================== +--- grub-2.02~rc1.orig/grub-core/loader/i386/efi/linux.c ++++ grub-2.02~rc1/grub-core/loader/i386/efi/linux.c +@@ -324,7 +324,14 @@ grub_cmd_linux (grub_command_t cmd __att + lh.code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem; + } + +- grub_memcpy(params, &lh, 2 * 512); ++ /* Grub linuxefi erroneously initialize linux's boot_params with non-zero values. (bsc#1025563) ++ ++ From https://www.kernel.org/doc/Documentation/x86/boot.txt: ++ The memory for struct boot_params could be allocated anywhere (even above 4G) ++ and initialized to all zero. ++ Then, the setup header at offset 0x01f1 of kernel image on should be ++ loaded into struct boot_params and examined. */ ++ grub_memcpy (¶ms->setup_sects, &lh.setup_sects, sizeof (lh) - 0x01f1); + + params->type_of_loader = 0x21; + diff --git a/grub2-lvm-allocate-metadata-buffer-from-raw-contents.patch b/grub2-lvm-allocate-metadata-buffer-from-raw-contents.patch new file mode 100644 index 0000000..f78bb76 --- /dev/null +++ b/grub2-lvm-allocate-metadata-buffer-from-raw-contents.patch @@ -0,0 +1,148 @@ +From: Michael Chang +Date: Fri, 9 Apr 2021 19:58:24 +0800 +Subject: [PATCH] Allocate LVM metadata buffer from raw contents + +The size reserved for on disk LVM metadata area can be exceedingly large that +may trigger out of memory error for allocating buffer based on it. Refine the +buffer allocation to use size of raw LVM metadata contents and read them from +within the metadata area as we only need to parse the JSON formatted contents +rather than the entire metadata area. This reduced the size significantly and +the likelihood to out of memory error. +--- + grub-core/disk/lvm.c | 79 ++++++++++++++++++++++++-------------------- + 1 file changed, 43 insertions(+), 36 deletions(-) + +diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c +index 8257159b3..1d1a3dcad 100644 +--- a/grub-core/disk/lvm.c ++++ b/grub-core/disk/lvm.c +@@ -140,9 +140,11 @@ grub_lvm_detect (grub_disk_t disk, + grub_err_t err; + grub_uint64_t mda_offset, mda_size; + grub_size_t ptr; ++ grub_uint64_t mda_raw_offset, mda_raw_size; + char buf[GRUB_LVM_LABEL_SIZE]; + char vg_id[GRUB_LVM_ID_STRLEN+1]; + char pv_id[GRUB_LVM_ID_STRLEN+1]; ++ char mdah_buf[sizeof (struct grub_lvm_mda_header) + sizeof (struct grub_lvm_raw_locn)]; + char *metadatabuf, *mda_end, *vgname; + const char *p, *q; + struct grub_lvm_label_header *lh = (struct grub_lvm_label_header *) buf; +@@ -220,21 +222,15 @@ grub_lvm_detect (grub_disk_t disk, + + dlocn++; + mda_offset = grub_le_to_cpu64 (dlocn->offset); +- mda_size = grub_le_to_cpu64 (dlocn->size); + + /* It's possible to have multiple copies of metadata areas, we just use the + first one. */ +- +- /* Allocate buffer space for the circular worst-case scenario. */ +- metadatabuf = grub_calloc (2, mda_size); +- if (! metadatabuf) ++ err = grub_disk_read (disk, 0, mda_offset, sizeof (mdah_buf), mdah_buf); ++ if (err) + goto fail; + +- err = grub_disk_read (disk, 0, mda_offset, mda_size, metadatabuf); +- if (err) +- goto fail2; ++ mdah = (struct grub_lvm_mda_header *) mdah_buf; + +- mdah = (struct grub_lvm_mda_header *) metadatabuf; + if ((grub_strncmp ((char *)mdah->magic, GRUB_LVM_FMTT_MAGIC, + sizeof (mdah->magic))) + || (grub_le_to_cpu32 (mdah->version) != GRUB_LVM_FMTT_VERSION)) +@@ -244,42 +240,58 @@ grub_lvm_detect (grub_disk_t disk, + #ifdef GRUB_UTIL + grub_util_info ("unknown LVM metadata header"); + #endif +- goto fail2; ++ goto fail; + } + + rlocn = mdah->raw_locns; +- if (grub_le_to_cpu64 (rlocn->offset) >= grub_le_to_cpu64 (mda_size)) ++ ++ mda_size = grub_le_to_cpu64 (mdah->size); ++ mda_raw_size = grub_le_to_cpu64 (rlocn->size); ++ mda_raw_offset = grub_le_to_cpu64 (rlocn->offset); ++ ++ if (mda_raw_offset >= mda_size) + { + #ifdef GRUB_UTIL + grub_util_info ("metadata offset is beyond end of metadata area"); + #endif +- goto fail2; ++ goto fail; + } + +- if (grub_le_to_cpu64 (rlocn->offset) + grub_le_to_cpu64 (rlocn->size) > +- grub_le_to_cpu64 (mdah->size)) ++ metadatabuf = grub_malloc (mda_raw_size); ++ ++ if (! metadatabuf) ++ goto fail; ++ ++ if (mda_raw_offset + mda_raw_size > mda_size) + { +- if (2 * mda_size < GRUB_LVM_MDA_HEADER_SIZE || +- (grub_le_to_cpu64 (rlocn->offset) + grub_le_to_cpu64 (rlocn->size) - +- grub_le_to_cpu64 (mdah->size) > mda_size - GRUB_LVM_MDA_HEADER_SIZE)) +- { +-#ifdef GRUB_UTIL +- grub_util_info ("cannot copy metadata wrap in circular buffer"); +-#endif +- goto fail2; +- } ++ err = grub_disk_read (disk, 0, ++ mda_offset + mda_raw_offset, ++ mda_size - mda_raw_offset, ++ metadatabuf); ++ if (err) ++ goto fail2; + + /* Metadata is circular. Copy the wrap in place. */ +- grub_memcpy (metadatabuf + mda_size, +- metadatabuf + GRUB_LVM_MDA_HEADER_SIZE, +- grub_le_to_cpu64 (rlocn->offset) + +- grub_le_to_cpu64 (rlocn->size) - +- grub_le_to_cpu64 (mdah->size)); ++ err = grub_disk_read (disk, 0, ++ mda_offset + GRUB_LVM_MDA_HEADER_SIZE, ++ mda_raw_offset + mda_raw_size - mda_size, ++ metadatabuf + mda_size - mda_raw_offset); ++ if (err) ++ goto fail2; ++ } ++ else ++ { ++ err = grub_disk_read (disk, 0, ++ mda_offset + mda_raw_offset, ++ mda_raw_size, ++ metadatabuf); ++ if (err) ++ goto fail2; + } + +- if (grub_add ((grub_size_t)metadatabuf, +- (grub_size_t)grub_le_to_cpu64 (rlocn->offset), +- &ptr)) ++ p = q = metadatabuf; ++ ++ if (grub_add ((grub_size_t)metadatabuf, (grub_size_t)mda_raw_size, &ptr)) + { + error_parsing_metadata: + #ifdef GRUB_UTIL +@@ -288,11 +300,6 @@ grub_lvm_detect (grub_disk_t disk, + goto fail2; + } + +- p = q = (char *)ptr; +- +- if (grub_add ((grub_size_t)metadatabuf, (grub_size_t)mda_size, &ptr)) +- goto error_parsing_metadata; +- + mda_end = (char *)ptr; + + while (*q != ' ' && q < mda_end) diff --git a/grub2-menu-unrestricted.patch b/grub2-menu-unrestricted.patch new file mode 100644 index 0000000..a3f3d32 --- /dev/null +++ b/grub2-menu-unrestricted.patch @@ -0,0 +1,23 @@ +Index: grub-2.02~beta2/grub-core/normal/menu.c +=================================================================== +--- grub-2.02~beta2.orig/grub-core/normal/menu.c ++++ grub-2.02~beta2/grub-core/normal/menu.c +@@ -213,7 +213,17 @@ grub_menu_execute_entry(grub_menu_entry_ + grub_size_t sz = 0; + + if (entry->restricted) +- err = grub_auth_check_authentication (entry->users); ++ { ++ int auth_check = 1; ++ if (entry->users && entry->users[0] == 0) ++ { ++ const char *unr = grub_env_get ("unrestricted_menu"); ++ if (unr && (unr[0] == '1' || unr[0] == 'y')) ++ auth_check = 0; ++ } ++ if (auth_check) ++ err = grub_auth_check_authentication (entry->users); ++ } + + if (err) + { diff --git a/grub2-mkconfig-aarch64.patch b/grub2-mkconfig-aarch64.patch new file mode 100644 index 0000000..fcefd43 --- /dev/null +++ b/grub2-mkconfig-aarch64.patch @@ -0,0 +1,14 @@ +grub-mkonfig: Look for Image-* on aarch64 + +Index: grub-2.02~beta2/util/grub.d/10_linux.in +=================================================================== +--- grub-2.02~beta2.orig/util/grub.d/10_linux.in ++++ grub-2.02~beta2/util/grub.d/10_linux.in +@@ -190,6 +190,7 @@ EOF + machine=`uname -m` + case "x$machine" in + xi?86 | xx86_64) klist="/boot/vmlinuz-* /vmlinuz-* /boot/kernel-*" ;; ++ xaarch64) klist="/boot/Image-* /Image-* /boot/kernel-*" ;; + xs390 | xs390x) klist="/boot/image-* /boot/kernel-*" ;; + *) klist="/boot/vmlinuz-* /boot/vmlinux-* /vmlinuz-* /vmlinux-* \ + /boot/kernel-*" ;; diff --git a/grub2-mkconfig-arm.patch b/grub2-mkconfig-arm.patch new file mode 100644 index 0000000..51d3847 --- /dev/null +++ b/grub2-mkconfig-arm.patch @@ -0,0 +1,12 @@ +Index: grub-2.02~beta3/util/grub.d/10_linux.in +=================================================================== +--- grub-2.02~beta3.orig/util/grub.d/10_linux.in ++++ grub-2.02~beta3/util/grub.d/10_linux.in +@@ -193,6 +193,7 @@ machine=`uname -m` + case "x$machine" in + xi?86 | xx86_64) klist="/boot/vmlinuz-* /vmlinuz-* /boot/kernel-*" ;; + xaarch64) klist="/boot/Image-* /Image-* /boot/kernel-*" ;; ++ xarm*) klist="/boot/zImage-* /zImage-* /boot/kernel-*" ;; + xs390 | xs390x) klist="/boot/image-* /boot/kernel-*" ;; + *) klist="/boot/vmlinuz-* /boot/vmlinux-* /vmlinuz-* /vmlinux-* \ + /boot/kernel-*" ;; diff --git a/grub2-mkconfig-default-entry-correction.patch b/grub2-mkconfig-default-entry-correction.patch new file mode 100644 index 0000000..eef2037 --- /dev/null +++ b/grub2-mkconfig-default-entry-correction.patch @@ -0,0 +1,16 @@ +Index: grub-2.06/util/grub-mkconfig.in +=================================================================== +--- grub-2.06.orig/util/grub-mkconfig.in ++++ grub-2.06/util/grub-mkconfig.in +@@ -356,6 +356,11 @@ and /etc/grub.d/* files or please file a + # none of the children aborted with error, install the new grub.cfg + cat ${grub_cfg}.new > ${grub_cfg} + rm -f ${grub_cfg}.new ++ # check if default entry need to be corrected for updated distributor version ++ # and/or use fallback entry if default kernel entry removed ++ if test -x /usr/sbin/grub2-check-default; then ++ /usr/sbin/grub2-check-default >&2 ++ fi + sync_fs_journal || true + fi + fi diff --git a/grub2-once b/grub2-once new file mode 100644 index 0000000..86d052b --- /dev/null +++ b/grub2-once @@ -0,0 +1,309 @@ +#!/usr/bin/perl +# +# (C) 2014 mchang@suse.com +# +# 2014-02-20 jw@suse.de + +use strict; + +my $grub2_dir; +my $grub2_reboot; +my $grub2_editenv; +my $show_mapped; +my $id_name; +my @menuentry; +my @enumentry; +my %E; + +sub dPrint($) { + #print( STDERR @_[0]); +} + +sub sh_test($) { + my ( $exp ) = @_; + + dPrint( "?? '$exp' "); + + # Don't test grub command return status from linux shell, this often results + # in command not found error. In such case the expression often has no + # opening bracket and just returning false here to signify -ENOCMD error. + return 0 if ( $exp =~ m{^\s*[^\[]}); + + $exp .= " ]" if ( $exp =~ m{^\[.*[^\]]\s*$} ); # gnaaa + #my $t = qx{set -x; $exp}; + my $t = qx{$exp}; + my $ret = $? >> 8; + $ret = ($ret == 0) ? 1 : 0; + dPrint("=> $ret ($t)\n"); + return $ret; +} + +sub read_cfg($$) { + my ($dir, $cfg) = @_; + + my $fh; + my $m = ""; + my $state = 1; # 1 == normal, 010 == if-false, 011 == if-true, 110 == else-false, 111 == else-true + my @State = (); + + if ($dir) { + %E = ( "config_directory" => $dir ); + dPrint("# VE: 'cd'='$dir'\n"); + $dir .= "/"; + if ($> == 0) { + open($fh, "$grub2_editenv - list |") || die "cannot read grub2 environment: $!\n"; + while (<$fh>) { + chomp; + if ( m{^([^\s=]+?)=(.*)$} ) { + my ($k, $v) = ($1, $2); + $v =~ s{^"([^"]*)"$}{$1}; + dPrint("# VE: '$k'='$v'\n"); + $E{$k} = $v; + } + } + close($fh); + } + } + + dPrint("# open($dir$cfg)\n"); + open($fh, "<$dir$cfg") || die "cannot read $cfg in $dir: $!\n"; + + LINE: while ( <$fh> ) { + s{^#.*$}{}; # get rid of trailing comments, + s{\s+$}{}; # trailing whitespace + s{\s*;$}{}; # including semicolons + next if (m{^\s*$}); # and empty lines. + s{^\s*}{ }; # force leading whitespace to one + + dPrint(sprintf("#%d: '%s' [%s]%04b\n", $., $_, join(",",@State), $state)); + if ( m{^ fi$} ) { + $state = pop( @State); + $m .= "$_\n"; + dPrint(sprintf(">FI: [%s]0b%04b\n", join(",",@State), $state)); + next; + } + if ($state & 0b10) { # {if,else}-* + if ( m{^ elif\s+(.*?)\s*; then$} && !($state & 0b1000)) { + if ($state & 0b1) { + $state = 0b110; # else-false + } else { + $state = 0b010 + sh_test( $1); # if-? + dPrint(sprintf("=EI: 0b%03b\n", $state)); + $m .= "$_\n"; + next; + } + } elsif ( m{^ else$} && !($state & 0b1000)) { + if (($state & 0b111) == 0b010) { # in 'if' but neither 'else' nor 'true' + $state = 0b111; # else-true + } else { + $state = 0b110; # else-false + } + $m .= "$_\n"; + dPrint(sprintf("=EL: 0b%03b\n", $state)); + next; + } + } + if ($state & 0b1) { # *-true or normal + dPrint("-I1: $_\n"); + } else { # *-false + dPrint("-I0: $_\n"); + if ( m{^ if (.*?)\s*; then$} ) { + push( @State, $state); + $state = 0b1000; + $m .= "$_\n"; + } + next; + } + + while ( m'(?:[^\\])(\$(?:{([^}]+?)}|([A-Za-z0-9_]+)))' ) { + my ($s, $k1, $k2) = ($1, $2, $3); + my $k = (defined($k1)) ? $k1 : $k2; + dPrint("# VT: '$k'\n"); + if (exists( $E{$k})) { + $s =~ s{([\$\{\}\"])}{\\$1}g; + dPrint("# VB: '$_'\n"); + s{$s}{$E{$k}} || die; + dPrint("# VR: '$_'\n"); + } else { + $s =~ s{([\$\{\}\"])}{\\$1}g; + s{$s}{} || die; + dPrint("# VR: '$_'\n"); + } + } + + if ( m{^ if (.*?)\s*; then$} ) { + push( @State, $state); + $state = 0b010 + sh_test( $1); + dPrint(sprintf("$title" : "$title"; + my $eId = (($pId ne "") ? "$pId>" : "") . $c++; + + if ($type eq "menuentry") { + push @menuentry, $name; + push @enumentry, [$name, $eId]; + } elsif ($type eq "submenu") { + parse_menuentry ($name, $eId, $data); + } + } +} + +# Enable restore grubenv service (bnc#892358) +# Restore grubenv settings for booting default entry to workaround the grub2-once cannot +# work and function properly on lvm, md and s390. +sub enable_restore_grubenv_service { + + my $systemctl = "/usr/bin/systemctl"; + my $cleanup = "/var/lib/misc/grub2-cleanup-once"; + + unless (-e $cleanup) { + open(my $fh, ">", $cleanup) or die "open: $cleanup $!\n"; + close($fh); + } + + return 0 if (system("$systemctl --quiet is-enabled grub2-once") == 0); + system "$systemctl --no-reload enable grub2-once >/dev/null 2>&1"; +} + +$id_name = ""; +if (@ARGV == 2 && ($ARGV[0] eq "--show-mapped")) { + $show_mapped = 1; + $id_name = $ARGV[1]; +} elsif (@ARGV == 1) { + $show_mapped = 0; + $id_name = $ARGV[0]; +} + +die "wrong command line options, try --help\n" if ($id_name eq ""); + +open(SYSCONF, ") { + chomp; + next if ( /^\s*#/ ); + if ( /LOADER_TYPE=(\'|\"|)([^\'\"\s]+)\1(\s*|\s+#.*)$/ ) { + dPrint("OK : $2\n"); + if ($2 eq "grub2" || $2 eq "grub2-efi") { + # Found grub2 to be the incumbent loader ... + $grub2_dir = "/boot/grub2"; + $grub2_reboot = "/usr/sbin/grub2-reboot"; + $grub2_editenv = "/usr/bin/grub2-editenv"; + # Note : Here we continues rather than exiting the loop, which + # results in different behavior than previous "the first wins". Now + # the latest defined LOADER_TYPE can be used to override any + # previous one, which is identical to the result of regular shell + # variable expansion to meet most people's expectation. + } + } else { + next if ( /^\s*$/ ); + dPrint("SKIP: <$_>\n"); + } +} + +close (SYSCONF); + +if ($id_name eq "--help" or $id_name eq "-h") + { + print "Usage: grub2-once [--show-mapped ID | --list | ID | NAME_SUBSTRING ]\n"; + system "$grub2_reboot \"--help\""; + exit 0; + } + +die "no grub2_dir" if ($grub2_dir eq ""); + +my $m = read_cfg( $grub2_dir, "grub.cfg"); +# Note: only *one* top-level call to parse_menuentry() is possible +# or else it will start again with 0 (and no parent)! +parse_menuentry ("", "", $m); + +my $ret = ""; +my $name = ""; +my $id = -1; + +if ($id_name eq '--enum') { + foreach my $e (@enumentry) { + printf "%-7s %s\n", $e->[1], $e->[0]; + } + exit 0; +} + +if ($id_name eq '--list') + { + my $c = 0; + foreach my $e (@menuentry) + { + printf "%6d %s\n", $c, $e; + $c++; + } + exit 0; + } + +if ($id_name =~ m!^[0-9]+$!) { + + if ($id_name < @menuentry) { + $id = $id_name; + $name = $menuentry[$id]; + $ret = $name; + } + +} else { + + my $i = -1; + my $c = 0; + + $name = $id_name; + + foreach my $e (@menuentry) { + if ($e =~ qr!\Q$name\E!) { + $i = $c; + last; + } + } continue { + ++$c; + } + + if ($i >= 0) { + $id = $i; + $name = $menuentry[$id]; + $ret = "$id"; + } +} + +if ($show_mapped > 0) { + print $ret; +} else { + system "$grub2_reboot \"$name\""; + enable_restore_grubenv_service; +} + diff --git a/grub2-once.service b/grub2-once.service new file mode 100644 index 0000000..d67e165 --- /dev/null +++ b/grub2-once.service @@ -0,0 +1,17 @@ +[Unit] +Description=Restore grubenv +DefaultDependencies=no +After=local-fs.target +Before=sysinit.target shutdown.target +Conflicts=shutdown.target +ConditionPathIsReadWrite=/boot/grub2/grubenv +ConditionPathExists=/var/lib/misc/grub2-cleanup-once + +[Service] +Type=oneshot +ExecStart=-/usr/bin/grub2-editenv /boot/grub2/grubenv unset next_entry +ExecStartPost=-/usr/bin/rm -f /var/lib/misc/grub2-cleanup-once +StandardOutput=journal + +[Install] +WantedBy=sysinit.target diff --git a/grub2-pass-corret-root-for-nfsroot.patch b/grub2-pass-corret-root-for-nfsroot.patch new file mode 100644 index 0000000..72d780c --- /dev/null +++ b/grub2-pass-corret-root-for-nfsroot.patch @@ -0,0 +1,140 @@ +From 340fd0c8717c2bf33163a18bfec72243b0e51862 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Thu, 30 Aug 2012 15:43:17 +0800 +Subject: [PATCH] Pass corret root= for nfsroot + +References: bnc#774548, bsc#1069094 +Patch-Mainline: no + +Fix / is mounted on nfs. The fix is to pass kernel parameters +with correct root= for nfs. However since grub2 doesn't support +nfs file system module, the /boot on nfs is not possible and +grub2-probe not work in probing nfs mounted path. The fix is merely +on the script level and not use grub2-probe for above reasons. + +v2: Filter out autofs and securityfs from /proc/self/mountinfo (bsc#1069094) + +--- + util/grub-mkconfig.in | 37 ++++++++++++++++++++++++++++++------- + 1 files changed, 30 insertions(+), 7 deletions(-) + +Index: grub-2.06~rc1/util/grub-mkconfig.in +=================================================================== +--- grub-2.06~rc1.orig/util/grub-mkconfig.in ++++ grub-2.06~rc1/util/grub-mkconfig.in +@@ -131,14 +131,27 @@ else + exit 1 + fi + +-# Device containing our userland. Typically used for root= parameter. +-GRUB_DEVICE="`${grub_probe} --target=device /`" +-GRUB_DEVICE_UUID="`${grub_probe} --device ${GRUB_DEVICE} --target=fs_uuid 2> /dev/null`" || true +-GRUB_DEVICE_PARTUUID="`${grub_probe} --device ${GRUB_DEVICE} --target=partuuid 2> /dev/null`" || true ++probe_nfsroot_device () { ++ while read line ; do ++ part1=`echo $line | sed -e 's! - .*$!!'` ++ part2=`echo $line | sed -n -e 's! - \(.*\)$!\n\1!p' | sed 1d` ++ ++ set -- $part1 ++ path=$5 ++ ++ set -- $part2 ++ fstype=$1 ++ device=$2 ++ ++ if [ "x${path}" = "x/" ] && ++ [ "x${fstype}" = "xnfs" -o "x${fstype}" = "xnfs4" ] ; then ++ echo "${fstype}:$device" ++ return ++ fi ++ done ++} + +-# Device containing our /boot partition. Usually the same as GRUB_DEVICE. +-GRUB_DEVICE_BOOT="`${grub_probe} --target=device /boot`" +-GRUB_DEVICE_BOOT_UUID="`${grub_probe} --device ${GRUB_DEVICE_BOOT} --target=fs_uuid 2> /dev/null`" || true ++NFSROOT_DEVICE="`awk '($9!="autofs")&&($9!="securityfs")' /proc/self/mountinfo | probe_nfsroot_device`" + + # Disable os-prober by default due to security reasons. + GRUB_DISABLE_OS_PROBER="true" +@@ -146,11 +159,26 @@ GRUB_DISABLE_OS_PROBER="true" + # Filesystem for the device containing our userland. Used for stuff like + # choosing Hurd filesystem module. + GRUB_FS="`${grub_probe} --device ${GRUB_DEVICE} --target=fs 2> /dev/null || echo unknown`" +- +-if [ x"$GRUB_FS" = xunknown ]; then +- GRUB_FS="$(stat -f -c %T / || echo unknown)" ++if [ "x${NFSROOT_DEVICE}" != "x" ]; then ++ GRUB_DEVICE="" ++ GRUB_DEVICE_UUID="" ++ GRUB_DEVICE_PARTUUID="" ++ GRUB_FS="unknown" ++else ++ # Device containing our userland. Typically used for root= parameter. ++ GRUB_DEVICE="`${grub_probe} --target=device /`" ++ GRUB_DEVICE_UUID="`${grub_probe} --device ${GRUB_DEVICE} --target=fs_uuid 2> /dev/null`" || true ++ GRUB_DEVICE_PARTUUID="`${grub_probe} --device ${GRUB_DEVICE} --target=partuuid 2> /dev/null`" || true ++ ++ if [ x"$GRUB_FS" = x ] || [ x"$GRUB_FS" = xunknown ]; then ++ GRUB_FS="$(stat -f -c %T / || echo unknown)" ++ fi + fi + ++# Device containing our /boot partition. Usually the same as GRUB_DEVICE. ++GRUB_DEVICE_BOOT="`${grub_probe} --target=device /boot`" ++GRUB_DEVICE_BOOT_UUID="`${grub_probe} --device ${GRUB_DEVICE_BOOT} --target=fs_uuid 2> /dev/null`" || true ++ + # Provide a default set of stock linux early initrd images. + # Define here so the list can be modified in the sourced config file. + if [ "x${GRUB_EARLY_INITRD_LINUX_STOCK}" = "x" ]; then +Index: grub-2.06~rc1/util/grub.d/10_linux.in +=================================================================== +--- grub-2.06~rc1.orig/util/grub.d/10_linux.in ++++ grub-2.06~rc1/util/grub.d/10_linux.in +@@ -86,6 +86,12 @@ linux_entry () + type="$3" + args="$4" + ++ if [ -n "${linux_root_device_thisversion}" ]; then ++ root_device="root=${linux_root_device_thisversion}" ++ else ++ root_device="" ++ fi ++ + if [ -z "$boot_device_id" ]; then + boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" + fi +@@ -141,7 +147,7 @@ linux_entry () + message="$(gettext_printf "Loading Linux %s ..." ${version})" + sed "s/^/$submenu_indentation/" << EOF + echo '$(echo "$message" | grub_quote)' +- linux ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ${args} ++ linux ${rel_dirname}/${basename} ${root_device} ${args} + EOF + if test -n "${initrd}" ; then + # TRANSLATORS: ramdisk isn't identifier. Should be translated. +Index: grub-2.06~rc1/util/grub.d/20_linux_xen.in +=================================================================== +--- grub-2.06~rc1.orig/util/grub.d/20_linux_xen.in ++++ grub-2.06~rc1/util/grub.d/20_linux_xen.in +@@ -107,6 +107,11 @@ linux_entry_xsm () + args="$5" + xen_args="$6" + xsm="$7" ++ if [ -n "${linux_root_device_thisversion}" ]; then ++ root_device="root=${linux_root_device_thisversion}" ++ else ++ root_device="" ++ fi + # If user wants to enable XSM support, make sure there's + # corresponding policy file. + if ${xsm} ; then +@@ -157,7 +162,7 @@ linux_entry_xsm () + fi + ${xen_loader} ${rel_xen_dirname}/${xen_basename} placeholder ${xen_args} \${xen_rm_opts} + echo '$(echo "$lmessage" | grub_quote)' +- ${module_loader} ${rel_dirname}/${basename} placeholder root=${linux_root_device_thisversion} ${args} ++ ${module_loader} ${rel_dirname}/${basename} placeholder ${root_device} ${args} + EOF + if test -n "${initrd}" ; then + # TRANSLATORS: ramdisk isn't identifier. Should be translated. diff --git a/grub2-ppc-terminfo.patch b/grub2-ppc-terminfo.patch new file mode 100644 index 0000000..0d88dae --- /dev/null +++ b/grub2-ppc-terminfo.patch @@ -0,0 +1,151 @@ +From e263907f50e496e602edd9bd846ccb6e0565a085 Mon Sep 17 00:00:00 2001 +From: Mark Hamzy +Date: Wed, 28 Mar 2012 14:46:41 -0500 +Subject: [PATCH] Migrate PPC from Yaboot to Grub2 + +Add configuration support for serial terminal consoles. This will set the +maximum screen size so that text is not overwritten. + +--- + Makefile.util.def | 7 +++ + util/grub.d/20_ppc_terminfo.in | 114 ++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 121 insertions(+), 0 deletions(-) + create mode 100644 util/grub.d/20_ppc_terminfo.in + +Index: grub-2.02~beta2/Makefile.util.def +=================================================================== +--- grub-2.02~beta2.orig/Makefile.util.def ++++ grub-2.02~beta2/Makefile.util.def +@@ -485,6 +485,13 @@ script = { + }; + + script = { ++ name = '20_ppc_terminfo'; ++ common = util/grub.d/20_ppc_terminfo.in; ++ installdir = grubconf; ++ condition = COND_HOST_LINUX; ++}; ++ ++script = { + name = '30_os-prober'; + common = util/grub.d/30_os-prober.in; + installdir = grubconf; +Index: grub-2.02~beta2/util/grub.d/20_ppc_terminfo.in +=================================================================== +--- /dev/null ++++ grub-2.02~beta2/util/grub.d/20_ppc_terminfo.in +@@ -0,0 +1,114 @@ ++#! /bin/sh ++set -e ++ ++# grub-mkconfig helper script. ++# Copyright (C) 2006,2007,2008,2009,2010 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 . ++ ++prefix=@prefix@ ++exec_prefix=@exec_prefix@ ++bindir=@bindir@ ++libdir=@libdir@ ++. "@datadir@/@PACKAGE@/grub-mkconfig_lib" ++ ++export TEXTDOMAIN=@PACKAGE@ ++export TEXTDOMAINDIR=@localedir@ ++ ++X=80 ++Y=24 ++TERMINAL=ofconsole ++ ++argument () { ++ opt=$1 ++ shift ++ ++ if test $# -eq 0; then ++ echo "$0: option requires an argument -- '$opt'" 1>&2 ++ exit 1 ++ fi ++ echo $1 ++} ++ ++check_terminfo () { ++ ++ while test $# -gt 0 ++ do ++ option=$1 ++ shift ++ ++ case "$option" in ++ terminfo | TERMINFO) ++ ;; ++ ++ -g) ++ NEWXY=`argument $option "$@"` ++ NEWX=`echo $NEWXY | cut -d x -f 1` ++ NEWY=`echo $NEWXY | cut -d x -f 2` ++ ++ if [ ${NEWX} -ge 80 ] ; then ++ X=${NEWX} ++ else ++ echo "Warning: ${NEWX} is less than the minimum size of 80" ++ fi ++ ++ if [ ${NEWY} -ge 24 ] ; then ++ Y=${NEWY} ++ else ++ echo "Warning: ${NEWY} is less than the minimum size of 24" ++ fi ++ ++ shift ++ ;; ++ ++ *) ++# # accept console or ofconsole ++# if [ "$option" != "console" -a "$option" != "ofconsole" ] ; then ++# echo "Error: GRUB_TERMINFO unknown console: $option" ++# exit 1 ++# fi ++# # perfer console ++# TERMINAL=console ++ # accept ofconsole ++ if [ "$option" != "ofconsole" ] ; then ++ echo "Error: GRUB_TERMINFO unknown console: $option" ++ exit 1 ++ fi ++ # perfer console ++ TERMINAL=ofconsole ++ ;; ++ esac ++ ++ done ++ ++} ++ ++if ! uname -m | grep -q ppc ; then ++ exit 0 ++fi ++ ++if [ "x${GRUB_TERMINFO}" != "x" ] ; then ++ F1=`echo ${GRUB_TERMINFO} | cut -d " " -f 1` ++ ++ if [ "${F1}" != "terminfo" ] ; then ++ echo "Error: GRUB_TERMINFO is set to \"${GRUB_TERMINFO}\" The first word should be terminfo." ++ exit 1 ++ fi ++ ++ check_terminfo ${GRUB_TERMINFO} ++fi ++ ++cat << EOF ++ terminfo -g ${X}x${Y} ${TERMINAL} ++EOF diff --git a/grub2-ppc64-cas-fix-double-free.patch b/grub2-ppc64-cas-fix-double-free.patch new file mode 100644 index 0000000..b3ceac8 --- /dev/null +++ b/grub2-ppc64-cas-fix-double-free.patch @@ -0,0 +1,100 @@ +Index: grub-2.04~rc1/grub-core/kern/ieee1275/openfw.c +=================================================================== +--- grub-2.04~rc1.orig/grub-core/kern/ieee1275/openfw.c ++++ grub-2.04~rc1/grub-core/kern/ieee1275/openfw.c +@@ -595,7 +595,7 @@ grub_ieee1275_canonicalise_devname (cons + + /* Check if it's a CAS reboot. If so, set the script to be executed. */ + int +-grub_ieee1275_cas_reboot (char *script) ++grub_ieee1275_cas_reboot (char **script) + { + grub_uint32_t ibm_ca_support_reboot; + grub_uint32_t ibm_fw_nbr_reboots; +@@ -628,16 +628,37 @@ grub_ieee1275_cas_reboot (char *script) + + if (ibm_ca_support_reboot || ibm_fw_nbr_reboots) + { +- if (! grub_ieee1275_get_property_length (options, "boot-last-label", &actual)) +- { +- if (actual > 1024) +- script = grub_realloc (script, actual + 1); +- grub_ieee1275_get_property (options, "boot-last-label", script, actual, +- &actual); +- return 0; +- } ++ grub_ssize_t len; ++ char *buf; ++ ++ if (grub_ieee1275_get_property_length (options, "boot-last-label", &len) ++ || len <= 0) ++ { ++ grub_dprintf ("ieee1275", "boot-last-label missing or invalid\n"); ++ goto out; ++ } ++ /* The returned property string length may not include terminating null byte, and in ++ a bid to avoid out of bound access we allocate one more byte to add it back */ ++ buf = grub_malloc ((grub_size_t)len + 1); ++ if (!buf) ++ { ++ grub_print_error (); ++ goto out; ++ } ++ if (grub_ieee1275_get_property (options, "boot-last-label", buf, (grub_size_t)len + 1, &actual) ++ || actual < 0) ++ { ++ grub_dprintf ("ieee1275", "error while get boot-last-label property\n"); ++ grub_free (buf); ++ goto out; ++ } ++ /* Add terminating null byte */ ++ buf[len] = '\0'; ++ *script = buf; ++ return 0; + } + ++out: + grub_ieee1275_set_boot_last_label (""); + + return -1; +@@ -651,8 +672,9 @@ int grub_ieee1275_set_boot_last_label (c + grub_dprintf("ieee1275", "set boot_last_label (size: %" PRIxGRUB_SIZE ")\n", grub_strlen(text)); + if (! grub_ieee1275_finddevice ("/options", &options) && + options != (grub_ieee1275_ihandle_t) -1) ++ /* To be on the safe side, set the property string with terminating null byte */ + grub_ieee1275_set_property (options, "boot-last-label", text, +- grub_strlen (text), &actual); ++ grub_strlen (text) + 1, &actual); + return 0; + } + +Index: grub-2.04~rc1/grub-core/normal/main.c +=================================================================== +--- grub-2.04~rc1.orig/grub-core/normal/main.c ++++ grub-2.04~rc1/grub-core/normal/main.c +@@ -281,10 +281,9 @@ grub_normal_execute (const char *config, + #ifdef GRUB_MACHINE_IEEE1275 + int boot; + boot = 0; +- char *script; ++ char *script = NULL; + char *dummy[1] = { NULL }; +- script = grub_malloc (1024); +- if (! grub_ieee1275_cas_reboot (script)) ++ if (! grub_ieee1275_cas_reboot (&script) && script) + { + if (! grub_script_execute_new_scope (script, 0, dummy)) + boot = 1; +Index: grub-2.04~rc1/include/grub/ieee1275/ieee1275.h +=================================================================== +--- grub-2.04~rc1.orig/include/grub/ieee1275/ieee1275.h ++++ grub-2.04~rc1/include/grub/ieee1275/ieee1275.h +@@ -263,7 +263,7 @@ int EXPORT_FUNC(grub_ieee1275_devalias_n + void EXPORT_FUNC(grub_ieee1275_children_peer) (struct grub_ieee1275_devalias *alias); + void EXPORT_FUNC(grub_ieee1275_children_first) (const char *devpath, + struct grub_ieee1275_devalias *alias); +-int EXPORT_FUNC(grub_ieee1275_cas_reboot) (char *script); ++int EXPORT_FUNC(grub_ieee1275_cas_reboot) (char **script); + int EXPORT_FUNC(grub_ieee1275_set_boot_last_label) (const char *text); + + char *EXPORT_FUNC(grub_ieee1275_get_boot_dev) (void); diff --git a/grub2-ppc64-cas-new-scope.patch b/grub2-ppc64-cas-new-scope.patch new file mode 100644 index 0000000..3a751f4 --- /dev/null +++ b/grub2-ppc64-cas-new-scope.patch @@ -0,0 +1,17 @@ +Index: grub-2.02/grub-core/normal/main.c +=================================================================== +--- grub-2.02.orig/grub-core/normal/main.c ++++ grub-2.02/grub-core/normal/main.c +@@ -282,10 +282,11 @@ grub_normal_execute (const char *config, + int boot; + boot = 0; + char *script; ++ char *dummy[1] = { NULL }; + script = grub_malloc (1024); + if (! grub_ieee1275_cas_reboot (script)) + { +- if (! grub_script_execute_sourcecode (script)) ++ if (! grub_script_execute_new_scope (script, 0, dummy)) + boot = 1; + } + grub_free (script); diff --git a/grub2-ppc64-cas-reboot-support.patch b/grub2-ppc64-cas-reboot-support.patch new file mode 100644 index 0000000..1481700 --- /dev/null +++ b/grub2-ppc64-cas-reboot-support.patch @@ -0,0 +1,174 @@ +From 9d1411ffa7290c1cbdc9ee95bb5fcc5506e63e0f Mon Sep 17 00:00:00 2001 +From: Paulo Flabiano Smorigo +Date: Thu, 20 Sep 2012 18:07:39 -0300 +Subject: [PATCH 096/152] IBM client architecture (CAS) reboot support + +This is an implementation of IBM client architecture (CAS) reboot for GRUB. + +There are cases where the POWER firmware must reboot in order to support +specific features requested by a kernel. The kernel calls +ibm,client-architecture-support and it may either return or reboot with the new +feature set. eg: + +Calling ibm,client-architecture-support.../ +Elapsed time since release of system processors: 70959 mins 50 secs +Welcome to GRUB! + +Instead of return to the GRUB menu, it will check if the flag for CAS reboot is +set. If so, grub will automatically boot the last booted kernel using the same +parameters +--- + grub-core/kern/ieee1275/openfw.c | 62 ++++++++++++++++++++++++++++++++++++++++ + grub-core/normal/main.c | 19 ++++++++++++ + grub-core/script/execute.c | 7 +++++ + include/grub/ieee1275/ieee1275.h | 2 ++ + 4 files changed, 90 insertions(+) + +Index: grub-2.04~rc1/grub-core/kern/ieee1275/openfw.c +=================================================================== +--- grub-2.04~rc1.orig/grub-core/kern/ieee1275/openfw.c ++++ grub-2.04~rc1/grub-core/kern/ieee1275/openfw.c +@@ -593,6 +593,69 @@ grub_ieee1275_canonicalise_devname (cons + return NULL; + } + ++/* Check if it's a CAS reboot. If so, set the script to be executed. */ ++int ++grub_ieee1275_cas_reboot (char *script) ++{ ++ grub_uint32_t ibm_ca_support_reboot; ++ grub_uint32_t ibm_fw_nbr_reboots; ++ char property_value[10]; ++ grub_ssize_t actual; ++ grub_ieee1275_ihandle_t options; ++ ++ if (grub_ieee1275_finddevice ("/options", &options) < 0) ++ return -1; ++ ++ /* Check two properties, one is enough to get cas reboot value */ ++ ibm_ca_support_reboot = 0; ++ if (grub_ieee1275_get_integer_property (grub_ieee1275_chosen, ++ "ibm,client-architecture-support-reboot", ++ &ibm_ca_support_reboot, ++ sizeof (ibm_ca_support_reboot), ++ &actual) >= 0) ++ grub_dprintf("ieee1275", "ibm,client-architecture-support-reboot: %u\n", ++ ibm_ca_support_reboot); ++ ++ ibm_fw_nbr_reboots = 0; ++ if (grub_ieee1275_get_property (options, "ibm,fw-nbr-reboots", ++ property_value, sizeof (property_value), ++ &actual) >= 0) ++ { ++ property_value[sizeof (property_value) - 1] = 0; ++ ibm_fw_nbr_reboots = (grub_uint8_t) grub_strtoul (property_value, 0, 10); ++ grub_dprintf("ieee1275", "ibm,fw-nbr-reboots: %u\n", ibm_fw_nbr_reboots); ++ } ++ ++ if (ibm_ca_support_reboot || ibm_fw_nbr_reboots) ++ { ++ if (! grub_ieee1275_get_property_length (options, "boot-last-label", &actual)) ++ { ++ if (actual > 1024) ++ script = grub_realloc (script, actual + 1); ++ grub_ieee1275_get_property (options, "boot-last-label", script, actual, ++ &actual); ++ return 0; ++ } ++ } ++ ++ grub_ieee1275_set_boot_last_label (""); ++ ++ return -1; ++} ++ ++int grub_ieee1275_set_boot_last_label (const char *text) ++{ ++ grub_ieee1275_ihandle_t options; ++ grub_ssize_t actual; ++ ++ grub_dprintf("ieee1275", "set boot_last_label (size: %" PRIxGRUB_SIZE ")\n", grub_strlen(text)); ++ if (! grub_ieee1275_finddevice ("/options", &options) && ++ options != (grub_ieee1275_ihandle_t) -1) ++ grub_ieee1275_set_property (options, "boot-last-label", text, ++ grub_strlen (text), &actual); ++ return 0; ++} ++ + char * + grub_ieee1275_get_boot_dev (void) + { +Index: grub-2.04~rc1/grub-core/normal/main.c +=================================================================== +--- grub-2.04~rc1.orig/grub-core/normal/main.c ++++ grub-2.04~rc1/grub-core/normal/main.c +@@ -33,6 +33,9 @@ + #include + #include + #include ++#ifdef GRUB_MACHINE_IEEE1275 ++#include ++#endif + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -275,6 +278,21 @@ grub_normal_execute (const char *config, + { + menu = read_config_file (config); + ++#ifdef GRUB_MACHINE_IEEE1275 ++ int boot; ++ boot = 0; ++ char *script; ++ script = grub_malloc (1024); ++ if (! grub_ieee1275_cas_reboot (script)) ++ { ++ if (! grub_script_execute_sourcecode (script)) ++ boot = 1; ++ } ++ grub_free (script); ++ if (boot) ++ grub_command_execute ("boot", 0, 0); ++#endif ++ + /* Ignore any error. */ + grub_errno = GRUB_ERR_NONE; + } +Index: grub-2.04~rc1/grub-core/script/execute.c +=================================================================== +--- grub-2.04~rc1.orig/grub-core/script/execute.c ++++ grub-2.04~rc1/grub-core/script/execute.c +@@ -28,6 +28,9 @@ + #include + #include + #include ++#ifdef GRUB_MACHINE_IEEE1275 ++#include ++#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. */ +@@ -878,6 +881,10 @@ grub_script_execute_sourcecode (const ch + 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; +Index: grub-2.04~rc1/include/grub/ieee1275/ieee1275.h +=================================================================== +--- grub-2.04~rc1.orig/include/grub/ieee1275/ieee1275.h ++++ grub-2.04~rc1/include/grub/ieee1275/ieee1275.h +@@ -263,6 +263,8 @@ int EXPORT_FUNC(grub_ieee1275_devalias_n + void EXPORT_FUNC(grub_ieee1275_children_peer) (struct grub_ieee1275_devalias *alias); + void EXPORT_FUNC(grub_ieee1275_children_first) (const char *devpath, + struct grub_ieee1275_devalias *alias); ++int EXPORT_FUNC(grub_ieee1275_cas_reboot) (char *script); ++int EXPORT_FUNC(grub_ieee1275_set_boot_last_label) (const char *text); + + char *EXPORT_FUNC(grub_ieee1275_get_boot_dev) (void); + diff --git a/grub2-ppc64le-disable-video.patch b/grub2-ppc64le-disable-video.patch new file mode 100644 index 0000000..6a58bf7 --- /dev/null +++ b/grub2-ppc64le-disable-video.patch @@ -0,0 +1,49 @@ +Index: grub-2.04~rc1/grub-core/kern/ieee1275/cmain.c +=================================================================== +--- grub-2.04~rc1.orig/grub-core/kern/ieee1275/cmain.c ++++ grub-2.04~rc1/grub-core/kern/ieee1275/cmain.c +@@ -90,7 +90,10 @@ grub_ieee1275_find_options (void) + } + + if (rc >= 0 && grub_strncmp (tmp, "IBM", 3) == 0) +- grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_TREE_SCANNING_FOR_DISKS); ++ { ++ grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_TREE_SCANNING_FOR_DISKS); ++ grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_DISABLE_VIDEO_SUPPORT); ++ } + + /* Old Macs have no key repeat, newer ones have fully working one. + The ones inbetween when repeated key generates an escaoe sequence +Index: grub-2.04~rc1/grub-core/video/ieee1275.c +=================================================================== +--- grub-2.04~rc1.orig/grub-core/video/ieee1275.c ++++ grub-2.04~rc1/grub-core/video/ieee1275.c +@@ -352,9 +352,12 @@ static struct grub_video_adapter grub_vi + + GRUB_MOD_INIT(ieee1275_fb) + { +- find_display (); +- if (display) +- grub_video_register (&grub_video_ieee1275_adapter); ++ if (! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_DISABLE_VIDEO_SUPPORT)) ++ { ++ find_display (); ++ if (display) ++ grub_video_register (&grub_video_ieee1275_adapter); ++ } + } + + GRUB_MOD_FINI(ieee1275_fb) +Index: grub-2.04~rc1/include/grub/ieee1275/ieee1275.h +=================================================================== +--- grub-2.04~rc1.orig/include/grub/ieee1275/ieee1275.h ++++ grub-2.04~rc1/include/grub/ieee1275/ieee1275.h +@@ -148,6 +148,8 @@ enum grub_ieee1275_flag + GRUB_IEEE1275_FLAG_CURSORONOFF_ANSI_BROKEN, + + GRUB_IEEE1275_FLAG_RAW_DEVNAMES, ++ ++ GRUB_IEEE1275_FLAG_DISABLE_VIDEO_SUPPORT + }; + + extern int EXPORT_FUNC(grub_ieee1275_test_flag) (enum grub_ieee1275_flag flag); diff --git a/grub2-ppc64le-memory-map.patch b/grub2-ppc64le-memory-map.patch new file mode 100644 index 0000000..10034a0 --- /dev/null +++ b/grub2-ppc64le-memory-map.patch @@ -0,0 +1,84 @@ +Index: grub-2.04~rc1/grub-core/kern/ieee1275/openfw.c +=================================================================== +--- grub-2.04~rc1.orig/grub-core/kern/ieee1275/openfw.c ++++ grub-2.04~rc1/grub-core/kern/ieee1275/openfw.c +@@ -302,6 +302,34 @@ grub_ieee1275_map (grub_addr_t phys, gru + return args.catch_result; + } + ++/* Preallocate IEEE1275_MAX_MAP_RESOURCE map tracks to track the ++ * map regions allocated to us by the firmware. Cannot ++ * dynamically allocate them, since the heap is not set ++ * yet. ++ */ ++struct grub_map_track grub_map_track[IEEE1275_MAX_MAP_RESOURCE]; ++int grub_map_track_index=0; ++ ++void ++grub_releasemap () ++{ ++ int i=0; ++ for (i=grub_map_track_index-1; i >= 0; i--) ++ grub_ieee1275_release(grub_map_track[i].addr, grub_map_track[i].size); ++ grub_map_track_index = 0; ++ return; ++} ++ ++static void ++grub_track_map (grub_addr_t addr, grub_size_t size) ++{ ++ if (grub_map_track_index >= IEEE1275_MAX_MAP_RESOURCE) ++ return; ++ grub_map_track[grub_map_track_index].addr = addr; ++ grub_map_track[grub_map_track_index++].size = size; ++ return; ++} ++ + grub_err_t + grub_claimmap (grub_addr_t addr, grub_size_t size) + { +@@ -317,6 +345,7 @@ grub_claimmap (grub_addr_t addr, grub_si + return grub_errno; + } + ++ grub_track_map (addr, size); + return GRUB_ERR_NONE; + } + +Index: grub-2.04~rc1/include/grub/ieee1275/ieee1275.h +=================================================================== +--- grub-2.04~rc1.orig/include/grub/ieee1275/ieee1275.h ++++ grub-2.04~rc1/include/grub/ieee1275/ieee1275.h +@@ -30,6 +30,12 @@ struct grub_ieee1275_mem_region + unsigned int size; + }; + ++#define IEEE1275_MAX_MAP_RESOURCE 10 ++struct grub_map_track { ++ grub_addr_t addr; ++ grub_size_t size; ++}; ++ + #define IEEE1275_MAX_PROP_LEN 8192 + #define IEEE1275_MAX_PATH_LEN 256 + +@@ -235,6 +241,7 @@ char *EXPORT_FUNC(grub_ieee1275_encode_u + int EXPORT_FUNC(grub_ieee1275_get_block_size) (grub_ieee1275_ihandle_t ihandle); + + grub_err_t EXPORT_FUNC(grub_claimmap) (grub_addr_t addr, grub_size_t size); ++void EXPORT_FUNC(grub_releasemap) (void); + + int + EXPORT_FUNC(grub_ieee1275_map) (grub_addr_t phys, grub_addr_t virt, +Index: grub-2.04~rc1/grub-core/kern/ieee1275/init.c +=================================================================== +--- grub-2.04~rc1.orig/grub-core/kern/ieee1275/init.c ++++ grub-2.04~rc1/grub-core/kern/ieee1275/init.c +@@ -73,6 +73,7 @@ grub_addr_t grub_ieee1275_original_stack + void + grub_exit (void) + { ++ grub_releasemap(); + grub_ieee1275_exit (); + } + diff --git a/grub2-s390x-01-Changes-made-and-files-added-in-order-to-allow-s390x.patch b/grub2-s390x-01-Changes-made-and-files-added-in-order-to-allow-s390x.patch new file mode 100644 index 0000000..492f28f --- /dev/null +++ b/grub2-s390x-01-Changes-made-and-files-added-in-order-to-allow-s390x.patch @@ -0,0 +1,304 @@ +From f38ada424e7d991a0121253ba1abc430b86a990b Mon Sep 17 00:00:00 2001 +From: John Jolly +Date: Wed, 22 Jan 2014 01:18:10 -0700 +Subject: [PATCH 1/3] - Changes made and files added in order to allow s390x + build + +--- + grub-core/kern/emu/cache_s.S | 1 + + grub-core/kern/emu/lite.c | 2 ++ + grub-core/kern/s390x/dl.c | 37 +++++++++++++++++++++++++++++++++++ + grub-core/lib/s390x/setjmp.S | 46 ++++++++++++++++++++++++++++++++++++++++++++ + grub-core/lib/setjmp.S | 2 ++ + include/grub/cache.h | 2 +- + include/grub/s390x/setjmp.h | 29 ++++++++++++++++++++++++++++ + include/grub/s390x/time.h | 27 ++++++++++++++++++++++++++ + include/grub/s390x/types.h | 32 ++++++++++++++++++++++++++++++ + 9 files changed, 177 insertions(+), 1 deletion(-) + create mode 100644 grub-core/kern/s390x/dl.c + create mode 100644 grub-core/lib/s390x/setjmp.S + create mode 100644 include/grub/s390x/setjmp.h + create mode 100644 include/grub/s390x/time.h + create mode 100644 include/grub/s390x/types.h + +Index: grub-2.04~rc1/grub-core/kern/emu/cache_s.S +=================================================================== +--- grub-2.04~rc1.orig/grub-core/kern/emu/cache_s.S ++++ grub-2.04~rc1/grub-core/kern/emu/cache_s.S +@@ -10,6 +10,7 @@ + #include "../powerpc/cache.S" + #elif defined(__ia64__) || defined(__arm__) || defined(__aarch64__) || \ + defined(__mips__) || defined(__riscv) ++#elif defined(__s390x__) + #else + #error "No target cpu type is defined" + #endif +Index: grub-2.04~rc1/grub-core/kern/emu/lite.c +=================================================================== +--- grub-2.04~rc1.orig/grub-core/kern/emu/lite.c ++++ grub-2.04~rc1/grub-core/kern/emu/lite.c +@@ -26,6 +26,8 @@ + #include "../arm64/dl.c" + #elif defined(__riscv) + #include "../riscv/dl.c" ++#elif defined(__s390x__) ++#include "../s390x/dl.c" + #else + #error "No target cpu type is defined" + #endif +Index: grub-2.04~rc1/grub-core/kern/dl.c +=================================================================== +--- grub-2.04~rc1.orig/grub-core/kern/dl.c ++++ grub-2.04~rc1/grub-core/kern/dl.c +@@ -229,7 +229,7 @@ grub_dl_load_segments (grub_dl_t mod, co + unsigned i; + const Elf_Shdr *s; + grub_size_t tsize = 0, talign = 1; +-#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) ++#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && !defined (__s390x__) + grub_size_t tramp; + grub_size_t got; + grub_err_t err; +@@ -245,7 +245,7 @@ grub_dl_load_segments (grub_dl_t mod, co + talign = s->sh_addralign; + } + +-#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) ++#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && !defined (__s390x__) + err = grub_arch_dl_get_tramp_got_size (e, &tramp, &got); + if (err) + return err; +@@ -308,7 +308,7 @@ grub_dl_load_segments (grub_dl_t mod, co + mod->segment = seg; + } + } +-#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) ++#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && !defined (__s390x__) + ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_TRAMP_ALIGN); + mod->tramp = ptr; + mod->trampptr = ptr; +Index: grub-2.04~rc1/grub-core/kern/s390x/dl.c +=================================================================== +--- /dev/null ++++ grub-2.04~rc1/grub-core/kern/s390x/dl.c +@@ -0,0 +1,40 @@ ++/* dl.c - arch-dependent part of loadable module support */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2002,2004,2005,2007,2009 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 . ++ */ ++ ++#include ++ ++/* Check if EHDR is a valid ELF header. */ ++grub_err_t ++grub_arch_dl_check_header (void *ehdr) ++{ ++ (void)(ehdr); ++ return GRUB_ERR_BUG; ++} ++ ++/* Relocate symbols. */ ++grub_err_t ++grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, ++ Elf_Shdr *s, grub_dl_segment_t seg) ++{ ++ (void)(mod); ++ (void)(ehdr); ++ (void)(s); ++ (void)(seg); ++ return GRUB_ERR_BUG; ++} +Index: grub-2.04~rc1/grub-core/lib/s390x/setjmp.S +=================================================================== +--- /dev/null ++++ grub-2.04~rc1/grub-core/lib/s390x/setjmp.S +@@ -0,0 +1,46 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2005,2007,2009 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 . ++ */ ++ ++#include ++#include ++ ++ .file "setjmp.S" ++ ++GRUB_MOD_LICENSE "GPLv3+" ++ ++ .text ++ ++/* ++ * int grub_setjmp (grub_jmp_buf env) ++ */ ++FUNCTION(grub_setjmp) ++ stmg %r11,%r15,0(%r2) ++ lghi %r2,0 ++ br %r14 ++ ++/* ++ * int grub_longjmp (grub_jmp_buf env, int val) ++ */ ++FUNCTION(grub_longjmp) ++ chi %r3,0 ++ jne .L2 ++ lghi %r3,1 ++.L2: ++ lmg %r11,%r15,0(%r2) ++ lgr %r2,%r3 ++ br %r14 +Index: grub-2.04~rc1/grub-core/lib/setjmp.S +=================================================================== +--- grub-2.04~rc1.orig/grub-core/lib/setjmp.S ++++ grub-2.04~rc1/grub-core/lib/setjmp.S +@@ -17,6 +17,8 @@ + #include "./arm64/setjmp.S" + #elif defined(__riscv) + #include "./riscv/setjmp.S" ++#elif defined(__s390x__) ++#include "./s390x/setjmp.S" + #else + #error "Unknown target cpu type" + #endif +Index: grub-2.04~rc1/include/grub/cache.h +=================================================================== +--- grub-2.04~rc1.orig/include/grub/cache.h ++++ grub-2.04~rc1/include/grub/cache.h +@@ -23,7 +23,7 @@ + #include + #include + +-#if defined (__i386__) || defined (__x86_64__) ++#if defined (__i386__) || defined (__x86_64__) || defined (__s390x__) + static inline void + grub_arch_sync_caches (void *address __attribute__ ((unused)), + grub_size_t len __attribute__ ((unused))) +Index: grub-2.04~rc1/include/grub/s390x/setjmp.h +=================================================================== +--- /dev/null ++++ grub-2.04~rc1/include/grub/s390x/setjmp.h +@@ -0,0 +1,29 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2002,2004,2006,2007,2009 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 . ++ */ ++ ++#ifndef GRUB_SETJMP_CPU_HEADER ++#define GRUB_SETJMP_CPU_HEADER 1 ++ ++#include ++ ++typedef grub_uint64_t grub_jmp_buf[5]; ++ ++int grub_setjmp (grub_jmp_buf env) __attribute__ ((returns_twice)); ++void grub_longjmp (grub_jmp_buf env, int val) __attribute__ ((noreturn)); ++ ++#endif /* ! GRUB_SETJMP_CPU_HEADER */ +Index: grub-2.04~rc1/include/grub/s390x/time.h +=================================================================== +--- /dev/null ++++ grub-2.04~rc1/include/grub/s390x/time.h +@@ -0,0 +1,27 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2007 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 . ++ */ ++ ++#ifndef KERNEL_CPU_TIME_HEADER ++#define KERNEL_CPU_TIME_HEADER 1 ++ ++static __inline void ++grub_cpu_idle (void) ++{ ++} ++ ++#endif /* ! KERNEL_CPU_TIME_HEADER */ +Index: grub-2.04~rc1/include/grub/s390x/types.h +=================================================================== +--- /dev/null ++++ grub-2.04~rc1/include/grub/s390x/types.h +@@ -0,0 +1,32 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2002,2004,2006,2007 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 . ++ */ ++ ++#ifndef GRUB_TYPES_CPU_HEADER ++#define GRUB_TYPES_CPU_HEADER 1 ++ ++/* The size of void *. */ ++#define GRUB_TARGET_SIZEOF_VOID_P 8 ++ ++/* The size of long. */ ++#define GRUB_TARGET_SIZEOF_LONG 8 ++ ++/* s390x is big-endian. */ ++#define GRUB_TARGET_WORDS_BIGENDIAN 1 ++ ++ ++#endif /* ! GRUB_TYPES_CPU_HEADER */ diff --git a/grub2-s390x-02-kexec-module-added-to-emu.patch b/grub2-s390x-02-kexec-module-added-to-emu.patch new file mode 100644 index 0000000..24a6ca7 --- /dev/null +++ b/grub2-s390x-02-kexec-module-added-to-emu.patch @@ -0,0 +1,342 @@ +--- + grub-core/Makefile.am | 1 + grub-core/Makefile.core.def | 2 + grub-core/kern/emu/main.c | 4 + grub-core/kern/emu/misc.c | 18 ++++ + grub-core/loader/emu/linux.c | 173 +++++++++++++++++++++++++++++++++++++++++++ + include/grub/emu/exec.h | 4 + include/grub/emu/hostfile.h | 3 + include/grub/emu/misc.h | 3 + 8 files changed, 204 insertions(+), 4 deletions(-) + +Index: grub-2.04~rc1/grub-core/Makefile.core.def +=================================================================== +--- grub-2.04~rc1.orig/grub-core/Makefile.core.def ++++ grub-2.04~rc1/grub-core/Makefile.core.def +@@ -1786,9 +1786,9 @@ module = { + arm64 = loader/arm64/linux.c; + riscv32 = loader/riscv/linux.c; + riscv64 = loader/riscv/linux.c; ++ emu = loader/emu/linux.c; + common = loader/linux.c; + common = lib/cmdline.c; +- enable = noemu; + }; + + module = { +Index: grub-2.04~rc1/grub-core/loader/emu/linux.c +=================================================================== +--- /dev/null ++++ grub-2.04~rc1/grub-core/loader/emu/linux.c +@@ -0,0 +1,173 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2006,2007,2008,2009,2010 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 . ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static grub_dl_t my_mod; ++ ++static char *kernel_path; ++static char *initrd_path; ++static char *boot_cmdline; ++ ++static grub_err_t ++grub_linux_boot (void) ++{ ++ grub_err_t rc = GRUB_ERR_NONE; ++ char *initrd_param; ++ const char *kexec[] = { "kexec", "-l", kernel_path, boot_cmdline, NULL, NULL }; ++ const char *systemctl[] = { "systemctl", "kexec", NULL }; ++ int kexecute = grub_util_get_kexecute(); ++ ++ if (initrd_path) { ++ initrd_param = grub_xasprintf("--initrd=%s", initrd_path); ++ kexec[3] = initrd_param; ++ kexec[4] = boot_cmdline; ++ } else { ++ initrd_param = grub_xasprintf("%s", ""); ++ //return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("initrd required!")); ++ } ++ ++ grub_printf("%serforming 'kexec -l %s %s %s'\n", ++ (kexecute) ? "P" : "Not p", ++ kernel_path, initrd_param, boot_cmdline); ++ ++ if (kexecute) ++ rc = grub_util_exec(kexec); ++ ++ grub_free(initrd_param); ++ ++ if (rc != GRUB_ERR_NONE) { ++ grub_error (rc, N_("Error trying to perform kexec load operation.")); ++ grub_sleep (3); ++ return rc; ++ } ++ if (kexecute < 1) ++ grub_fatal (N_("Use '"PACKAGE"-emu --kexec' to force a system restart.")); ++ ++ grub_printf("Performing 'systemctl kexec' (%s) ", ++ (kexecute==1) ? "do-or-die" : "just-in-case"); ++ rc = grub_util_exec (systemctl); ++ ++ if (kexecute == 1) ++ grub_fatal (N_("Error trying to perform 'systemctl kexec'")); ++ ++ /* need to check read-only root before resetting hard!? */ ++ grub_printf("Performing 'kexec -e'"); ++ kexec[1] = "-e"; ++ kexec[2] = NULL; ++ rc = grub_util_exec(kexec); ++ if ( rc != GRUB_ERR_NONE ) ++ grub_fatal (N_("Error trying to directly perform 'kexec -e'.")); ++ ++ return rc; ++} ++ ++static grub_err_t ++grub_linux_unload (void) ++{ ++ grub_dl_unref (my_mod); ++ if ( boot_cmdline != NULL ) ++ grub_free (boot_cmdline); ++ boot_cmdline = NULL; ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) ++{ ++ int i; ++ char *tempstr; ++ ++ grub_dl_ref (my_mod); ++ ++ if (argc == 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); ++ ++ if ( !grub_util_is_regular(argv[0]) ) ++ return grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("Cannot find kernel file %s"), argv[0]); ++ ++ if ( kernel_path != NULL ) ++ grub_free(kernel_path); ++ ++ kernel_path = grub_xasprintf("%s", argv[0]); ++ ++ if ( boot_cmdline != NULL ) { ++ grub_free(boot_cmdline); ++ boot_cmdline = NULL; ++ } ++ ++ if ( argc > 1 ) ++ { ++ boot_cmdline = grub_xasprintf("--command-line=%s", argv[1]); ++ for ( i = 2; i < argc; i++ ) { ++ tempstr = grub_xasprintf("%s %s", boot_cmdline, argv[i]); ++ grub_free(boot_cmdline); ++ boot_cmdline = tempstr; ++ } ++ } ++ ++ grub_loader_set (grub_linux_boot, grub_linux_unload, 0); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) ++{ ++ if (argc == 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); ++ ++ if ( !grub_util_is_regular(argv[0]) ) ++ return grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("Cannot find initrd file %s"), argv[0]); ++ ++ if ( initrd_path != NULL ) ++ grub_free(initrd_path); ++ ++ initrd_path = grub_xasprintf("%s", argv[0]); ++ ++ grub_dl_unref (my_mod); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_command_t cmd_linux, cmd_initrd; ++ ++GRUB_MOD_INIT(linux) ++{ ++ cmd_linux = grub_register_command ("linux", grub_cmd_linux, 0, N_("Load Linux.")); ++ cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, 0, N_("Load initrd.")); ++ my_mod = mod; ++ kernel_path = NULL; ++ initrd_path = NULL; ++ boot_cmdline = NULL; ++} ++ ++GRUB_MOD_FINI(linux) ++{ ++ grub_unregister_command (cmd_linux); ++ grub_unregister_command (cmd_initrd); ++} +Index: grub-2.04~rc1/include/grub/emu/hostfile.h +=================================================================== +--- grub-2.04~rc1.orig/include/grub/emu/hostfile.h ++++ grub-2.04~rc1/include/grub/emu/hostfile.h +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + + int +@@ -29,7 +30,7 @@ grub_util_is_directory (const char *path + int + grub_util_is_special_file (const char *path); + int +-grub_util_is_regular (const char *path); ++EXPORT_FUNC(grub_util_is_regular) (const char *path); + + char * + grub_util_path_concat (size_t n, ...); +Index: grub-2.04~rc1/include/grub/emu/exec.h +=================================================================== +--- grub-2.04~rc1.orig/include/grub/emu/exec.h ++++ grub-2.04~rc1/include/grub/emu/exec.h +@@ -23,6 +23,8 @@ + #include + + #include ++#include ++ + pid_t + grub_util_exec_pipe (const char *const *argv, int *fd); + pid_t +@@ -32,7 +34,7 @@ int + grub_util_exec_redirect_all (const char *const *argv, const char *stdin_file, + const char *stdout_file, const char *stderr_file); + int +-grub_util_exec (const char *const *argv); ++EXPORT_FUNC(grub_util_exec) (const char *const *argv); + int + grub_util_exec_redirect (const char *const *argv, const char *stdin_file, + const char *stdout_file); +Index: grub-2.04~rc1/grub-core/Makefile.am +=================================================================== +--- grub-2.04~rc1.orig/grub-core/Makefile.am ++++ grub-2.04~rc1/grub-core/Makefile.am +@@ -303,6 +303,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/inc + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/hostdisk.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/hostfile.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/exec.h + if COND_GRUB_EMU_SDL + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/sdl.h + endif +Index: grub-2.04~rc1/grub-core/kern/emu/main.c +=================================================================== +--- grub-2.04~rc1.orig/grub-core/kern/emu/main.c ++++ grub-2.04~rc1/grub-core/kern/emu/main.c +@@ -107,6 +107,7 @@ static struct argp_option options[] = { + N_("use GRUB files in the directory DIR [default=%s]"), 0}, + {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, + {"hold", 'H', N_("SECS"), OPTION_ARG_OPTIONAL, N_("wait until a debugger will attach"), 0}, ++ {"kexec", 'X', 0, 0, N_("try the untryable."), 0}, + { 0, 0, 0, 0, 0, 0 } + }; + +@@ -164,6 +165,9 @@ argp_parser (int key, char *arg, struct + case 'v': + verbosity++; + break; ++ case 'X': ++ grub_util_set_kexecute(); ++ break; + + case ARGP_KEY_ARG: + { +Index: grub-2.04~rc1/grub-core/kern/emu/misc.c +=================================================================== +--- grub-2.04~rc1.orig/grub-core/kern/emu/misc.c ++++ grub-2.04~rc1/grub-core/kern/emu/misc.c +@@ -39,6 +39,7 @@ + #include + + int verbosity; ++int kexecute; + + void + grub_util_warn (const char *fmt, ...) +@@ -82,7 +83,7 @@ grub_util_error (const char *fmt, ...) + vfprintf (stderr, fmt, ap); + va_end (ap); + fprintf (stderr, ".\n"); +- exit (1); ++ grub_exit (); + } + + void * +@@ -141,6 +142,9 @@ xasprintf (const char *fmt, ...) + void + grub_exit (void) + { ++#if defined (GRUB_KERNEL) ++ grub_reboot(); ++#endif + exit (1); + } + #endif +@@ -202,3 +206,15 @@ grub_util_load_image (const char *path, + + fclose (fp); + } ++ ++void ++grub_util_set_kexecute(void) ++{ ++ kexecute++; ++} ++ ++int ++grub_util_get_kexecute(void) ++{ ++ return kexecute; ++} +Index: grub-2.04~rc1/include/grub/emu/misc.h +=================================================================== +--- grub-2.04~rc1.orig/include/grub/emu/misc.h ++++ grub-2.04~rc1/include/grub/emu/misc.h +@@ -56,6 +56,9 @@ void EXPORT_FUNC(grub_util_warn) (const + void EXPORT_FUNC(grub_util_info) (const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 1, 2))); + void EXPORT_FUNC(grub_util_error) (const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 1, 2), noreturn)); + ++void EXPORT_FUNC(grub_util_set_kexecute) (void); ++int EXPORT_FUNC(grub_util_get_kexecute) (void) WARN_UNUSED_RESULT; ++ + grub_uint64_t EXPORT_FUNC (grub_util_get_cpu_time_ms) (void); + + #ifdef HAVE_DEVICE_MAPPER diff --git a/grub2-s390x-03-output-7-bit-ascii.patch b/grub2-s390x-03-output-7-bit-ascii.patch new file mode 100644 index 0000000..bb1ddac --- /dev/null +++ b/grub2-s390x-03-output-7-bit-ascii.patch @@ -0,0 +1,540 @@ +Vn: + * recognize 'dev/sclp_line0' as 3215-look-alike. [bnc#876743] +Vn+1: + * revamp readkey_dumb(). +Vn+2: + * support hotkeys on all line-mode terminals, not only 3215. [bnc#885668] + +--- + grub-core/kern/emu/main.c | 8 + + grub-core/normal/menu_text.c | 54 +++++++- + grub-core/normal/term.c | 2 + grub-core/osdep/unix/emuconsole.c | 238 +++++++++++++++++++++++++++++++++++++- + include/grub/term.h | 4 + 5 files changed, 294 insertions(+), 12 deletions(-) + +Index: grub-2.06~rc1/grub-core/osdep/unix/emuconsole.c +=================================================================== +--- grub-2.06~rc1.orig/grub-core/osdep/unix/emuconsole.c ++++ grub-2.06~rc1/grub-core/osdep/unix/emuconsole.c +@@ -39,17 +39,61 @@ + + #include + ++#include ++#include ++ + extern struct grub_terminfo_output_state grub_console_terminfo_output; + static int original_fl; + static int saved_orig; + static struct termios orig_tty; + static struct termios new_tty; ++static int console_mode = 0; ++ ++#define MAX_LEN 1023 ++#if defined(__s390x__) ++static int ++dummy (void) ++{ ++ return 0; ++} ++#endif ++#if 0 ++static char msg[MAX_LEN+1]; ++static void ++dprint (int len) ++{ ++ if (len < 0) ++ return; ++ if (len > MAX_LEN) ++ len = MAX_LEN; ++ write (2, msg, len); ++} ++#define dprintf(fmt, vargs...) dprint(snprintf(msg, MAX_LEN, fmt, ## vargs)) ++#else ++#define dprintf(fmt, vargs...) {} ++#endif + + static void +-put (struct grub_term_output *term __attribute__ ((unused)), const int c) ++put (struct grub_term_output *term, const int c) + { + char chr = c; + ssize_t actual; ++ struct grub_terminfo_output_state *data ++ = (struct grub_terminfo_output_state *) term->data; ++ ++ if (term->flags & GRUB_TERM_DUMB) { ++ if (c == '\n') { ++ data->pos.y++; ++ data->pos.x = 0; ++ } else { ++ data->pos.x++; ++ } ++ if (0) { ++ if (c == ' ') chr = '_'; ++ if (c == GRUB_TERM_BACKSPACE) chr = '{'; ++ if (c == '\b') chr = '<'; ++ } ++ } + + actual = write (STDOUT_FILENO, &chr, 1); + if (actual < 1) +@@ -60,17 +104,152 @@ put (struct grub_term_output *term __att + } + + static int +-readkey (struct grub_term_input *term __attribute__ ((unused))) ++readkey (struct grub_term_input *term) + { + grub_uint8_t c; + ssize_t actual; + ++ fd_set readfds; ++ struct timeval timeout; ++ int sel; ++ FD_SET (0, &readfds); ++ timeout.tv_sec = 0; ++ timeout.tv_usec = 500000; ++ if ((sel=select (1, &readfds, (fd_set *)0, (fd_set *)0, &timeout)) <= 0) ++ { ++ if (sel < 0 && errno == EINTR) ++ return 0x03; /* '^C' */ ++ return -1; ++ } ++ + actual = read (STDIN_FILENO, &c, 1); + if (actual > 0) + return c; + return -1; + } + ++#define NO_KEY ((grub_uint8_t)-1) ++static int ++readkey_dumb (struct grub_term_input *term) ++{ ++ grub_uint8_t c; ++ static grub_uint8_t p = NO_KEY; ++ ++ c = readkey (term); ++ if (c == NO_KEY) ++ return -1; ++ if ((p == '^' || p == '\n') && c == '\n') /* solitary '^' or '\n'? */ ++ { ++ c = p; /* use immediately! */ ++ p = '\n'; ++ } ++ else if ((c == '\n' || c == '^') && p != c) /* non-duplicate specials? */ ++ { ++ p = c; /* remember! */ ++ c = NO_KEY; ++ } ++ else if (p == '^') ++ { ++ if (c != '^') ++ c &= 0x1F; ++ p = NO_KEY; ++ } ++ else ++ p = c; ++ return c; ++} ++ ++static void ++grub_dumb_putchar (struct grub_term_output *term, ++ const struct grub_unicode_glyph *c) ++{ ++ unsigned i; ++ ++ /* For now, do not try to use a surrogate pair. */ ++ if (c->base > 0xffff) ++ put (term, '?'); ++ else ++ put (term, (c->base & 0xffff)); ++ ++ if (0) { ++ for (i = 0; i < c->ncomb; i++) ++ if (c->base < 0xffff) ++ put (term, grub_unicode_get_comb (c)[i].code); ++ } ++} ++ ++static struct grub_term_coordinate ++grub_dumb_getxy (struct grub_term_output *term) ++{ ++ struct grub_terminfo_output_state *data ++ = (struct grub_terminfo_output_state *) term->data; ++ ++ dprintf ("<%d,%d>", data->pos.x, data->pos.y); ++ return data->pos; ++} ++ ++static struct grub_term_coordinate ++grub_dumb_getwh (struct grub_term_output *term) ++{ ++ static int once = 0; ++ struct grub_terminfo_output_state *data ++ = (struct grub_terminfo_output_state *) term->data; ++ ++ if (!once++) ++ dprintf ("dumb_getwh: w=%d h=%d\n", data->size.x, data->size.y); ++ return data->size; ++} ++ ++static void ++grub_dumb_gotoxy (struct grub_term_output *term, ++ struct grub_term_coordinate pos) ++{ ++ struct grub_terminfo_output_state *data ++ = (struct grub_terminfo_output_state *) term->data; ++ ++ if (pos.x > grub_term_width (term) || pos.y > grub_term_height (term)) ++ { ++ grub_error (GRUB_ERR_BUG, "invalid point (%u,%u)", pos.x, pos.y); ++ return; ++ } ++ ++ dprintf("goto(%d,%d)", pos.x, pos.y); ++ if (pos.x > (grub_term_width (term) - 4)) { ++ dprintf (" really?"); ++ //return; ++ } ++ ++ if (data->gotoxy) ++ { ++ int i; ++ dprintf ("data-gotoxy"); ++ if (data->pos.y != pos.y) { ++ put (term, '\n'); ++ ++ for (i = 1; i < pos.x; i++ ) ++ put (term, ' '); ++ } ++ } ++ else ++ { ++ int i = 0; ++ if (data->pos.y != pos.y || data->pos.x > pos.x) { ++ if (data->pos.y >= pos.y) data->pos.y = pos.y - 1; ++ if (pos.y - data->pos.y > 3) data->pos.y = pos.y - 2; ++ dprintf (" <%dnl>+%d", (pos.y - data->pos.y), pos.x); ++ for (i = data->pos.y; i < pos.y; i++ ) ++ put (term, '\n'); ++ } ++ for (i = data->pos.x; i < pos.x; i++ ) ++ put (term, ' '); ++ dprintf ("#%d", i); ++ grub_dumb_getxy (term); ++ } ++ ++ dprintf ("\n"); ++ data->pos = pos; ++} ++ + static grub_err_t + grub_console_init_input (struct grub_term_input *term) + { +@@ -105,7 +284,8 @@ static grub_err_t + grub_console_init_output (struct grub_term_output *term) + { + struct winsize size; +- if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &size) >= 0) ++ if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &size) >= 0 && ++ size.ws_col > 0 && size.ws_row > 0) + { + grub_console_terminfo_output.size.x = size.ws_col; + grub_console_terminfo_output.size.y = size.ws_row; +@@ -115,6 +295,8 @@ grub_console_init_output (struct grub_te + grub_console_terminfo_output.size.x = 80; + grub_console_terminfo_output.size.y = 24; + } ++ if (console_mode == 3215) ++ grub_console_terminfo_output.size.x -= 1; + + grub_terminfo_output_init (term); + +@@ -161,24 +343,72 @@ static struct grub_term_output grub_cons + void + grub_console_init (void) + { ++#if ! defined(__s390x__) + const char *cs = nl_langinfo (CODESET); + if (cs && grub_strcasecmp (cs, "UTF-8")) + grub_console_term_output.flags = GRUB_TERM_CODE_TYPE_UTF8_LOGICAL; + else + grub_console_term_output.flags = GRUB_TERM_CODE_TYPE_ASCII; ++#else ++ char link[MAX_LEN+1]; ++ ssize_t len = readlink ("/proc/self/fd/0", link, MAX_LEN); ++ ++ if (len > 0) ++ link[len] = 0; ++ else ++ link[0] = 0; ++ if (grub_strncmp ("/dev/ttyS", link, 9) == 0 ) ++ console_mode = 3215; ++ else if (grub_strncmp ("/dev/3270/tty", link, 13) == 0 ) ++ console_mode = 3270; ++ else if (grub_strncmp ("/dev/sclp_line", link, 14) == 0 ) ++ console_mode = 3215; ++ grub_console_term_output.flags = GRUB_TERM_CODE_TYPE_ASCII; ++ switch (console_mode) ++ { ++ case 3215: ++ grub_console_term_output.flags |= GRUB_TERM_DUMB; ++ /* FALLTHROUGH */ ++ case 3270: ++ grub_console_term_output.flags |= GRUB_TERM_LINE; ++ grub_console_term_output.flags |= GRUB_TERM_NO_ECHO; ++ grub_console_terminfo_input.readkey = readkey_dumb; ++ break; ++ default: ++ break; ++ } ++#endif ++ if (grub_console_term_output.flags & GRUB_TERM_DUMB) ++ { ++ grub_console_term_output.putchar = grub_dumb_putchar, ++ grub_console_term_output.getxy = grub_dumb_getxy; ++ grub_console_term_output.getwh = grub_dumb_getwh; ++ grub_console_term_output.gotoxy = grub_dumb_gotoxy; ++ grub_console_term_output.cls = (void *) dummy; ++ grub_console_term_output.setcolorstate = (void *) dummy; ++ grub_console_term_output.setcursor = (void *) dummy; ++ grub_console_term_output.progress_update_divisor = GRUB_PROGRESS_NO_UPDATE; ++ } + grub_term_register_input ("console", &grub_console_term_input); + grub_term_register_output ("console", &grub_console_term_output); + grub_terminfo_init (); +- grub_terminfo_output_register (&grub_console_term_output, "vt100-color"); ++ grub_terminfo_output_register (&grub_console_term_output, ++ (grub_console_term_output.flags & GRUB_TERM_DUMB) ? "dumb":"vt100-color"); + } + + void + grub_console_fini (void) + { ++ dprintf( "grub_console_fini: %d\n", grub_console_term_output.flags & GRUB_TERM_DUMB); + if (saved_orig) + { + fcntl (STDIN_FILENO, F_SETFL, original_fl); + tcsetattr(STDIN_FILENO, TCSANOW, &orig_tty); + } ++ if (!(grub_console_term_output.flags & GRUB_TERM_DUMB)) ++ { ++ const char clear[] = { 0x1b, 'c', 0 }; ++ write (STDOUT_FILENO, clear, 2); ++ } + saved_orig = 0; + } +Index: grub-2.06~rc1/grub-core/normal/menu_text.c +=================================================================== +--- grub-2.06~rc1.orig/grub-core/normal/menu_text.c ++++ grub-2.06~rc1/grub-core/normal/menu_text.c +@@ -113,6 +113,7 @@ draw_border (struct grub_term_output *te + { + int i; + ++ if (! (term->flags & GRUB_TERM_DUMB)) { + grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL); + + grub_term_gotoxy (term, (struct grub_term_coordinate) { geo->first_entry_x - 1, +@@ -142,7 +143,7 @@ draw_border (struct grub_term_output *te + grub_putcode (GRUB_UNICODE_CORNER_LR, term); + + grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL); +- ++ } + grub_term_gotoxy (term, + (struct grub_term_coordinate) { geo->first_entry_x - 1, + (geo->first_entry_y - 1 + geo->num_entries +@@ -155,6 +156,15 @@ print_message (int nested, int edit, str + int ret = 0; + grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL); + ++ if (edit && (term->flags & GRUB_TERM_LINE)) ++ { ++ ret += grub_print_message_indented_real ++ (_("Minimum Emacs-like screen editing is supported. '^i' lists " ++ "completions. Type '^x' to boot, '^c' for a command-line " ++ "or '^[' to discard edits and return to the GRUB menu."), ++ STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run); ++ } ++ else + if (edit) + { + ret += grub_print_message_indented_real (_("Minimum Emacs-like screen editing is \ +@@ -165,10 +175,15 @@ command-line or ESC to discard edits and + } + else + { ++#if defined(__s390x__hotkey) ++ ret += grub_print_message_indented_real ++ (_("Select a menu option by pressing the hotkey specified. "), ++ STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run); ++#else + char *msg_translated; + + msg_translated = grub_xasprintf (_("Use the %C and %C keys to select which " +- "entry is highlighted."), ++ "entry is highlighted. "), + GRUB_UNICODE_UPARROW, + GRUB_UNICODE_DOWNARROW); + if (!msg_translated) +@@ -177,6 +192,7 @@ command-line or ESC to discard edits and + STANDARD_MARGIN, term, dry_run); + + grub_free (msg_translated); ++#endif + + if (nested) + { +@@ -211,6 +227,10 @@ print_entry (int y, int highlight, grub_ + + title = entry ? entry->title : ""; + title_len = grub_strlen (title); ++ ++ if ((data->term->flags & GRUB_TERM_DUMB) && title[0] == '\0') ++ return; ++ + unicode_title = grub_calloc (title_len, sizeof (*unicode_title)); + if (! unicode_title) + /* XXX How to show this error? */ +@@ -244,6 +264,14 @@ print_entry (int y, int highlight, grub_ + if (data->geo.num_entries > 1) + grub_putcode (highlight ? '*' : ' ', data->term); + ++ if ((data->term->flags & GRUB_TERM_LINE) && title[0] != '\0') { ++ grub_putcode('(', data->term); ++ grub_putcode((entry && entry->hotkey >= '0' && entry->hotkey <= 'z') ? ++ entry->hotkey : ' ', data->term); ++ grub_putcode(')', data->term); ++ grub_putcode(' ', data->term); ++ } ++ + grub_print_ucs4_menu (unicode_title, + unicode_title + len, + 0, +@@ -416,6 +444,8 @@ grub_menu_init_page (int nested, int edi + grub_term_highlight_color = old_color_highlight; + geo->timeout_y = geo->first_entry_y + geo->num_entries + + geo->border + empty_lines; ++ if (term->flags & GRUB_TERM_DUMB) ++ geo->timeout_y = 1; + if (bottom_message) + { + grub_term_gotoxy (term, +@@ -425,6 +455,8 @@ grub_menu_init_page (int nested, int edi + print_message (nested, edit, term, 0); + geo->timeout_y += msg_num_lines; + } ++ if (term->flags & GRUB_TERM_DUMB) ++ geo->timeout_y = 1; + geo->right_margin = grub_term_width (term) + - geo->first_entry_x + - geo->entry_width - 1; +@@ -436,12 +468,19 @@ menu_text_print_timeout (int timeout, vo + struct menu_viewer_data *data = dataptr; + char *msg_translated = 0; + +- grub_term_gotoxy (data->term, ++ if (data->geo.timeout_y) ++ grub_term_gotoxy (data->term, + (struct grub_term_coordinate) { 0, data->geo.timeout_y }); + ++ if (data->term->flags & GRUB_TERM_DUMB) ++ { ++ if (! data->geo.timeout_y) ++ data->timeout_msg = TIMEOUT_TERSE; ++ data->geo.timeout_y = 0; ++ } + if (data->timeout_msg == TIMEOUT_TERSE + || data->timeout_msg == TIMEOUT_TERSE_NO_MARGIN) +- msg_translated = grub_xasprintf (_("%ds"), timeout); ++ msg_translated = grub_xasprintf (_(" %ds"), timeout); + else + msg_translated = grub_xasprintf (_("The highlighted entry will be executed automatically in %ds."), timeout); + if (!msg_translated) +@@ -471,6 +510,8 @@ menu_text_print_timeout (int timeout, vo + data->term); + grub_free (msg_translated); + ++ if (data->term->flags & GRUB_TERM_DUMB) ++ return; + grub_term_gotoxy (data->term, + (struct grub_term_coordinate) { + grub_term_cursor_x (&data->geo), +@@ -498,7 +539,7 @@ menu_text_set_chosen_entry (int entry, v + data->first = entry; + complete_redraw = 1; + } +- if (complete_redraw) ++ if (complete_redraw || (data->term->flags & GRUB_TERM_DUMB)) + print_entries (data->menu, data); + else + { +@@ -528,6 +569,9 @@ menu_text_clear_timeout (void *dataptr) + struct menu_viewer_data *data = dataptr; + int i; + ++ if ((data->term->flags & GRUB_TERM_DUMB)) ++ return; ++ + for (i = 0; i < data->geo.timeout_lines;i++) + { + grub_term_gotoxy (data->term, (struct grub_term_coordinate) { +Index: grub-2.06~rc1/grub-core/normal/term.c +=================================================================== +--- grub-2.06~rc1.orig/grub-core/normal/term.c ++++ grub-2.06~rc1/grub-core/normal/term.c +@@ -981,7 +981,7 @@ grub_print_ucs4_menu (const grub_uint32_ + { + print_ucs4_real (str, last_position, margin_left, margin_right, + term, 0, 0, 1, skip_lines, max_lines, +- contchar, 1, pos); ++ contchar, (term->flags & GRUB_TERM_DUMB)? 0 : 1, pos); + } + + void +Index: grub-2.06~rc1/grub-core/kern/emu/main.c +=================================================================== +--- grub-2.06~rc1.orig/grub-core/kern/emu/main.c ++++ grub-2.06~rc1/grub-core/kern/emu/main.c +@@ -190,6 +190,12 @@ static struct argp argp = { + NULL, help_filter, NULL + }; + ++void ++ignore (int num __attribute__ ((unused))) ++{ ++ return; ++} ++ + + + #pragma GCC diagnostic ignored "-Wmissing-prototypes" +@@ -259,7 +265,7 @@ main (int argc, char *argv[]) + sleep (1); + } + +- signal (SIGINT, SIG_IGN); ++ signal (SIGINT, (sighandler_t) &ignore); + grub_console_init (); + grub_host_init (); + +Index: grub-2.06~rc1/include/grub/term.h +=================================================================== +--- grub-2.06~rc1.orig/include/grub/term.h ++++ grub-2.06~rc1/include/grub/term.h +@@ -102,8 +102,10 @@ grub_term_color_state; + #define GRUB_TERM_NO_EDIT (1 << 1) + /* Set when the terminal cannot do fancy things. */ + #define GRUB_TERM_DUMB (1 << 2) ++/* Set when the terminal is line oriented. */ ++#define GRUB_TERM_LINE (1 << 3) + /* Which encoding does terminal expect stream to be. */ +-#define GRUB_TERM_CODE_TYPE_SHIFT 3 ++#define GRUB_TERM_CODE_TYPE_SHIFT 4 + #define GRUB_TERM_CODE_TYPE_MASK (7 << GRUB_TERM_CODE_TYPE_SHIFT) + /* Only ASCII characters accepted. */ + #define GRUB_TERM_CODE_TYPE_ASCII (0 << GRUB_TERM_CODE_TYPE_SHIFT) diff --git a/grub2-s390x-04-grub2-install.patch b/grub2-s390x-04-grub2-install.patch new file mode 100644 index 0000000..9a050bf --- /dev/null +++ b/grub2-s390x-04-grub2-install.patch @@ -0,0 +1,1276 @@ +From: Raymund Will +Subject: Allow s390x-emu to be "installed" +References: fate#314213, bnc#866867, bnc#868909, bnc#874155, bnc#876743, + bnc#879136, bnc#889562, bnc#889572 +Patch-Mainline: no + +V2: + * try harder to find root filesystem (incl. subvol-handling). + * read /etc/sysconfig/bootloader as final fallback. +V3: + * refresh initrd by default, prefer running kernel and + re-zipl despite minor issues. [bnc#866867, fate#314213] +V4: + * append 'quiet splash=silent' for 'initgrub'-boot. + * properly check for dracut script during 'grub2-install'. + * move 'zipl2grub.pl' to '/usr/sbin/grub2-zipl-setup'. +V5: + * actually call 'grub2-zipl-setup' from 'grub2-install'. + * handle 'GRUB{,_EMU}_CONMODE'. [bnc#868909] +V6: + * grub2-zipl-setup: support 'xz' initrd compression. [bnc#874155] +V7: + * dracut-grub2.sh: use 'showconsole' to determine console device. [bnc#876743] + * dracut-grub2.sh: and fall back to '/dev/console' (instead of 'tty1'). + * dracut-grub2.sh: introduce "debug()" helper function. +V8: + * grub2-zipl-setup: replace poor choice in '/sysroot/sys' check. [bnc#879136] + * grub2-zipl-setup: fix typo in '/sysroot/proc' check. +V9: + * grub2-zipl-setup: honor GRUB_DISABLE_LINUX_UUID. [bnc#885854] +V10: + * grub2-zipl-setup: fix stupid typo in previous fix. [bnc#889562, bnc#889572] +V11: + * grub2-zipl-setup: disable 'grub-mkrelpath' acrobatics. [bnc#889572] +V12: + * dracut-grub2.sh: try to mount '/.snapshots' if missing. [bnc#892014] + * dracut-grub2.sh: use '/dev/shm' for debug output, so it's accessible + from grub2-emu's shell. +V13: + * grub2-zipl-setup: make initrd mount '/boot', if needed. [bnc#873951, bnc#892088] + * dracut-grub2.sh: provide /boot from above to grub2-emu in chroot. +V14: + * grub2-zipl-setup: actually remove obsolete kernel/initrds. [bnc#892810] +V15: + * zipl2grub.conf: turn of zipl-prompt and quiescent plymouth. [bsc#898198] +V16: + * dracut-grub2.sh: force read-only '/usr' for kexec. [bsc#932951] +V17: + * grub2-zipl-setup: remove arybase dependency by not referencing $[. [bsc#1055280] +V18: + * dracut-zipl-refresh.sh.in: initial submission. [bsc#1127293] + * dracut-grub2.sh: try to call zipl-refresh on failed kexec and drop + to an emergency shell otherwise +V19: + * dracut-grub2.sh: use 'grep -P' instead of '-E'. [bsc#1136970] +V20: + * dracut-grub2.sh: add support for '/boot/writable'. [bsc#1190395] + + +--- + Makefile.util.def | 46 +++ + configure.ac | 9 + grub-core/Makefile.core.def | 7 + grub-core/osdep/basic/no_platform.c | 7 + grub-core/osdep/unix/platform.c | 11 + grub-core/osdep/windows/platform.c | 6 + include/grub/util/install.h | 4 + util/grub-install-common.c | 1 + util/grub-install.c | 43 +++ + util/s390x/dracut-grub2.sh.in | 141 +++++++++++ + util/s390x/dracut-module-setup.sh.in | 19 + + util/s390x/dracut-zipl-refresh.sh.in | 183 ++++++++++++++ + util/s390x/zipl2grub.conf.in | 26 ++ + util/s390x/zipl2grub.pl.in | 423 +++++++++++++++++++++++++++++++++ + 14 files changed, 923 insertions(+), 3 deletions(-) + +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -374,6 +374,7 @@ program = { + ldadd = grub-core/lib/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; + cppflags = '-DGRUB_SETUP_FUNC=grub_util_bios_setup'; ++ emu_condition = COND_NOT_s390x; + }; + + program = { +@@ -394,6 +395,7 @@ program = { + ldadd = grub-core/lib/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; + cppflags = '-DGRUB_SETUP_FUNC=grub_util_sparc_setup'; ++ emu_condition = COND_NOT_s390x; + }; + + program = { +@@ -409,6 +411,7 @@ program = { + ldadd = libgrubkern.a; + ldadd = grub-core/lib/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ++ emu_condition = COND_NOT_s390x; + }; + + program = { +@@ -439,6 +442,7 @@ program = { + ldadd = libgrubkern.a; + ldadd = grub-core/lib/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ++ emu_condition = COND_NOT_s390x; + }; + + data = { +@@ -656,6 +660,7 @@ program = { + common = grub-core/disk/host.c; + + common = util/resolve.c; ++ emu_condition = COND_s390x; + common = grub-core/kern/emu/argp_common.c; + common = grub-core/osdep/init.c; + +@@ -725,6 +730,46 @@ script = { + }; + + script = { ++ name = grub-zipl-setup; ++ installdir = sbin; ++ common = util/s390x/zipl2grub.pl.in; ++ enable = emu; ++ emu_condition = COND_s390x; ++}; ++ ++data = { ++ name = zipl2grub.conf.in; ++ common = util/s390x/zipl2grub.conf.in; ++ installdir = grubconf; ++ enable = emu; ++ emu_condition = COND_s390x; ++}; ++ ++script = { ++ name = dracut-module-setup.sh; ++ common = util/s390x/dracut-module-setup.sh.in; ++ enable = emu; ++ emu_condition = COND_s390x; ++ installdir = platform; ++}; ++ ++script = { ++ name = dracut-grub.sh; ++ common = util/s390x/dracut-grub2.sh.in; ++ enable = emu; ++ emu_condition = COND_s390x; ++ installdir = platform; ++}; ++ ++script = { ++ name = dracut-zipl-refresh; ++ common = util/s390x/dracut-zipl-refresh.sh.in; ++ enable = emu; ++ emu_condition = COND_s390x; ++ installdir = platform; ++}; ++ ++script = { + name = grub-mkconfig_lib; + common = util/grub-mkconfig_lib.in; + installdir = noinst; +@@ -1342,6 +1387,7 @@ program = { + ldadd = libgrubkern.a; + ldadd = grub-core/lib/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ++ emu_condition = COND_NOT_s390x; + }; + + program = { +--- a/configure.ac ++++ b/configure.ac +@@ -206,9 +206,9 @@ if test x$platform != xemu ; then + esac + fi + +-if test x"$target_cpu-$platform" = xsparc64-emu ; then +- target_m64=1 +-fi ++case x"$target_cpu-$platform" in ++ xsparc64-emu | xs390x-emu) target_m64=1 ;; ++esac + + case "$target_os" in + windows* | mingw32*) target_os=cygwin ;; +@@ -1999,6 +1999,9 @@ AM_CONDITIONAL([COND_riscv32], [test x$t + AM_CONDITIONAL([COND_riscv64], [test x$target_cpu = xriscv64 ]) + AM_CONDITIONAL([COND_riscv32_efi], [test x$target_cpu = xriscv32 -a x$platform = xefi]) + AM_CONDITIONAL([COND_riscv64_efi], [test x$target_cpu = xriscv64 -a x$platform = xefi]) ++AM_CONDITIONAL([COND_s390x], [test x$target_cpu = xs390x ]) ++AM_CONDITIONAL([COND_NOT_s390x], [test x$target_cpu != xs390x ]) ++AM_CONDITIONAL([COND_s390x_emu], [test x$target_cpu = xs390x -a x$platform = xemu]) + + AM_CONDITIONAL([COND_HOST_HURD], [test x$host_kernel = xhurd]) + AM_CONDITIONAL([COND_HOST_LINUX], [test x$host_kernel = xlinux]) +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -1147,6 +1147,7 @@ module = { + module = { + name = videotest; + common = commands/videotest.c; ++ emu_condition = COND_NOT_s390x; + }; + + module = { +@@ -1596,6 +1597,7 @@ module = { + common = gfxmenu/gui_progress_bar.c; + common = gfxmenu/gui_util.c; + common = gfxmenu/gui_string_util.c; ++ emu_condition = COND_NOT_s390x; + }; + + module = { +@@ -2029,11 +2031,13 @@ module = { + name = gfxterm; + common = term/gfxterm.c; + enable = videomodules; ++ emu_condition = COND_NOT_s390x; + }; + + module = { + name = gfxterm_background; + common = term/gfxterm_background.c; ++ emu_condition = COND_NOT_s390x; + }; + + module = { +@@ -2154,6 +2158,7 @@ module = { + enable = x86_64_efi; + enable = emu; + enable = xen; ++ emu_condition = COND_NOT_s390x; + }; + + module = { +@@ -2200,6 +2205,7 @@ module = { + module = { + name = gfxterm_menu; + common = tests/gfxterm_menu.c; ++ emu_condition = COND_NOT_s390x; + }; + + module = { +@@ -2353,6 +2359,7 @@ module = { + enable = x86_64_efi; + enable = emu; + enable = xen; ++ emu_condition = COND_NOT_s390x; + }; + + module = { +--- a/grub-core/osdep/basic/no_platform.c ++++ b/grub-core/osdep/basic/no_platform.c +@@ -44,3 +44,10 @@ grub_install_sgi_setup (const char *inst + { + grub_util_error ("%s", _("no SGI routines are available for your platform")); + } ++ ++void ++grub_install_zipl (const char *d, int i, int f) ++{ ++ grub_util_error ("%s", _("no zIPL routines are available for your platform")); ++} ++ +--- a/grub-core/osdep/unix/platform.c ++++ b/grub-core/osdep/unix/platform.c +@@ -239,3 +239,14 @@ grub_install_sgi_setup (const char *inst + imgfile, destname, NULL }); + grub_util_warn ("%s", _("You will have to set `SystemPartition' and `OSLoader' manually.")); + } ++ ++void ++grub_install_zipl (const char *dest, int install, int force) ++{ ++ if (grub_util_exec ((const char * []){ PACKAGE"-zipl-setup", ++ verbosity ? "-v" : "", ++ install ? "" : "--debug", ++ !force ? "" : "--force", ++ "-z", dest, NULL })) ++ grub_util_error (_("`%s' failed.\n"), PACKAGE"-zipl-setup"); ++} +--- a/grub-core/osdep/windows/platform.c ++++ b/grub-core/osdep/windows/platform.c +@@ -424,3 +424,9 @@ grub_install_sgi_setup (const char *inst + { + grub_util_error ("%s", _("no SGI routines are available for your platform")); + } ++ ++void ++grub_install_zipl (const char *d, int i, int f) ++{ ++ grub_util_error ("%s", _("no zIPL routines are available for your platform")); ++} +--- a/include/grub/util/install.h ++++ b/include/grub/util/install.h +@@ -109,6 +109,7 @@ enum grub_install_plat + GRUB_INSTALL_PLATFORM_ARM_COREBOOT, + GRUB_INSTALL_PLATFORM_RISCV32_EFI, + GRUB_INSTALL_PLATFORM_RISCV64_EFI, ++ GRUB_INSTALL_PLATFORM_S390X_EMU, + GRUB_INSTALL_PLATFORM_MAX + }; + +@@ -236,6 +237,9 @@ void + grub_install_sgi_setup (const char *install_device, + const char *imgfile, const char *destname); + ++void ++grub_install_zipl (const char *d, int i, int f); ++ + int + grub_install_compress_gzip (const char *src, const char *dest); + int +--- a/util/grub-install-common.c ++++ b/util/grub-install-common.c +@@ -902,6 +902,7 @@ static struct + [GRUB_INSTALL_PLATFORM_ARM_COREBOOT] = { "arm", "coreboot" }, + [GRUB_INSTALL_PLATFORM_RISCV32_EFI] = { "riscv32", "efi" }, + [GRUB_INSTALL_PLATFORM_RISCV64_EFI] = { "riscv64", "efi" }, ++ [GRUB_INSTALL_PLATFORM_S390X_EMU] = { "s390x", "emu" }, + }; + + char * +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -66,6 +66,7 @@ static int force_file_id = 0; + static char *disk_module = NULL; + static char *efidir = NULL; + static char *macppcdir = NULL; ++static char *zipldir = NULL; + static int force = 0; + static int have_abstractions = 0; + static int have_cryptodisk = 0; +@@ -106,6 +107,7 @@ enum + OPTION_NO_BOOTSECTOR, + OPTION_NO_RS_CODES, + OPTION_MACPPC_DIRECTORY, ++ OPTION_ZIPL_DIRECTORY, + OPTION_LABEL_FONT, + OPTION_LABEL_COLOR, + OPTION_LABEL_BGCOLOR, +@@ -181,6 +183,11 @@ argp_parser (int key, char *arg, struct + efidir = xstrdup (arg); + return 0; + ++ case OPTION_ZIPL_DIRECTORY: ++ free (zipldir); ++ zipldir = xstrdup (arg); ++ return 0; ++ + case OPTION_DISK_MODULE: + free (disk_module); + disk_module = xstrdup (arg); +@@ -298,6 +305,8 @@ static struct argp_option options[] = { + N_("use DIR as the EFI System Partition root."), 2}, + {"macppc-directory", OPTION_MACPPC_DIRECTORY, N_("DIR"), 0, + N_("use DIR for PPC MAC install."), 2}, ++ {"zipl-directory", OPTION_ZIPL_DIRECTORY, N_("DIR"), 0, ++ N_("use DIR as the zIPL Boot Partition root."), 2}, + {"label-font", OPTION_LABEL_FONT, N_("FILE"), 0, N_("use FILE as font for label"), 2}, + {"label-color", OPTION_LABEL_COLOR, N_("COLOR"), 0, N_("use COLOR for label"), 2}, + {"label-bgcolor", OPTION_LABEL_BGCOLOR, N_("COLOR"), 0, N_("use COLOR for label background"), 2}, +@@ -332,6 +341,8 @@ get_default_platform (void) + #else + return NULL; + #endif ++#elif defined (__s390x__) ++ return "s390x-emu"; + #else + return NULL; + #endif +@@ -507,6 +518,8 @@ have_bootdev (enum grub_install_plat pl) + case GRUB_INSTALL_PLATFORM_I386_XEN: + case GRUB_INSTALL_PLATFORM_X86_64_XEN: + case GRUB_INSTALL_PLATFORM_I386_XEN_PVH: ++ ++ case GRUB_INSTALL_PLATFORM_S390X_EMU: + return 0; + + /* pacify warning. */ +@@ -922,6 +935,7 @@ main (int argc, char *argv[]) + case GRUB_INSTALL_PLATFORM_I386_XEN: + case GRUB_INSTALL_PLATFORM_X86_64_XEN: + case GRUB_INSTALL_PLATFORM_I386_XEN_PVH: ++ case GRUB_INSTALL_PLATFORM_S390X_EMU: + break; + + case GRUB_INSTALL_PLATFORM_I386_QEMU: +@@ -972,6 +986,7 @@ main (int argc, char *argv[]) + case GRUB_INSTALL_PLATFORM_I386_XEN: + case GRUB_INSTALL_PLATFORM_X86_64_XEN: + case GRUB_INSTALL_PLATFORM_I386_XEN_PVH: ++ case GRUB_INSTALL_PLATFORM_S390X_EMU: + free (install_device); + install_device = NULL; + break; +@@ -1247,6 +1262,20 @@ main (int argc, char *argv[]) + } + } + ++ if (platform == GRUB_INSTALL_PLATFORM_S390X_EMU) ++ { ++ if (!zipldir) ++ { ++ char *d = grub_util_path_concat (2, bootdir, "zipl"); ++ if (!grub_util_is_directory (d)) ++ { ++ free (d); ++ grub_util_error ("%s", _("cannot find zIPL directory")); ++ } ++ zipldir = d; ++ } ++ } ++ + grub_install_copy_files (grub_install_source_directory, + grubdir, platform); + +@@ -1496,6 +1525,7 @@ main (int argc, char *argv[]) + case GRUB_INSTALL_PLATFORM_I386_XEN: + case GRUB_INSTALL_PLATFORM_X86_64_XEN: + case GRUB_INSTALL_PLATFORM_I386_XEN_PVH: ++ case GRUB_INSTALL_PLATFORM_S390X_EMU: + grub_util_warn ("%s", _("no hints available for your platform. Expect reduced performance")); + break; + /* pacify warning. */ +@@ -1613,6 +1643,10 @@ main (int argc, char *argv[]) + strcpy (mkimage_target, "sparc64-ieee1275-raw"); + core_name = "core.img"; + break; ++ case GRUB_INSTALL_PLATFORM_S390X_EMU: ++ strcpy (mkimage_target, "grub2-emu"); ++ core_name = mkimage_target; ++ break; + /* pacify warning. */ + case GRUB_INSTALL_PLATFORM_MAX: + break; +@@ -1628,6 +1662,7 @@ main (int argc, char *argv[]) + core_name); + char *prefix = xasprintf ("%s%s", prefix_drive ? : "", + relative_grubdir); ++ if (core_name != mkimage_target) + grub_install_make_image_wrap (/* source dir */ grub_install_source_directory, + /*prefix */ prefix, + /* output */ imgfile, +@@ -1666,6 +1701,10 @@ main (int argc, char *argv[]) + /* image target */ mkimage_target, 0); + } + break; ++ ++ case GRUB_INSTALL_PLATFORM_S390X_EMU: ++ break; ++ + case GRUB_INSTALL_PLATFORM_ARM_EFI: + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: +@@ -1962,6 +2001,10 @@ main (int argc, char *argv[]) + } + break; + ++ case GRUB_INSTALL_PLATFORM_S390X_EMU: ++ grub_install_zipl (zipldir, install_bootsector, force); ++ break; ++ + case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON: + case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS: + case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS: +--- /dev/null ++++ b/util/s390x/dracut-grub2.sh.in +@@ -0,0 +1,141 @@ ++#!/bin/sh ++# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- ++# ex: ts=8 sw=4 sts=4 et filetype=sh ++#getargbool() { true; } ++ ++if getargbool 0 initgrub && [ ! -e /grub2skip ] || [ -e /grub2force ]; then ++ #type getarg >/dev/null 2>&1 || . /lib/dracut-lib.sh ++ checkro() { ++ local tgt="$1" ++ local dev mp fs opts dc ++ local rofs=true ++ while read dev mp fs opts dc; do ++ [ "$mp" = "$tgt" ] || continue ++ case ",$opts," in ++ (*,ro,*) rofs=true;; ++ (*) rofs=false;; ++ esac ++ done < /proc/mounts ++ echo $rofs ++ } ++ checkd() { ++ [ -d $1 ] && echo true || echo false ++ } ++ checke() { ++ [ -e $1 ] && echo true || echo false ++ } ++ checksubvol() { ++ local tgt="$1" ++ local tst="$2" ++ if [ -n "$tst" -a -e "/sysroot$tgt/$tst" ]; then ++ echo true ++ elif grep -qP '^[^#\s]+\s+'"$tgt"'\s+' /sysroot/etc/fstab; then ++ echo false ++ else ++ echo true ++ fi ++ } ++ checksnap() { ++ # checksubvol /.snapshots grub-snapshot.cfg ++ if [ -e /sysroot/.snapshots/grub-snapshot.cfg ]; then ++ echo true ++ elif grep -qP '^[^#\s]+\s+/.snapshots\s+' /sysroot/etc/fstab; then ++ echo false ++ else ++ echo true ++ fi ++ } ++ checkboot() { ++ [ -d /boot/grub2 ] && echo false || echo true ++ } ++ getterm() { ++ local term="$(getarg TERM)" ++ [ -z "$term" ] && term=dumb ++ echo $term ++ } ++ debug() { ++ if [ -n "$1" ]; then ++ echo "$1" >> /dev/.grub2.debug ++ fi ++ shift; ++ [ -n "$*" ] || return 0 ++ echo "+ $*" >> /dev/.grub2.debug ++ "$@" >> /dev/.grub2.debug ++ } ++ ++ exec_prefix=@exec_prefix@ ++ bindir=@bindir@ ++ if [ -e /sysroot$bindir/grub2-emu ]; then ++ ++ export TERM=$(getterm) ++ export grub2rofs=$(checkro /sysroot) ++ export grub2roufs=$(checkro /sysroot/usr) ++ export grub2sysfs=$(checkd /sysroot/sys/devices/system/memory) ++ export grub2procfs=$(checkd /sysroot/proc/self) ++ export grub2bootfs=$(checkboot) ++ export grub2bootw=$(checksubvol /boot/writable) ++ export grub2devfs=$(checkd /sysroot/dev/disk) ++ export grub2snap=$(checksnap) ++ debug "" export -p ++ ++ _ctty="$(RD_DEBUG= getarg rd.ctty=)" && _ctty="/dev/${_ctty##*/}" ++ if [ -z "$_ctty" ]; then ++ _ctty=$(showconsole) ++ fi ++ if [ -z "$_ctty" ]; then ++ _ctty=console ++ while [ -f /sys/class/tty/$_ctty/active ]; do ++ _ctty=$(cat /sys/class/tty/$_ctty/active) ++ _ctty=${_ctty##* } # last one in the list ++ done ++ _ctty=/dev/$_ctty ++ fi ++ [ -c "$_ctty" ] || _ctty=/dev/console ++ case "$(/usr/bin/setsid --help 2>&1)" in *--ctty*) CTTY="--ctty";; esac ++ ++ CTTY="$CTTY --wait" ++ $grub2rofs || mount -o remount,ro /sysroot ++ $grub2roufs || mount -o remount,ro /sysroot/usr ++ $grub2sysfs || mount --bind {,/sysroot}/sys ++ $grub2procfs || mount --bind {,/sysroot}/proc ++ $grub2bootfs || mount --bind {,/sysroot}/boot ++ $grub2devfs || mount --bind {,/sysroot}/dev ++ $grub2snap || chroot /sysroot mount -rn /.snapshots ++ $grub2bootw || chroot /sysroot mount -rn /boot/writable ++ debug "" cat /proc/mounts ++ ++ debug "Trying grub2-emu (ro=$grub2rofs, TERM=$TERM, ctty=$_ctty)..." ++ setsid $CTTY -- chroot /sysroot $bindir/grub2-emu -X -X 0<>$_ctty 1>&0 2>&0 ++ ++ if [ -x /sysroot@libdir@/grub2/zipl-refresh ]; then ++ setsid $CTTY -- /sysroot@libdir@/grub2/zipl-refresh 0<>$_ctty 1>&0 2>&0 ++ if [ $? != 0 ]; then ++ warn "Not continuing" ++ emergency_shell -n grub2-emu-zipl-refresh ++ else ++ echo "+ reboot" >& $_ctty ++ sleep 3 ++ reboot ++ fi ++ else ++ echo " ++ Attention: 'grub2' failed to start the target kernel and 'zipl-refresh' ++ is not available. This should never happen. Please contact support." >& $_ctty ++ warn "Not continuing" ++ emergency_shell -n grub2-emu-kexec ++ fi ++ ++ $grub2snap || umount /sysroot/.snapshots ++ $grub2devfs || umount /sysroot/dev ++ $grub2bootw || umount /sysroot/boot/writable ++ $grub2bootfs || umount /sysroot/boot ++ $grub2procfs || umount /sysroot/proc ++ $grub2sysfs || umount /sysroot/sys ++ $grub2roufs || mount -o remount,rw /sysroot/usr ++ $grub2rofs || mount -o remount,rw /sysroot ++ else ++ warn "No $bindir/grub2-emu in /sysroot--dropping to emergency shell..." ++ emergency_shell -n no-grub2-emu ++ fi ++fi ++ +--- /dev/null ++++ b/util/s390x/dracut-module-setup.sh.in +@@ -0,0 +1,19 @@ ++#!/bin/bash ++# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- ++# ex: ts=8 sw=4 sts=4 et filetype=sh ++ ++# called by dracut ++check() { ++ local _arch=$(uname -m) ++ [ "$_arch" = "s390" -o "$_arch" = "s390x" ] || return 1 ++ return 0 ++} ++ ++# called by dracut ++install() { ++ inst_hook cleanup 99 "$moddir/grub2.sh" ++ inst_multiple showconsole ++ inst_multiple mount umount chroot cat grep /usr/bin/setsid ++ #inst_multiple grub2-emu kexec ++} ++ +--- /dev/null ++++ b/util/s390x/zipl2grub.conf.in +@@ -0,0 +1,26 @@ ++## This is the template for '@zipldir@/config' and is subject to ++## rpm's %config file handling in case of grub2-s390x-emu package update. ++ ++[defaultboot] ++defaultmenu = menu ++ ++[grub2] ++ target = @zipldir@ ++ ramdisk = @zipldir@/initrd,0x2000000 ++ image = @zipldir@/image ++ parameters = "root=@GRUB_DEVICE@ @GRUB_EMU_CONMODE@ @GRUB_CMDLINE_LINUX@ @GRUB_CMDLINE_LINUX_DEFAULT@ initgrub quiet splash=silent plymouth.enable=0 " ++ ++[skip-grub2] ++ target = @zipldir@ ++ ramdisk = @zipldir@/initrd,0x2000000 ++ image = @zipldir@/image ++ parameters = "root=@GRUB_DEVICE@ @GRUB_CONMODE@ @GRUB_CMDLINE_LINUX@ @GRUB_CMDLINE_LINUX_DEFAULT@ " ++ ++:menu ++ target = @zipldir@ ++ timeout = 16 ++ default = 1 ++ prompt = 0 ++ 1 = grub2 ++ 2 = skip-grub2 ++ +--- /dev/null ++++ b/util/s390x/zipl2grub.pl.in +@@ -0,0 +1,423 @@ ++#!/usr/bin/perl ++use strict; ++ ++my $C = $0; $C =~ s{^.*/}{}; ++ ++my $in = '@sysconfdir@/default/zipl2grub.conf.in'; ++my $default = '@sysconfdir@/default/grub'; ++my $fallback = '@sysconfdir@/zipl.conf'; ++my $sysconfbl = '@sysconfdir@/sysconfig/bootloader'; ++my $zipldir = ""; ++my $running = ""; ++my $refresh = 1; # needs to default to "on" until most bugs are shaken out! ++my $force = 0; ++my $verbose = 0; ++my $debug = 0; ++my $miss = 0; ++my $cfg = ""; ++my %fsdev = (); ++my %fstype = (); ++ ++my %C = ( ++ GRUB_CMDLINE_LINUX_DEFAULT => "quiet splash=silent", ++ GRUB_DISABLE_LINUX_UUID => "false", ++); ++ ++my %Mandatory = ( ++ GRUB_CMDLINE_LINUX_DEFAULT => 1, ++ GRUB_DEVICE => 1, ++); ++ ++sub Panic($$) { ++ printf( STDERR "%s", $_[1]); ++ exit( $_[0]); ++} ++sub Info($$) { ++ printf( STDERR "%s", $_[1]) if ($_[0] <= $verbose); ++} ++sub System(@) { ++ my (@C) =@_; ++ Info( 1, "+ " . join( " ", @C) . "\n"); ++ return 0 if ($debug); ++ system( @C); ++ if ($? == -1) { ++ Panic( $?, "$C[0]: Failed to execute: $!\n"); ++ } elsif ($? & 127) { ++ Panic( $?, sprintf( "$C[0]: Died with signal %d with%s coredump\n", ++ ($? & 127), ($? & 128) ? '' : 'out')); ++ } elsif ( $? >> 8 != 0 ) { ++ Panic( $?, "$C[0]: Failed\n"); ++ } ++ return( 0); ++} ++sub cp($$) { ++ my @C = ( "cp", "-p", $_[0], $_[1]); ++ System( @C); ++} ++sub rm($) { ++ return( 0) unless ( -l $_[0] || -e $_[0]); ++ Info( 2, "+ rm $_[0]\n"); ++ return 0 if ($debug); ++ unlink( $_[0]) || Panic( 1, "$C: unlink: $!.\n"); ++} ++sub mv($$) { ++ Info( 1, "+ mv $_[0] $_[1]\n"); ++ return 0 if ($debug); ++ rename($_[0], $_[1]) || Panic( 1, "$C: rename: $!.\n"); ++} ++sub ln($$) { ++ Info( 1, "+ ln -sf $_[0] $_[1]\n"); ++ return 0 if ($debug); ++ unlink( $_[1]) || Panic( 1, "$C: unlink: $!.\n") if ( -e $_[1]); ++ symlink($_[0], $_[1]) || Panic( 1, "$C: symlink: $!.\n"); ++} ++sub BootCopy($$$) { ++ my( $file, $dir, $tgt) = @_; ++ my $curr = "$dir/$tgt"; ++ my $prev = "$dir/$tgt.prev"; ++ Info(4, "Copy /boot/$file $dir $tgt\n"); ++ if ( -l $curr ) { ++ my $curf = readlink( $curr); ++ if ( $curf ne $file ) { ++ if ( -l $prev ) { ++ my $pref = readlink( $prev); ++ $pref = "$dir/$pref" unless ($pref =~ m{^/}); ++ rm( $pref); ++ } ++ mv( $curr, $prev); ++ } ++ } ++ cp( "/boot/$file", "$dir/$file"); ++ ln( $file, $curr); ++} ++sub MkInitrd($$$) { ++ my( $initrd, $dir, $version) = @_; ++ my @C = ( "dracut", "--hostonly", "--force"); ++ my $uuid; ++ if ( exists( $fsdev{"/boot"}) ) { ++ chomp( $uuid = qx{grub2-probe --target=fs_uuid /boot}); ++ my ($dev, $type) = ($fsdev{"/boot"}, $fstype{"/boot"}); ++ if ( $type eq "auto" ) { ++ chomp( $type = qx{grub2-probe --target=fs /boot}); ++ } ++ if ($C{GRUB_DISABLE_LINUX_UUID} eq "true" && ++ $dev =~ m{^(UUID=|/dev/disk/by-uuid/)}) { ++ chomp( $dev = qx{grub2-probe --target=device /boot}); ++ } ++ push @C, "--mount", "$dev /boot $type ro"; ++ } ++ push @C, "$dir/$initrd", $version; ++ System( @C); ++ ln( $initrd, "$dir/initrd"); ++} ++sub ChkInitrd($$) { ++ my( $dir, $initrd) = @_; ++ my $found = -1; ++ my $d = $dir; ++ my $pattern = qr{lib/dracut/hooks/cleanup/99-grub2.sh}; ++ my $show = "cleanup/99-grub2.sh"; ++ my $cat = undef; ++ my $magic; ++ ++ return $found unless (-r "$dir/$initrd"); ++ open( IN, "< $dir/$initrd") || return $found; ++ my $rd = sysread( IN, $magic, 6); ++ close( IN); ++ return $found unless (defined( $rd) && $rd == 6); ++ $cat = "xzcat" if ($magic eq "\xFD7zXZ\x00"); ++ $cat = "zcat" if (substr($magic, 0, 2) eq "\037\213"); ++ $cat = "cat" if (substr($magic, 0, 5) eq "07070"); ++ return $found unless (defined($cat)); ++ ++ my $modinst = "/usr/lib/dracut/modules.d/99grub2/module-setup.sh"; ++ if ( -r $modinst ) { ++ my( $hook, $ord, $script); ++ my $pat = qr{^\s*inst_hook\s+(\S+)\s+([0-9]+)\s+\"\$moddir/(grub2\.sh)\"}; ++ open( IN, "< $modinst") || die; ++ while ( ) { ++ next unless ($_ =~ $pat); ++ $show = "$1/$2-$3"; ++ $pattern = qr{lib/dracut/hooks/$show}o; ++ last; ++ } ++ close( IN); ++ } ++ ++ $found = 0; ++ Info( 3, "+ $cat $d/$initrd | cpio -it | grep '$show'\n"); ++ open( IN, "$cat $d/$initrd | cpio -it 2>/dev/null |") || ++ Panic( 1, "$C: cpio: $!.\n"); ++ while ( ) { ++ $found = 1 if ($_ =~ $pattern); ++ } ++ close( IN); ++ return $found; ++} ++ ++sub Usage($) { ++ my @cat = ("", ++ "Parameter error.", ++ "zIPL directory missing.", ++ "Configuration template missing.", ++ "Configuration template unreadable.", ++ "zIPL directory not accesible.", ++ "" ++ ); ++ my $msg = ""; ++ ++ $msg .= sprintf( "%s: %s\n", $C, $cat[$_[0]]) if ($_[0] > 0); ++ $msg .= "Usage: $C [-v] [-d] [-f] [-T template] [-z ZIPLDIR]\n"; ++ Panic( $_[0], $msg . "\n"); ++} ++ ++while ( $#ARGV >= 0 ) { ++ $_ = shift; ++ next if /^$/; ++ last if /^--$/; ++ (/^--verbose$/ || /^-v$/) && ($verbose++, next); ++ (/^--quiet$/ || /^-q$/) && ($verbose = 0, next); ++ (/^--debug$/ || /^-d$/) && ($debug = 1, $verbose++, next); ++ (/^--force$/ || /^-f$/) && ($force = $refresh = 1, next); ++ (/^--refresh$/ || /^-r$/) && ($refresh = 1, next); ++ (/^--keep$/ || /^-k$/) && ($refresh = 0, next); ++ (/^--?help/ || /^-h/) && (Usage(0)); ++ (/^--zipldir$/ || /^-z$/) && ($zipldir = shift || Usage(2), next); ++ (/^--template$/ || /^-T$/) && ($in = shift || Usage(3), next); ++ (/^-/) && (Usage(1)); ++ Usage(1); ++} ++Usage(4) if (! -r $in); ++ ++if ($zipldir) { ++ $C{zipldir} = $zipldir; # command-line wins ++} elsif ( exists( $C{zipldir}) ) { ++ $zipldir = $C{zipldir}; # otherwise fall back to config ++} else { ++ $zipldir = $C{zipldir} = "/boot/zipl"; # but don't proceed without... ++} ++Usage(5) if (! -d $zipldir); ++if ( $zipldir eq "/boot" ) { ++ Panic( 5, "$C: zIPL directory '/boot' not supported!\n"); ++} ++ ++if ( ! -r $default && ! -r $fallback && ! -r $sysconfbl ) { ++ Panic( 0, "$C: No configuration files found. Retry later!\n"); ++} ++if ( -r $default ) { ++ open( IN, "< $default") || die; ++ while ( ) { ++ chomp; ++ s{^\s*#.*$}{}; ++ next if m{^\s*$}; ++ s{x}{\x01xx\x01}g; ++ s{\\\"}{\x01x1\x01}g; ++ s{\\\'}{\x01x2\x01}g; ++ Info( 5, "<$_>\n"); ++ if ( m{^([^\s=]+)='([^']*)'\s*(?:#.*)?$} || ++ m{^([^\s=]+)="([^"]*)"\s*(?:#.*)?$} || ++ m{^([^\s=]+)=(\S*)\s*(?:#.*)?$} ) { ++ my ( $k, $v) = ($1, $2); ++ $v =~ s{\x01x2\x01}{\\'}g; ++ $v =~ s{\x01x1\x01}{\\"}g; ++ $v =~ s{\x01xx\x01}{x}g; ++ $C{$k} = $v; ++ next; ++ } ++ print( STDERR "$default:$.: parse error ignored.\n"); ++ } ++ close( IN); ++} ++if ( -r "/etc/fstab" ) { ++ my $regex = qr{^(\S+)\s+(\S+)\s+(\S+)\s+\S+\s+\S+\s+\S+\s*(?:#.*)?$}; ++ open( IN, "< /etc/fstab") || die; ++ while ( ) { ++ next if ( m{^\s*#} ); ++ my ($dev, $mp, $type) = (m{$regex}o); ++ $fsdev{$mp} = $dev; ++ $fstype{$mp} = $type; ++ } ++ close( IN); ++} ++ ++if ( ! exists( $C{GRUB_DEVICE}) && ++ $C{GRUB_CMDLINE_LINUX_DEFAULT} eq "quiet splash=silent" && ++ -r $fallback ) { ++ # configuration incomplete, let's try fallback ++ open( IN, "< $fallback") || die; ++ my $section = ""; ++ while( ){ ++ if ( m{^\[([^\]]+)\]\s*$} ) { ++ $section = $1; ++ } ++ if ( $section eq "ipl" && ++ m{^\s*parameters\s*=\s*\"root=(\S+)(?:\s*|\s+([^\"]+))\"} ) { ++ $C{GRUB_DEVICE} = $1; ++ $C{GRUB_CMDLINE_LINUX_DEFAULT} = $2 if (defined($2) && $2 !~ m{^\s*$}); ++ last; ++ } ++ } ++ close( IN); ++ $default = $fallback; ++} ++ ++if ( ! exists( $C{GRUB_DEVICE}) && exists( $fsdev{"/"}) ) { ++ my( $dev, $type, $subvol) = ( $fsdev{"/"}, $fstype{"/"}, ""); ++ if ( $dev !~ m{^(UUID=|/dev/disk/by-uuid/)} || ++ $C{GRUB_DISABLE_LINUX_UUID} ne "true" ) { ++ $C{GRUB_DEVICE} = $dev; ++ # grub2-mkrelpath fails on rollback -- and provides no known merit... ++ #chomp( $subvol = qx{grub2-mkrelpath /}) if ( $type eq "btrfs" ); ++ #$subvol =~ s{^/}{}; ++ #$C{GRUB_DEVICE} .= " rootflags=subvol=$subvol" if ($subvol); ++ } ++} ++if ( ! exists( $C{GRUB_DEVICE}) ) { ++ my( $dev, $uuid, $type, $subvol) = ("", "", "", ""); ++ chomp( $dev = qx{grub2-probe --target=device /}); ++ chomp( $uuid = qx{grub2-probe --device $dev --target=fs_uuid}); ++ if ( $dev ) { ++ if ( $uuid && $C{GRUB_DISABLE_LINUX_UUID} ne "true" ) { ++ $C{GRUB_DEVICE} = "UUID=$uuid"; ++ } else { ++ $C{GRUB_DEVICE} = "$dev"; ++ } ++ chomp( $type = qx{stat -f --printf='%T' /}); ++ # grub2-mkrelpath fails on rollback -- and provides no known merit... ++ #chomp( $subvol = qx{grub2-mkrelpath /}) if ( $type eq "btrfs" ); ++ #$subvol =~ s{^/}{}; ++ #$C{GRUB_DEVICE} .= " rootflags=subvol=$subvol" if ($subvol); ++ } ++} ++if ( $C{GRUB_CMDLINE_LINUX_DEFAULT} eq "quiet splash=silent" && ++ -r $sysconfbl) { ++ open( IN, "< $sysconfbl") || die; ++ while ( ) { ++ next if ( m{^\s*#} ); ++ if ( m{^DEFAULT_APPEND=".*"(?:\s*|\s+#.*)$} ) { ++ $C{GRUB_CMDLINE_LINUX_DEFAULT} = $1; ++ } ++ } ++ close( IN); ++} ++ ++if ( ! exists( $C{GRUB_DEVICE})) { ++ Panic( 0, "$C: Default not ready and no fallback. Please retry later!\n"); ++} ++ ++if ( ! exists( $C{GRUB_EMU_CONMODE}) && exists( $C{GRUB_CONMODE}) ) { ++ # GRUB_CONMODE is used for 'grub2-emu' as well ++ $C{GRUB_EMU_CONMODE} = $C{GRUB_CONMODE}; ++} ++if ( exists( $C{GRUB_EMU_CONMODE}) && !exists( $C{GRUB_CONMODE}) ) { ++ # pick up 'conmode=' from CMDLINE ++ my $found = ""; ++ foreach ( "GRUB_CMDLINE_LINUX", "GRUB_CMDLINE_LINUX_DEFAULT" ) { ++ next unless ($C{$_} =~ m{ ?conmode=(\S+) ?}); ++ $C{GRUB_CONMODE} = $1; ++ last; ++ } ++ if ( !exists( $C{GRUB_CONMODE}) && $C{GRUB_EMU_CONMODE} eq "3270" ) { ++ # force GRUB_CONMODE to 3215 for least surprise ++ $C{GRUB_CONMODE}="3215"; ++ } ++} ++if ( exists( $C{GRUB_EMU_CONMODE}) && exists( $C{GRUB_CONMODE})) { ++ # strip "conmode=" from GRUB_CMDLINE{,_LINUX}_DEFAULT ++ foreach ( "GRUB_CMDLINE_LINUX", "GRUB_CMDLINE_LINUX_DEFAULT" ) { ++ $C{$_} =~ s{( ?)conmode=\S+ ?}{$1}g; ++ } ++} ++foreach ("GRUB_EMU_CONMODE", "GRUB_CONMODE") { ++ next unless( exists( $C{$_}) ); ++ $C{$_} = "conmode=" . $C{$_}; ++} ++ ++if ( $debug && $verbose > 2 ) { ++ foreach ( sort( keys( %C)) ) { ++ printf( "%s=\"%s\"\n", $_, $C{$_}); ++ } ++} ++ ++open( IN, "< $in") || ++ Panic( 1, "$C: Failed to open 'zipl.conf' template: $!.\n"); ++while ( ) { ++ Info( 3, "$.. <$_$.. >"); ++ if ( $. == 1 && m{^## This} ) { ++ $_ = "## This file was written by 'grub2-install/$C'\n" . ++ "## filling '$in' as template\n"; ++ } elsif ( $. == 2 && m{^## rpm's} ) { ++ $_ = "## with values from '$default'.\n" . ++ "## In-place modifications will eventually go missing!\n"; ++ } ++ while ( m{\@([^\@\s]+)\@} ) { ++ my $k = $1; ++ my $v; ++ if ( exists( $C{$k}) ) { ++ $v = $C{$k}; ++ } elsif ( exists( $Mandatory{$k}) ) { ++ $v = "$k"; ++ $miss++; ++ } else { ++ $v = ""; ++ } ++ s{\@$k\@}{$v}g; ++ } ++ Info( 2, $_); ++ $cfg .= $_; ++} ++if ( $miss ) { ++ Info( 1, "Partially filled config:\n===\n$cfg===\n"); ++ Panic( 1, "$C: 'zipl.conf' template could not be filled. \n"); ++} ++ ++my $ziplconf = "$zipldir/config"; ++if ( ! $debug ) { ++ open( OUT, "> $ziplconf") || die; ++ print( OUT $cfg) || die; ++ close( OUT); ++} ++ ++# copy out kernel and initrd ++my $defimage = "/boot/image"; ++my $definitrd = "/boot/initrd"; ++my $ziplimage = "$zipldir/image"; ++my $ziplinitrd = "$zipldir/initrd"; ++my $Image = "$defimage"; ++ ++if ( ! $running && ! $force ) { ++ chomp( $running = qx{uname -r}); ++ Info( 1, "preferred kernel: '$running'\n"); ++ $Image .= "-$running"; ++} ++if ( ! -r $Image ) { ++ $Image = $defimage; ++} ++Panic( 1, "$C: kernel '$Image' not readable!?\n") unless (-r $Image); ++ ++if ( -l $Image ) { ++ $Image = readlink( $Image); ++} ++my ($image, $version) = ($Image =~ m{^(?:/boot/)?([^-]+-(.+))$}); ++my $initrd = "initrd-$version"; ++ ++if ( !defined($image) || !defined($version) || ! -r "/boot/$image" ) { ++ Panic( 1, "$C: weird $Image. This should never happen!\n"); ++} ++ ++if ( ! -r $ziplimage || ! -r $ziplinitrd || $refresh ) { ++ BootCopy( $image, $zipldir, "image"); ++ BootCopy( $initrd, $zipldir, "initrd") if (-r "/boot/$initrd"); ++} ++if ( $refresh || ChkInitrd( $zipldir, "initrd") <= 0 ) { ++ MkInitrd( $initrd, $zipldir, $version); ++} ++if ( ChkInitrd( $zipldir, "initrd") == 0 ) { ++ Info( 0, "$C: dracut does not work as expected! Help needed!\n"); ++ $miss++; ++} ++ ++# now: go for it! ++my @C = ( "/sbin/zipl", (($verbose) ? "-Vnc" : "-nc"), "$ziplconf" ); ++System( @C); ++exit( $miss); ++ +--- /dev/null ++++ b/util/s390x/dracut-zipl-refresh.sh.in +@@ -0,0 +1,183 @@ ++#!/bin/bash ++# ex: ts=8 sw=4 sts=4 et filetype=sh syntax=off ++ ++debug=false ++TIMEOUT=300 ++[ -n "$SYSROOT" ] || ++SYSROOT=/sysroot ++[ -d $SYSROOT/boot ] || SYSROOT= ++ ++sync() { $SYSROOT/usr/bin/sync "$@"; } ++readlink() { $SYSROOT/usr/bin/readlink "$@"; } ++newline() { echo ""; } ++verbose() { ++ local a ++ local m ++ [ -n "$*" ] || return 0 ++ m="+" ++ for a in "$@"; do ++ case "$a" in ++ (*" "*|*" "*|"") m="$m '$a'";; ++ (*) m="$m $a";; ++ esac ++ done ++ echo "$m" ++ [ -n "$SYSROOT" -o "$1" = "chroot" ] || return 0 ++ "$@" ++} ++ ++SYSK="$(readlink $SYSROOT/boot/image)" ++SYSK="${SYSK#image-}" ++ZIPK="$(readlink $SYSROOT/boot/zipl/image)" ++ZIPK="${ZIPK#image-}" ++PRVK="$(readlink $SYSROOT/boot/zipl/image.prev 2> /dev/null)" ++PRVK="${PRVK#image-}" ++RUNK="$(uname -r)" ++# if /boot/zipl is not accessible ZIPK will be empty, assume running kernel ++[ -n "$ZIPK" ] || ZIPK="$RUNK" ++ ++[ -n "$SYSROOT" ] || { ++ echo "$0 is not intended for interactive use!" ++ $debug || ++ exit 0 ++ ## test: ++ TIMEOUT=6 ++ RUNK=110; ZIPK=110; PRVK=101; SYSK=194 ++ ##RUNK=$PRVK; ZIPK=$SYSK # previous booted, newest is default ++ ##t=$ZIPK; ZIPK=$PRVK; PRVK=$t; SYSK=$PRVK # unknown booted ++ ##ZIPK=$SYSK; PRVK="" # no update ++ ##ZIPK=$SYSK # try previous ++ echo "R=$RUNK S=$SYSK Z=$ZIPK P=$PRVK" ++ #verbose echo "a b" z ++ #verbose echo "^h ^j" ^z ++} ++ ++trap newline EXIT ++ ++echo -n " ++ Attention: 'grub2' failed to start the target kernel" ++ ++if [ "$ZIPK" != "$RUNK" -a "$RUNK" != "$SYSK" ]; then ++ # i.e. "previous" has been selected via zipl, but it fails!? ++ [ "$RUNK" = "$PRVK" ] && ++ echo " from previous" || ++ echo " from unknown" ++ ++ echo " ZIPL kernel ($RUNK). If default ($ZIPK) ++ fails as well, please contact support." ++ exit 1 ++fi ++echo "." ++if [ "$ZIPK" = "$SYSK" ]; then ++ [ -z "$PRVK" ] && ++ echo " ++ No kernel update readily available/installed. Please contact support." || ++ echo " ++ You may want to try the previous kernel ($PRVK) with ++ 'IPL ... LOADPARM 4', as no update kernel is readily available/installed." ++ exit 1 ++fi ++ ++echo " ++ A newer kernel ($SYSK) is available and will be deployed ++ in $TIMEOUT seconds. To facilitate this, the affected file-systems have ++ to be made writable, then 'grub2-install --force' needs to be run, ++ and, on success, a 'reboot' will be initiated. ++ ++ Press 'c[Enter]' to interrupt, any other input will proceed... " ++ ++trap interrupted=1 INT ++interrupted=0 ++input="" ++read -t $TIMEOUT input ++case "$input" in ++ ([Cc]) interrupted=2 ;; ++esac ++if [ $interrupted != 0 ]; then ++ echo " ++ Automatic update cancelled..." ++ exit 1 ++fi ++trap - INT ++echo " ++ Attempting automatic update..." ++ ++ismounted() { ++ local mode="$1" ++ local tgt="$2" ++ local dev mp fs opts dc ++ while read dev mp fs opts dc; do ++ [ "$mp" = "$tgt" ] || continue ++ case ",$opts," in ++ (*,$mode,*) return 0;; ++ esac ++ done < /proc/mounts ++ return 1 ++} ++ismp() { ++ local sysr="$1" ++ local tgt="$2" ++ local dev mp fs opts dc ++ while read dev mp fs opts dc; do ++ case "$dev" in ++ ("#"*) continue;; ++ esac ++ [ "$mp" = "$tgt" ] || continue ++ return 0 ++ done < $sysr/etc/fstab ++ return 1 ++} ++chroot() { ++ local tgt="$1"; shift ++ if [ -z "$tgt" ]; then ++ echo -n "+" ++ verbose "$@" ++ else ++ /usr/bin/chroot "$tgt" "$@" ++ fi ++} ++cleanup() { ++ local mp ++ echo " # cleanup" ++ for mp in $UMOUNT; do ++ verbose chroot "$SYSROOT" umount $mp ++ done ++ for mp in $WMOUNT; do ++ verbose mount -o remount,ro $mp ++ done ++ sync; sync ++ [ -z "$EXIT" ] || echo "$EXIT" ++ echo "" ++} ++trap cleanup EXIT ++UMOUNT="" ++WMOUNT="" ++EXIT="" ++ ++echo " # prepare" ++# remount $SYSROOT{,/boot{,/zipl}} read-write ++for mp in {"",/boot{,/zipl}}; do ++ [ -n "$SYSROOT$mp" ] || continue ++ if ismounted rw $SYSROOT$mp; then ++ echo " # $mp: already read-write: ignore" ++ elif ismounted ro $SYSROOT$mp; then ++ verbose mount -o remount,rw $SYSROOT$mp ++ WMOUNT="$SYSROOT$mp $WMOUNT" ++ elif ismp "$SYSROOT" $mp; then ++ verbose chroot "$SYSROOT" mount -w $mp || exit 1 ++ UMOUNT="$mp $UMOUNT" ++ fi ++done ++if [ ! -w $SYSROOT/boot/zipl/config ]; then ++ EXIT="ERROR: $SYSROOT/boot/zipl/config not writable! Aborting..." ++ exit 1 ++fi ++echo " # action" ++verbose chroot "$SYSROOT" grub2-zipl-setup --force ++ret=$? ++if [ $ret != 0 ]; then ++ EXIT=" # failed ($ret)" ++else ++ EXIT=" # done" ++fi ++exit $ret diff --git a/grub2-s390x-05-grub2-mkconfig.patch b/grub2-s390x-05-grub2-mkconfig.patch new file mode 100644 index 0000000..e62454a --- /dev/null +++ b/grub2-s390x-05-grub2-mkconfig.patch @@ -0,0 +1,145 @@ +From: Raymund Will +Subject: Enable grub2-mkconfig for s390x-emu +References: fate#314213, bnc#868909 +Patch-Mainline: no + +V2: + * omit subvolume-prefix for platform "emu" +V3: + * add 'conmode=' to command-line if GRUB_CONMODE exists. [bnc#868909] +V4: + * remove 's' from possible hot-keys for "bootable snapshots". [bnc#885668] + +--- + util/grub.d/10_linux.in | 63 ++++++++++++++++++++++++++++++++++++++---------- + 1 file changed, 51 insertions(+), 12 deletions(-) + +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -63,6 +63,10 @@ + LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID} + fi + ++if [ "x$GRUB_CONMODE" != "x" ]; then ++ GRUB_CMDLINE_LINUX="conmode=${GRUB_CONMODE} ${GRUB_CMDLINE_LINUX}" ++fi ++ + case x"$GRUB_FS" in + xbtrfs) + rootsubvol="`make_system_path_relative_to_its_root /`" +@@ -79,6 +83,21 @@ + + title_correction_code= + ++hotkey=1 ++incr_hotkey() ++{ ++ [ -z "$hotkey" ] && return ++ expr $hotkey + 1 ++} ++print_hotkey() ++{ ++ keys="123456789abdfgijklmnoprtuvwyz" ++ if [ -z "$hotkey" ]||[ $hotkey -eq 0 ]||[ $hotkey -gt 30 ]; then ++ return ++ fi ++ echo "--hotkey=$(expr substr $keys $hotkey 1)" ++} ++ + linux_entry () + { + os="$1" +@@ -108,9 +127,11 @@ + title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;" + grub_warn "$(gettext_printf "Please don't use old title \`%s' for GRUB_DEFAULT, use \`%s' (for versions before 2.00) or \`%s' (for 2.00 or later)" "$GRUB_ACTUAL_DEFAULT" "$replacement_title" "gnulinux-advanced-$boot_device_id>gnulinux-$version-$type-$boot_device_id")" + fi +- echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/" ++ echo "menuentry '$(echo "$title" | grub_quote)' $(print_hotkey) ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/" ++ hotkey=$(incr_hotkey) + else +- echo "menuentry '$(echo "$os" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/" ++ echo "menuentry '$(echo "$os" | grub_quote)' $(print_hotkey) ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/" ++ hotkey=$(incr_hotkey) + fi + if [ x$type != xrecovery ] ; then + save_default_entry | grub_add_tab +@@ -133,6 +154,7 @@ + + echo " insmod gzio" | sed "s/^/$submenu_indentation/" + ++ if [ $PLATFORM != emu ]; then # 'search' does not work for now + if [ x$dirname = x/ ]; then + if [ -z "${prepare_root_cache}" ]; then + prepare_root_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE} | grub_add_tab)" +@@ -144,6 +166,7 @@ + fi + printf '%s\n' "${prepare_boot_cache}" | sed "s/^/$submenu_indentation/" + fi ++ fi + message="$(gettext_printf "Loading Linux %s ..." ${version})" + sed "s/^/$submenu_indentation/" << EOF + echo '$(echo "$message" | grub_quote)' +@@ -168,17 +191,15 @@ + + machine=`uname -m` + case "x$machine" in +- xi?86 | xx86_64) +- list= +- for i in /boot/vmlinuz-* /vmlinuz-* /boot/kernel-* ; do +- if grub_file_is_not_garbage "$i" ; then list="$list $i" ; fi +- done ;; +- *) +- list= +- for i in /boot/vmlinuz-* /boot/vmlinux-* /vmlinuz-* /vmlinux-* /boot/kernel-* ; do +- if grub_file_is_not_garbage "$i" ; then list="$list $i" ; fi +- done ;; ++ xi?86 | xx86_64) klist="/boot/vmlinuz-* /vmlinuz-* /boot/kernel-*" ;; ++ xs390 | xs390x) klist="/boot/image-* /boot/kernel-*" ;; ++ *) klist="/boot/vmlinuz-* /boot/vmlinux-* /vmlinuz-* /vmlinux-* \ ++ /boot/kernel-*" ;; + esac ++list= ++for i in $klist ; do ++ if grub_file_is_not_garbage "$i" ; then list="$list $i" ; fi ++done + + case "$machine" in + i?86) GENKERNEL_ARCH="x86" ;; +@@ -188,6 +209,15 @@ + *) GENKERNEL_ARCH="$machine" ;; + esac + ++PLATFORM="native" ++if [ -d /sys/firmware/efi ]&&[ "x${GRUB_USE_LINUXEFI}" = "xtrue" ]; then ++ PLATFORM="efi" ++else ++ case "$machine" in ++ s390*) PLATFORM="emu" ;; ++ esac ++fi ++ + prepare_boot_cache= + prepare_root_cache= + boot_device_id= +@@ -204,6 +234,11 @@ + basename=`basename $linux` + dirname=`dirname $linux` + rel_dirname=`make_system_path_relative_to_its_root $dirname` ++ if [ $PLATFORM != "emu" ]; then ++ hotkey=0 ++ else ++ rel_dirname=$dirname ++ fi + version=`echo $basename | sed -e "s,^[^0-9]*-,,g"` + alt_version=`echo $version | sed -e "s,\.old$,,g"` + linux_root_device_thisversion="${LINUX_ROOT_DEVICE}" +@@ -319,7 +354,8 @@ + boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" + fi + # TRANSLATORS: %s is replaced with an OS name +- echo "submenu '$(gettext_printf "Advanced options for %s" "${OS}" | grub_quote)' \$menuentry_id_option 'gnulinux-advanced-$boot_device_id' {" ++ echo "submenu '$(gettext_printf "Advanced options for %s" "${OS}" | grub_quote)' $(print_hotkey) \$menuentry_id_option 'gnulinux-advanced-$boot_device_id' {" ++ hotkey=$(incr_hotkey) + is_top_level=false + fi + diff --git a/grub2-s390x-06-loadparm.patch b/grub2-s390x-06-loadparm.patch new file mode 100644 index 0000000..73a0a1e --- /dev/null +++ b/grub2-s390x-06-loadparm.patch @@ -0,0 +1,47 @@ +From: Raymund Will +Subject: Allow s390x-emu to telecontrolled by LOADPARM +References: bsc#892852, bsc#891946 +Patch-Mainline: no + +--- + util/grub.d/00_header.in | 27 +++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +Index: grub-2.02~beta3/util/grub.d/00_header.in +=================================================================== +--- grub-2.02~beta3.orig/util/grub.d/00_header.in ++++ grub-2.02~beta3/util/grub.d/00_header.in +@@ -52,6 +52,33 @@ if [ "\${env_block}" ] ; then + fi + + EOF ++if [ "`uname -m`" = "s390x" ]; then ++ cat <' ++ regexp -s 1:z_1 -s 2:z_2 '^([0-9][0-9>]*)\.([0-9][0-9.]*)$' "\$z_gp" ++ if [ ! "\$z_1" -o ! "\$z_2" ]; then break; fi ++ set z_gp="\$z_1>\$z_2" ++ done ++ if [ ! "\$z_gp" ]; then break; fi ++ set next_entry="\$z_gp" ++ unset z_gp ++ unset loadparm ++ break ++done ++EOF ++fi + if [ "x$GRUB_BUTTON_CMOS_ADDRESS" != "x" ]; then + cat < 0); +- $msg .= "Usage: $C [-v] [-d] [-f] [-T template] [-z ZIPLDIR]\n"; ++ $msg .= "Usage: $C [-v] [-d] [-f] [-T template] [-z ZIPLDIR] [-i imagepath]\n"; + Panic( $_[0], $msg . "\n"); + } + +@@ -184,6 +187,7 @@ while ( $#ARGV >= 0 ) { + (/^--?help/ || /^-h/) && (Usage(0)); + (/^--zipldir$/ || /^-z$/) && ($zipldir = shift || Usage(2), next); + (/^--template$/ || /^-T$/) && ($in = shift || Usage(3), next); ++ (/^--image$/ || /^-i$/) && ($Image = shift || Usage(5), $force = 1, next); + (/^-/) && (Usage(1)); + Usage(1); + } +@@ -379,11 +383,8 @@ if ( ! $debug ) { + } + + # copy out kernel and initrd +-my $defimage = "/boot/image"; +-my $definitrd = "/boot/initrd"; + my $ziplimage = "$zipldir/image"; + my $ziplinitrd = "$zipldir/initrd"; +-my $Image = "$defimage"; + + if ( ! $running && ! $force ) { + chomp( $running = qx{uname -r}); diff --git a/grub2-s390x-08-workaround-part-to-disk.patch b/grub2-s390x-08-workaround-part-to-disk.patch new file mode 100644 index 0000000..eb115e1 --- /dev/null +++ b/grub2-s390x-08-workaround-part-to-disk.patch @@ -0,0 +1,15 @@ +Index: grub-2.02~beta2/grub-core/osdep/linux/getroot.c +=================================================================== +--- grub-2.02~beta2.orig/grub-core/osdep/linux/getroot.c ++++ grub-2.02~beta2/grub-core/osdep/linux/getroot.c +@@ -713,6 +713,10 @@ grub_util_part_to_disk (const char *os_d + if (! realpath (os_dev, path)) + return NULL; + ++#ifdef __s390x__ ++ return path; ++#endif ++ + if (strncmp ("/dev/", path, 5) == 0) + { + char *p = path + 5; diff --git a/grub2-s390x-09-improve-zipl-setup.patch b/grub2-s390x-09-improve-zipl-setup.patch new file mode 100644 index 0000000..bc22c8e --- /dev/null +++ b/grub2-s390x-09-improve-zipl-setup.patch @@ -0,0 +1,209 @@ +--- + util/s390x/zipl2grub.conf.in | 30 +++++++++++++++++++- + util/s390x/zipl2grub.pl.in | 64 +++++++++++++++++++++++++++++-------------- + 2 files changed, 73 insertions(+), 21 deletions(-) + +--- a/util/s390x/zipl2grub.conf.in ++++ b/util/s390x/zipl2grub.conf.in +@@ -10,17 +10,45 @@ defaultmenu = menu + image = @zipldir@/image + parameters = "root=@GRUB_DEVICE@ @GRUB_EMU_CONMODE@ @GRUB_CMDLINE_LINUX@ @GRUB_CMDLINE_LINUX_DEFAULT@ initgrub quiet splash=silent plymouth.enable=0 " + ++[grub2-mem1G] ++ target = @zipldir@ ++ image = @zipldir@/image ++ ramdisk = @zipldir@/initrd,0x2000000 ++ parameters = "root=@GRUB_DEVICE@ @GRUB_EMU_CONMODE@ @GRUB_CMDLINE_LINUX@ @GRUB_CMDLINE_LINUX_DEFAULT@ initgrub quiet splash=silent plymouth.enable=0 mem=1G " ++ + [skip-grub2] + target = @zipldir@ + ramdisk = @zipldir@/initrd,0x2000000 + image = @zipldir@/image + parameters = "root=@GRUB_DEVICE@ @GRUB_CONMODE@ @GRUB_CMDLINE_LINUX@ @GRUB_CMDLINE_LINUX_DEFAULT@ " ++#@ ++#@[grub2-previous] ++#@ target = @zipldir@ ++#@ image = @zipldir@/image.prev ++#@ ramdisk = @zipldir@/initrd.prev,0x2000000 ++#@ parameters = "root=@GRUB_DEVICE@ @GRUB_EMU_CONMODE@ @GRUB_CMDLINE_LINUX@ @GRUB_CMDLINE_LINUX_DEFAULT@ initgrub quiet splash=silent plymouth.enable=0 " ++#@ ++#@[grub2-mem1G-previous] ++#@ target = @zipldir@ ++#@ image = @zipldir@/image.prev ++#@ ramdisk = @zipldir@/initrd.prev,0x2000000 ++#@ parameters = "root=@GRUB_DEVICE@ @GRUB_EMU_CONMODE@ @GRUB_CMDLINE_LINUX@ @GRUB_CMDLINE_LINUX_DEFAULT@ initgrub quiet splash=silent plymouth.enable=0 mem=1G " ++#@ ++#@[skip-grub2-previous] ++#@ target = @zipldir@ ++#@ image = @zipldir@/image.prev ++#@ ramdisk = @zipldir@/initrd.prev,0x2000000 ++#@ parameters = "root=@GRUB_DEVICE@ @GRUB_CONMODE@ @GRUB_CMDLINE_LINUX@ @GRUB_CMDLINE_LINUX_DEFAULT@ " + + :menu + target = @zipldir@ +- timeout = 16 ++ timeout = 60 + default = 1 + prompt = 0 + 1 = grub2 + 2 = skip-grub2 ++ 3 = grub2-mem1G ++#@ 4 = grub2-previous ++#@ 5 = skip-grub2-previous ++#@ 6 = grub2-mem1G-previous + +--- a/util/s390x/zipl2grub.pl.in ++++ b/util/s390x/zipl2grub.pl.in +@@ -10,6 +10,7 @@ my $sysconfbl = '@sysconfdir@/sysconfig/ + my $defimage = "/boot/image"; + my $definitrd = "/boot/initrd"; + my $Image = "$defimage"; ++my $previous = ".prev"; + my $zipldir = ""; + my $running = ""; + my $refresh = 1; # needs to default to "on" until most bugs are shaken out! +@@ -44,12 +45,12 @@ sub System(@) { + return 0 if ($debug); + system( @C); + if ($? == -1) { +- Panic( $?, "$C[0]: Failed to execute: $!\n"); ++ Panic( 1, "$C[0]: Failed to execute: $!\n"); + } elsif ($? & 127) { +- Panic( $?, sprintf( "$C[0]: Died with signal %d with%s coredump\n", ++ Panic( 1, sprintf( "$C[0]: Died with signal %d with%s coredump\n", + ($? & 127), ($? & 128) ? '' : 'out')); + } elsif ( $? >> 8 != 0 ) { +- Panic( $?, "$C[0]: Failed\n"); ++ Panic( $? >> 8, "$C[0]: Failed\n"); + } + return( 0); + } +@@ -74,11 +75,13 @@ sub ln($$) { + unlink( $_[1]) || Panic( 1, "$C: unlink: $!.\n") if ( -e $_[1]); + symlink($_[0], $_[1]) || Panic( 1, "$C: symlink: $!.\n"); + } +-sub BootCopy($$$) { ++ ++sub ManagePrev($$$){ + my( $file, $dir, $tgt) = @_; + my $curr = "$dir/$tgt"; +- my $prev = "$dir/$tgt.prev"; +- Info(4, "Copy /boot/$file $dir $tgt\n"); ++ my $prev = "$dir/$tgt$previous"; ++ my $ret = 0; ++ Info(2, "Manage $prev\n"); + if ( -l $curr ) { + my $curf = readlink( $curr); + if ( $curf ne $file ) { +@@ -88,7 +91,21 @@ sub BootCopy($$$) { + rm( $pref); + } + mv( $curr, $prev); ++ $ret = 1; ++ } else { ++ Info(2, " nothing to do ($curr -> $file).\n"); + } ++ } else { ++ Info(2, " nothing to do ($curr no sym-link).\n"); ++ } ++ return $ret; ++} ++sub BootCopy($$$) { ++ my( $file, $dir, $tgt) = @_; ++ my $curr = "$dir/$tgt"; ++ Info(4, "Copy /boot/$file $dir $tgt\n"); ++ if ( $tgt eq "image" && ManagePrev( $file, $dir, $tgt)) { ++ ManagePrev( $file, $dir, "initrd") + } + cp( "/boot/$file", "$dir/$file"); + ln( $file, $curr); +@@ -163,7 +180,9 @@ sub Usage($) { + "zIPL directory missing.", + "Configuration template missing.", + "Configuration template unreadable.", +- "zIPL directory not accesible.", ++ "zIPL directory not accessible.", ++ "kernel image parameter missing.", ++ "kernel image unreadable.", + "" + ); + my $msg = ""; +@@ -186,7 +205,8 @@ while ( $#ARGV >= 0 ) { + (/^--?help/ || /^-h/) && (Usage(0)); + (/^--zipldir$/ || /^-z$/) && ($zipldir = shift || Usage(2), next); + (/^--template$/ || /^-T$/) && ($in = shift || Usage(3), next); +- (/^--image$/ || /^-i$/) && ($Image = shift || Usage(5), $force = 1, next); ++ (/^--image$/ || /^-i$/) && ($Image = shift || Usage(6), ++ -r "$Image" || Usage(7), $force = 1, next); + (/^-/) && (Usage(1)); + Usage(1); + } +@@ -345,7 +365,7 @@ if ( $debug && $verbose > 2 ) { + open( IN, "< $in") || + Panic( 1, "$C: Failed to open 'zipl.conf' template: $!.\n"); + while ( ) { +- Info( 3, "$.. <$_$.. >"); ++ Info( 4, "$.. <$_$.. >"); + if ( $. == 1 && m{^## This} ) { + $_ = "## This file was written by 'grub2-install/$C'\n" . + "## filling '$in' as template\n"; +@@ -366,7 +386,7 @@ while ( ) { + } + s{\@$k\@}{$v}g; + } +- Info( 2, $_); ++ Info( 3, $_); + $cfg .= $_; + } + if ( $miss ) { +@@ -374,13 +394,6 @@ if ( $miss ) { + Panic( 1, "$C: 'zipl.conf' template could not be filled. \n"); + } + +-my $ziplconf = "$zipldir/config"; +-if ( ! $debug ) { +- open( OUT, "> $ziplconf") || die; +- print( OUT $cfg) || die; +- close( OUT); +-} +- + # copy out kernel and initrd + my $ziplimage = "$zipldir/image"; + my $ziplinitrd = "$zipldir/initrd"; +@@ -399,15 +412,15 @@ if ( -l $Image ) { + $Image = readlink( $Image); + } + my ($image, $version) = ($Image =~ m{^(?:/boot/)?([^-]+-(.+))$}); +-my $initrd = "initrd-$version"; +- + if ( !defined($image) || !defined($version) || ! -r "/boot/$image" ) { + Panic( 1, "$C: weird $Image. This should never happen!\n"); + } ++my $initrd = "initrd-$version"; + + if ( ! -r $ziplimage || ! -r $ziplinitrd || $refresh ) { + BootCopy( $image, $zipldir, "image"); +- BootCopy( $initrd, $zipldir, "initrd") if (-r "/boot/$initrd"); ++ BootCopy( $initrd, $zipldir, "initrd") ++ if (-r "/boot/$initrd" && ! exists( $fsdev{"/boot"})); + } + if ( $refresh || ChkInitrd( $zipldir, "initrd") <= 0 ) { + MkInitrd( $initrd, $zipldir, $version); +@@ -417,6 +430,17 @@ if ( ChkInitrd( $zipldir, "initrd") == 0 + $miss++; + } + ++# write zipl config file ++my $ziplconf = "$zipldir/config"; ++$cfg =~ s{#@}{}g if ( -r "$ziplimage$previous" && -r "$ziplinitrd$previous" ); ++if ( ! $debug ) { ++ open( OUT, "> $ziplconf") || die; ++ print( OUT $cfg) || die; ++ close( OUT); ++} else { ++ print( STDERR $cfg); ++} ++ + # now: go for it! + my @C = ( "/sbin/zipl", (($verbose) ? "-Vnc" : "-nc"), "$ziplconf" ); + System( @C); diff --git a/grub2-s390x-10-keep-network-at-kexec.patch b/grub2-s390x-10-keep-network-at-kexec.patch new file mode 100644 index 0000000..ff66df2 --- /dev/null +++ b/grub2-s390x-10-keep-network-at-kexec.patch @@ -0,0 +1,17 @@ +Index: grub-2.02/grub-core/loader/emu/linux.c +=================================================================== +--- grub-2.02.orig/grub-core/loader/emu/linux.c ++++ grub-2.02/grub-core/loader/emu/linux.c +@@ -76,9 +76,10 @@ grub_linux_boot (void) + grub_fatal (N_("Error trying to perform 'systemctl kexec'")); + + /* need to check read-only root before resetting hard!? */ +- grub_printf("Performing 'kexec -e'"); ++ grub_printf("Performing 'kexec -e -x'"); + kexec[1] = "-e"; +- kexec[2] = NULL; ++ kexec[2] = "-x"; ++ kexec[3] = NULL; + rc = grub_util_exec(kexec); + if ( rc != GRUB_ERR_NONE ) + grub_fatal (N_("Error trying to directly perform 'kexec -e'.")); diff --git a/grub2-s390x-11-secureboot.patch b/grub2-s390x-11-secureboot.patch new file mode 100644 index 0000000..b6805a9 --- /dev/null +++ b/grub2-s390x-11-secureboot.patch @@ -0,0 +1,153 @@ +--- + grub-core/loader/emu/linux.c | 4 ++-- + util/s390x/dracut-grub2.sh.in | 14 ++++++++++++-- + util/s390x/zipl2grub.conf.in | 1 + + util/s390x/zipl2grub.pl.in | 31 ++++++++++++++++++++++--------- + 4 files changed, 37 insertions(+), 13 deletions(-) + +--- a/grub-core/loader/emu/linux.c ++++ b/grub-core/loader/emu/linux.c +@@ -38,7 +38,7 @@ grub_linux_boot (void) + { + grub_err_t rc = GRUB_ERR_NONE; + char *initrd_param; +- const char *kexec[] = { "kexec", "-l", kernel_path, boot_cmdline, NULL, NULL }; ++ const char *kexec[] = { "kexec", "-la", kernel_path, boot_cmdline, NULL, NULL }; + const char *systemctl[] = { "systemctl", "kexec", NULL }; + int kexecute = grub_util_get_kexecute(); + +@@ -51,7 +51,7 @@ grub_linux_boot (void) + //return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("initrd required!")); + } + +- grub_printf("%serforming 'kexec -l %s %s %s'\n", ++ grub_printf("%serforming 'kexec -la %s %s %s'\n", + (kexecute) ? "P" : "Not p", + kernel_path, initrd_param, boot_cmdline); + +--- a/util/s390x/dracut-grub2.sh.in ++++ b/util/s390x/dracut-grub2.sh.in +@@ -18,6 +18,9 @@ if getargbool 0 initgrub && [ ! -e /grub + done < /proc/mounts + echo $rofs + } ++ checkcat() { ++ [ -r $1 ] && cat $1 ++ } + checkd() { + [ -d $1 ] && echo true || echo false + } +@@ -76,6 +79,7 @@ if getargbool 0 initgrub && [ ! -e /grub + export grub2bootw=$(checksubvol /boot/writable) + export grub2devfs=$(checkd /sysroot/dev/disk) + export grub2snap=$(checksnap) ++ export grub2secure=$(checkcat /sys/firmware/ipl/secure) + debug "" export -p + + _ctty="$(RD_DEBUG= getarg rd.ctty=)" && _ctty="/dev/${_ctty##*/}" +@@ -107,7 +111,7 @@ if getargbool 0 initgrub && [ ! -e /grub + debug "Trying grub2-emu (ro=$grub2rofs, TERM=$TERM, ctty=$_ctty)..." + setsid $CTTY -- chroot /sysroot $bindir/grub2-emu -X -X 0<>$_ctty 1>&0 2>&0 + +- if [ -x /sysroot@libdir@/grub2/zipl-refresh ]; then ++ if [ "$grub2secure" != 1 ]&&[ -x /sysroot@libdir@/grub2/zipl-refresh ]; then + setsid $CTTY -- /sysroot@libdir@/grub2/zipl-refresh 0<>$_ctty 1>&0 2>&0 + if [ $? != 0 ]; then + warn "Not continuing" +@@ -117,12 +121,18 @@ if getargbool 0 initgrub && [ ! -e /grub + sleep 3 + reboot + fi +- else ++ elif [ "$grub2secure" != 1 ]; then + echo " + Attention: 'grub2' failed to start the target kernel and 'zipl-refresh' + is not available. This should never happen. Please contact support." >& $_ctty + warn "Not continuing" + emergency_shell -n grub2-emu-kexec ++ else ++ echo " ++ Attention: 'grub2' failed to start the target kernel and secure boot seems ++ active. Automatic recovery not available. Please contact support." >& $_ctty ++ warn "Not continuing" ++ emergency_shell -n grub2-emu-kexec + fi + + $grub2snap || umount /sysroot/.snapshots +--- a/util/s390x/zipl2grub.conf.in ++++ b/util/s390x/zipl2grub.conf.in +@@ -45,6 +45,7 @@ defaultmenu = menu + timeout = 60 + default = 1 + prompt = 0 ++ secure = @SUSE_SECURE_BOOT@ + 1 = grub2 + 2 = skip-grub2 + 3 = grub2-mem1G +--- a/util/s390x/zipl2grub.pl.in ++++ b/util/s390x/zipl2grub.pl.in +@@ -21,6 +21,7 @@ my $miss = 0; + my $cfg = ""; + my %fsdev = (); + my %fstype = (); ++my %SBL = (); # key/value of $sysconfbl + + my %C = ( + GRUB_CMDLINE_LINUX_DEFAULT => "quiet splash=silent", +@@ -251,6 +252,15 @@ if ( -r $default ) { + } + close( IN); + } ++if ( -r $sysconfbl ) { ++ open( IN, "< $sysconfbl") || die; ++ while ( ) { ++ next if ( m{^\s*#} ); ++ next unless ( m{^\s*([^=#\s]+)="(.*)"(?:\s*|\s+#.*)$} ); ++ $SBL{$1} = $2; ++ } ++ close( IN); ++} + if ( -r "/etc/fstab" ) { + my $regex = qr{^(\S+)\s+(\S+)\s+(\S+)\s+\S+\s+\S+\s+\S+\s*(?:#.*)?$}; + open( IN, "< /etc/fstab") || die; +@@ -313,21 +323,21 @@ if ( ! exists( $C{GRUB_DEVICE}) ) { + } + } + if ( $C{GRUB_CMDLINE_LINUX_DEFAULT} eq "quiet splash=silent" && +- -r $sysconfbl) { +- open( IN, "< $sysconfbl") || die; +- while ( ) { +- next if ( m{^\s*#} ); +- if ( m{^DEFAULT_APPEND=".*"(?:\s*|\s+#.*)$} ) { +- $C{GRUB_CMDLINE_LINUX_DEFAULT} = $1; +- } +- } +- close( IN); ++ exists( $SBL{DEFAULT_APPEND}) ) { ++ $C{GRUB_CMDLINE_LINUX_DEFAULT} = $SBL{DEFAULT_APPEND}; + } + + if ( ! exists( $C{GRUB_DEVICE})) { + Panic( 0, "$C: Default not ready and no fallback. Please retry later!\n"); + } + ++if ( !exists( $C{SUSE_SECURE_BOOT}) ) { ++ $C{SUSE_SECURE_BOOT} = "0"; ++ if ( exists( $SBL{SECURE_BOOT}) && $SBL{SECURE_BOOT} =~ m{^(yes|true|1)$} ) { ++ $C{SUSE_SECURE_BOOT} = "1"; ++ } ++} ++ + if ( ! exists( $C{GRUB_EMU_CONMODE}) && exists( $C{GRUB_CONMODE}) ) { + # GRUB_CONMODE is used for 'grub2-emu' as well + $C{GRUB_EMU_CONMODE} = $C{GRUB_CONMODE}; +@@ -360,6 +370,9 @@ if ( $debug && $verbose > 2 ) { + foreach ( sort( keys( %C)) ) { + printf( "%s=\"%s\"\n", $_, $C{$_}); + } ++ foreach ( sort( keys( %SBL)) ) { ++ printf( "SBL: %s=\"%s\"\n", $_, $SBL{$_}); ++ } + } + + open( IN, "< $in") || diff --git a/grub2-s390x-skip-zfcpdump-image.patch b/grub2-s390x-skip-zfcpdump-image.patch new file mode 100644 index 0000000..71b82b4 --- /dev/null +++ b/grub2-s390x-skip-zfcpdump-image.patch @@ -0,0 +1,17 @@ +Index: grub-2.04/util/grub-mkconfig_lib.in +=================================================================== +--- grub-2.04.orig/util/grub-mkconfig_lib.in ++++ grub-2.04/util/grub-mkconfig_lib.in +@@ -189,6 +189,12 @@ grub_file_is_not_garbage () + *.rpmsave|*.rpmnew) return 1 ;; + README*|*/README*) return 1 ;; # documentation + *.sig) return 1 ;; # signatures ++ # Skip zfcpdump kernel from the grub boot menu (bsc#1166513) The zfcpdump ++ # kernel image is used by zipl to prepare a SCSI dump disc and is only ++ # intended to boot from that disk for creating kernel crash dumps, ++ # therefore booting it from grub is not making sense and also will result ++ # in unbootable system. ++ *-zfcpdump) return 1 ;; # s390 zfcpdump image + esac + else + return 1 diff --git a/grub2-secureboot-add-linuxefi.patch b/grub2-secureboot-add-linuxefi.patch new file mode 100644 index 0000000..7f82007 --- /dev/null +++ b/grub2-secureboot-add-linuxefi.patch @@ -0,0 +1,458 @@ +From: Matthew Garrett +Date: 2012-07-10 11:58:52 EDT +Subject: [PATCH] Add support for linuxefi + +References: fate#314485 +Patch-Mainline: no + +Signed-off-by: Michael Chang + +v2: Adjust patch according to new upstream commits +4d4a8c96e verifiers: Add possibility to verify kernel and modules command lines +ca0a4f689 verifiers: File type for fine-grained signature-verification controlling +7d36709d5 i386: make struct linux_kernel_header architecture specific +4bc909bf8 Remove grub_efi_allocate_pages. +v3: +The upstream commit + +df84d6e94 efi: Print error messages to grub_efi_allocate_pages_real() + +adds grub_error() to set error message and return grub_errno. We have to +unset the grub_errno if we want to ignore the error and proceed, or +the inadvertently provoked error handler would lead to unspecified +consequence. + +--- + grub-core/Makefile.core.def | 8 + + grub-core/kern/efi/mm.c | 32 ++++ + grub-core/loader/i386/efi/linux.c | 371 +++++++++++++++++++++++++++++++++++++ + include/grub/efi/efi.h | 3 + + include/grub/i386/linux.h | 1 + + 5 files changed, 415 insertions(+), 0 deletions(-) + create mode 100644 grub-core/loader/i386/efi/linux.c + +Index: grub-2.06/grub-core/Makefile.core.def +=================================================================== +--- grub-2.06.orig/grub-core/Makefile.core.def ++++ grub-2.06/grub-core/Makefile.core.def +@@ -1875,6 +1875,13 @@ module = { + }; + + module = { ++ name = linuxefi; ++ efi = loader/i386/efi/linux.c; ++ enable = i386_efi; ++ enable = x86_64_efi; ++}; ++ ++module = { + name = chain; + efi = loader/efi/chainloader.c; + i386_pc = loader/i386/pc/chainloader.c; +Index: grub-2.06/grub-core/kern/efi/mm.c +=================================================================== +--- grub-2.06.orig/grub-core/kern/efi/mm.c ++++ grub-2.06/grub-core/kern/efi/mm.c +@@ -113,6 +113,38 @@ grub_efi_drop_alloc (grub_efi_physical_a + } + } + ++/* Allocate pages below a specified address */ ++void * ++grub_efi_allocate_pages_max (grub_efi_physical_address_t max, ++ grub_efi_uintn_t pages) ++{ ++ grub_efi_status_t status; ++ grub_efi_boot_services_t *b; ++ grub_efi_physical_address_t address = max; ++ ++ if (max > 0xffffffff) ++ return 0; ++ ++ b = grub_efi_system_table->boot_services; ++ status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, GRUB_EFI_LOADER_DATA, pages, &address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ ++ if (address == 0) ++ { ++ /* Uggh, the address 0 was allocated... This is too annoying, ++ so reallocate another one. */ ++ address = max; ++ status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, GRUB_EFI_LOADER_DATA, pages, &address); ++ grub_efi_free_pages (0, pages); ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ } ++ ++ return (void *) ((grub_addr_t) address); ++} ++ + /* Allocate pages. Return the pointer to the first of allocated pages. */ + void * + grub_efi_allocate_pages_real (grub_efi_physical_address_t address, +Index: grub-2.06/grub-core/loader/i386/efi/linux.c +=================================================================== +--- /dev/null ++++ grub-2.06/grub-core/loader/i386/efi/linux.c +@@ -0,0 +1,345 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2012 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 . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static grub_dl_t my_mod; ++static int loaded; ++static void *kernel_mem; ++static grub_uint64_t kernel_size; ++static grub_uint8_t *initrd_mem; ++static grub_uint32_t handover_offset; ++struct linux_kernel_params *params; ++static char *linux_cmdline; ++ ++#define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) ++ ++typedef void(*handover_func)(void *, grub_efi_system_table_t *, struct linux_kernel_params *); ++ ++static grub_err_t ++grub_linuxefi_boot (void) ++{ ++ handover_func hf; ++ int offset = 0; ++ ++#ifdef __x86_64__ ++ offset = 512; ++#endif ++ ++ hf = (handover_func)((char *)kernel_mem + handover_offset + offset); ++ ++ asm volatile ("cli"); ++ ++ hf (grub_efi_image_handle, grub_efi_system_table, params); ++ ++ /* Not reached */ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_linuxefi_unload (void) ++{ ++ grub_dl_unref (my_mod); ++ loaded = 0; ++ if (initrd_mem) ++ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)initrd_mem, BYTES_TO_PAGES(params->ramdisk_size)); ++ if (linux_cmdline) ++ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)linux_cmdline, BYTES_TO_PAGES(params->cmdline_size + 1)); ++ if (kernel_mem) ++ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)kernel_mem, BYTES_TO_PAGES(kernel_size)); ++ if (params) ++ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)params, BYTES_TO_PAGES(16384)); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), ++ int argc, char *argv[]) ++{ ++ grub_file_t *files = 0; ++ int i, nfiles = 0; ++ grub_size_t size = 0; ++ grub_uint8_t *ptr; ++ ++ if (argc == 0) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); ++ goto fail; ++ } ++ ++ if (!loaded) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first")); ++ goto fail; ++ } ++ ++ files = grub_zalloc (argc * sizeof (files[0])); ++ if (!files) ++ goto fail; ++ ++ for (i = 0; i < argc; i++) ++ { ++ files[i] = grub_file_open (argv[i], GRUB_FILE_TYPE_LINUX_INITRD ++ | GRUB_FILE_TYPE_NO_DECOMPRESS); ++ if (! files[i]) ++ goto fail; ++ nfiles++; ++ size += ALIGN_UP (grub_file_size (files[i]), 4); ++ } ++ ++ initrd_mem = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(size)); ++ ++ if (!initrd_mem) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd")); ++ goto fail; ++ } ++ ++ params->ramdisk_size = size; ++ params->ramdisk_image = (grub_uint32_t)(grub_addr_t) initrd_mem; ++ ++ ptr = initrd_mem; ++ ++ for (i = 0; i < nfiles; i++) ++ { ++ grub_ssize_t cursize = grub_file_size (files[i]); ++ if (grub_file_read (files[i], ptr, cursize) != cursize) ++ { ++ if (!grub_errno) ++ grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), ++ argv[i]); ++ goto fail; ++ } ++ ptr += cursize; ++ grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4)); ++ ptr += ALIGN_UP_OVERHEAD (cursize, 4); ++ } ++ ++ params->ramdisk_size = size; ++ ++ fail: ++ for (i = 0; i < nfiles; i++) ++ grub_file_close (files[i]); ++ grub_free (files); ++ ++ if (initrd_mem && grub_errno) ++ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)initrd_mem, BYTES_TO_PAGES(size)); ++ ++ return grub_errno; ++} ++ ++static grub_err_t ++grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), ++ int argc, char *argv[]) ++{ ++ grub_file_t file = 0; ++ struct linux_i386_kernel_header lh; ++ grub_ssize_t len, start, filelen; ++ void *kernel; ++ grub_err_t err; ++ ++ grub_dl_ref (my_mod); ++ ++ if (argc == 0) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); ++ goto fail; ++ } ++ ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); ++ if (! file) ++ goto fail; ++ ++ filelen = grub_file_size (file); ++ ++ kernel = grub_malloc(filelen); ++ ++ if (!kernel) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer")); ++ goto fail; ++ } ++ ++ if (grub_file_read (file, kernel, filelen) != filelen) ++ { ++ grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), argv[0]); ++ goto fail; ++ } ++ ++ grub_file_seek (file, 0); ++ ++ grub_free(kernel); ++ ++ params = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(16384)); ++ ++ if (! params) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); ++ goto fail; ++ } ++ ++ grub_memset (params, 0, 16384); ++ ++ if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) ++ { ++ if (!grub_errno) ++ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), ++ argv[0]); ++ goto fail; ++ } ++ ++ if (lh.boot_flag != grub_cpu_to_le16 (0xaa55)) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("invalid magic number")); ++ goto fail; ++ } ++ ++ if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("too many setup sectors")); ++ goto fail; ++ } ++ ++ if (lh.version < grub_cpu_to_le16 (0x020b)) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("kernel too old")); ++ goto fail; ++ } ++ ++ if (!lh.handover_offset) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("kernel doesn't support EFI handover")); ++ goto fail; ++ } ++ ++ linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff, ++ BYTES_TO_PAGES(lh.cmdline_size + 1)); ++ ++ if (!linux_cmdline) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline")); ++ goto fail; ++ } ++ ++ grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); ++ err = grub_create_loader_cmdline (argc, argv, ++ linux_cmdline + sizeof (LINUX_IMAGE) - 1, ++ lh.cmdline_size - (sizeof (LINUX_IMAGE) - 1), ++ GRUB_VERIFY_KERNEL_CMDLINE); ++ if (err) ++ goto fail; ++ ++ lh.cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline; ++ ++ handover_offset = lh.handover_offset; ++ ++ start = (lh.setup_sects + 1) * 512; ++ len = grub_file_size(file) - start; ++ ++ kernel_mem = grub_efi_allocate_fixed (lh.pref_address, ++ BYTES_TO_PAGES(lh.init_size)); ++ ++ if (!kernel_mem) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ kernel_mem = grub_efi_allocate_pages_max(0x3fffffff, ++ BYTES_TO_PAGES(lh.init_size)); ++ } ++ ++ if (!kernel_mem) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel")); ++ goto fail; ++ } ++ ++ if (grub_file_seek (file, start) == (grub_off_t) -1) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), ++ argv[0]); ++ goto fail; ++ } ++ ++ if (grub_file_read (file, kernel_mem, len) != len && !grub_errno) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), ++ argv[0]); ++ } ++ ++ if (grub_errno == GRUB_ERR_NONE) ++ { ++ grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); ++ loaded = 1; ++ lh.code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem; ++ } ++ ++ grub_memcpy(params, &lh, 2 * 512); ++ ++ params->type_of_loader = 0x21; ++ ++ fail: ++ ++ if (file) ++ grub_file_close (file); ++ ++ if (grub_errno != GRUB_ERR_NONE) ++ { ++ grub_dl_unref (my_mod); ++ loaded = 0; ++ } ++ ++ if (linux_cmdline && !loaded) ++ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)linux_cmdline, BYTES_TO_PAGES(lh.cmdline_size + 1)); ++ ++ if (kernel_mem && !loaded) ++ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)kernel_mem, BYTES_TO_PAGES(kernel_size)); ++ ++ if (params && !loaded) ++ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)params, BYTES_TO_PAGES(16384)); ++ ++ return grub_errno; ++} ++ ++static grub_command_t cmd_linux, cmd_initrd; ++ ++GRUB_MOD_INIT(linuxefi) ++{ ++ cmd_linux = ++ grub_register_command ("linuxefi", grub_cmd_linux, ++ 0, N_("Load Linux.")); ++ cmd_initrd = ++ grub_register_command ("initrdefi", grub_cmd_initrd, ++ 0, N_("Load initrd.")); ++ my_mod = mod; ++} ++ ++GRUB_MOD_FINI(linuxefi) ++{ ++ grub_unregister_command (cmd_linux); ++ grub_unregister_command (cmd_initrd); ++} +Index: grub-2.06/include/grub/efi/efi.h +=================================================================== +--- grub-2.06.orig/include/grub/efi/efi.h ++++ grub-2.06/include/grub/efi/efi.h +@@ -47,6 +47,9 @@ EXPORT_FUNC(grub_efi_allocate_fixed) (gr + grub_efi_uintn_t pages); + void * + EXPORT_FUNC(grub_efi_allocate_any_pages) (grub_efi_uintn_t pages); ++void * ++EXPORT_FUNC(grub_efi_allocate_pages_max) (grub_efi_physical_address_t max, ++ grub_efi_uintn_t pages); + void EXPORT_FUNC(grub_efi_free_pages) (grub_efi_physical_address_t address, + grub_efi_uintn_t pages); + grub_efi_uintn_t EXPORT_FUNC(grub_efi_find_mmap_size) (void); diff --git a/grub2-secureboot-chainloader.patch b/grub2-secureboot-chainloader.patch new file mode 100644 index 0000000..28c51e2 --- /dev/null +++ b/grub2-secureboot-chainloader.patch @@ -0,0 +1,643 @@ +From 06ff1079788fedac5e3f1f12ed7bbe69228a7ae0 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Tue, 18 Dec 2012 16:54:03 +0800 +Subject: [PATCH] Add secureboot support on efi chainloader + +References: fate#314485 +Patch-Mainline: no + +Expand the chainloader to be able to verify the image by means of shim +lock protocol. The PE/COFF image is loaded and relocated by the +chainloader instead of calling LoadImage and StartImage UEFI boot +Service as they require positive verification result from keys enrolled +in KEK or DB. The shim will use MOK in addition to firmware enrolled +keys to verify the image. + +The chainloader module could be used to load other UEFI bootloaders, +such as xen.efi, and could be signed by any of MOK, KEK or DB. + +v1: +Use grub_efi_get_secureboot to get secure boot status + +Signed-off-by: Michael Chang +--- + grub-core/loader/efi/chainloader.c | 538 +++++++++++++++++++++++++++++++++-- + 1 files changed, 507 insertions(+), 31 deletions(-) + +Index: grub-2.04/grub-core/loader/efi/chainloader.c +=================================================================== +--- grub-2.04.orig/grub-core/loader/efi/chainloader.c ++++ grub-2.04/grub-core/loader/efi/chainloader.c +@@ -40,15 +40,32 @@ + #include + #endif + ++#ifdef __x86_64__ ++#define SUPPORT_SECURE_BOOT ++#endif ++ ++#ifdef SUPPORT_SECURE_BOOT ++#include ++#include ++#endif ++ + GRUB_MOD_LICENSE ("GPLv3+"); + + static grub_dl_t my_mod; + + static grub_efi_physical_address_t address; + static grub_efi_uintn_t pages; ++static grub_ssize_t fsize; + static grub_efi_device_path_t *file_path; + static grub_efi_handle_t image_handle; + static grub_efi_char16_t *cmdline; ++static grub_ssize_t cmdline_len; ++static grub_efi_handle_t dev_handle; ++ ++#ifdef SUPPORT_SECURE_BOOT ++static grub_efi_boolean_t debug_secureboot = 0; ++static grub_efi_status_t (*entry_point) (grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table); ++#endif + + static grub_err_t + grub_chainloader_unload (void) +@@ -63,6 +80,7 @@ grub_chainloader_unload (void) + grub_free (cmdline); + cmdline = 0; + file_path = 0; ++ dev_handle = 0; + + grub_dl_unref (my_mod); + return GRUB_ERR_NONE; +@@ -197,12 +215,409 @@ make_file_path (grub_efi_device_path_t * + return file_path; + } + ++#ifdef SUPPORT_SECURE_BOOT ++#define SHIM_LOCK_GUID \ ++ { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} } ++ ++struct grub_pe32_header_no_msdos_stub ++{ ++ char signature[GRUB_PE32_SIGNATURE_SIZE]; ++ struct grub_pe32_coff_header coff_header; ++ struct grub_pe64_optional_header optional_header; ++}; ++ ++struct pe_coff_loader_image_context ++{ ++ grub_efi_uint64_t image_address; ++ grub_efi_uint64_t image_size; ++ grub_efi_uint64_t entry_point; ++ grub_efi_uintn_t size_of_headers; ++ grub_efi_uint16_t image_type; ++ grub_efi_uint16_t number_of_sections; ++ struct grub_pe32_section_table *first_section; ++ struct grub_pe32_data_directory *reloc_dir; ++ struct grub_pe32_data_directory *sec_dir; ++ grub_efi_uint64_t number_of_rva_and_sizes; ++ struct grub_pe32_header_no_msdos_stub *pe_hdr; ++}; ++ ++typedef struct pe_coff_loader_image_context pe_coff_loader_image_context_t; ++ ++struct grub_efi_shim_lock ++{ ++ grub_efi_status_t (*verify)(void *buffer, ++ grub_efi_uint32_t size); ++ grub_efi_status_t (*hash)(void *data, ++ grub_efi_int32_t datasize, ++ pe_coff_loader_image_context_t *context, ++ grub_efi_uint8_t *sha256hash, ++ grub_efi_uint8_t *sha1hash); ++ grub_efi_status_t (*context)(void *data, ++ grub_efi_uint32_t size, ++ pe_coff_loader_image_context_t *context); ++}; ++ ++typedef struct grub_efi_shim_lock grub_efi_shim_lock_t; ++ ++static grub_efi_boolean_t ++grub_secure_validate (void *data, grub_efi_uint32_t size) ++{ ++ grub_efi_guid_t guid = SHIM_LOCK_GUID; ++ grub_efi_shim_lock_t *shim_lock; ++ ++ shim_lock = grub_efi_locate_protocol (&guid, NULL); ++ ++ if (!shim_lock) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "no shim lock protocol"); ++ return 0; ++ } ++ ++ if (shim_lock->verify (data, size) == GRUB_EFI_SUCCESS) ++ { ++ grub_dprintf ("chain", "verify success\n"); ++ return 1; ++ } ++ ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "verify failed"); ++ return 0; ++} ++ ++static grub_efi_boolean_t ++read_header (void *data, grub_efi_uint32_t size, pe_coff_loader_image_context_t *context) ++{ ++ grub_efi_guid_t guid = SHIM_LOCK_GUID; ++ grub_efi_shim_lock_t *shim_lock; ++ grub_efi_status_t status; ++ ++ shim_lock = grub_efi_locate_protocol (&guid, NULL); ++ ++ if (!shim_lock) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "no shim lock protocol"); ++ return 0; ++ } ++ ++ status = shim_lock->context (data, size, context); ++ ++ if (status == GRUB_EFI_SUCCESS) ++ { ++ grub_dprintf ("chain", "context success\n"); ++ return 1; ++ } ++ ++ switch (status) ++ { ++ case GRUB_EFI_UNSUPPORTED: ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "context error unsupported"); ++ break; ++ case GRUB_EFI_INVALID_PARAMETER: ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "context error invalid parameter"); ++ break; ++ default: ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "context error code"); ++ break; ++ } ++ ++ return 0; ++} ++ ++static void* ++image_address (void *image, grub_efi_uint64_t sz, grub_efi_uint64_t adr) ++{ ++ if (adr > sz) ++ return NULL; ++ ++ return ((grub_uint8_t*)image + adr); ++} ++ ++static grub_efi_status_t ++relocate_coff (pe_coff_loader_image_context_t *context, void *data) ++{ ++ struct grub_pe32_data_directory *reloc_base, *reloc_base_end; ++ grub_efi_uint64_t adjust; ++ grub_efi_uint16_t *reloc, *reloc_end; ++ char *fixup, *fixup_base, *fixup_data = NULL; ++ grub_efi_uint16_t *fixup_16; ++ grub_efi_uint32_t *fixup_32; ++ grub_efi_uint64_t *fixup_64; ++ ++ grub_efi_uint64_t size = context->image_size; ++ void *image_end = (char *)data + size; ++ ++ context->pe_hdr->optional_header.image_base = (grub_uint64_t)data; ++ ++ if (context->number_of_rva_and_sizes <= 5 || context->reloc_dir->size == 0) ++ { ++ grub_dprintf ("chain", "no need to reloc, we are done\n"); ++ return GRUB_EFI_SUCCESS; ++ } ++ ++ reloc_base = image_address (data, size, context->reloc_dir->rva); ++ reloc_base_end = image_address (data, size, context->reloc_dir->rva + context->reloc_dir->size -1); ++ ++ grub_dprintf ("chain", "reloc_base %p reloc_base_end %p\n", reloc_base, reloc_base_end); ++ ++ if (!reloc_base || !reloc_base_end) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "Reloc table overflows binary"); ++ return GRUB_EFI_UNSUPPORTED; ++ } ++ ++ adjust = (grub_uint64_t)data - context->image_address; ++ ++ while (reloc_base < reloc_base_end) ++ { ++ reloc = (grub_uint16_t *)((char*)reloc_base + sizeof (struct grub_pe32_data_directory)); ++ reloc_end = (grub_uint16_t *)((char*)reloc_base + reloc_base->size); ++ ++ if ((void *)reloc_end < data || (void *)reloc_end > image_end) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "Reloc table overflows binary"); ++ return GRUB_EFI_UNSUPPORTED; ++ } ++ ++ fixup_base = image_address(data, size, reloc_base->rva); ++ ++ if (!fixup_base) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid fixupbase"); ++ return GRUB_EFI_UNSUPPORTED; ++ } ++ ++ while (reloc < reloc_end) ++ { ++ fixup = fixup_base + (*reloc & 0xFFF); ++ switch ((*reloc) >> 12) ++ { ++ case GRUB_PE32_REL_BASED_ABSOLUTE: ++ break; ++ case GRUB_PE32_REL_BASED_HIGH: ++ fixup_16 = (grub_uint16_t *)fixup; ++ *fixup_16 = (grub_uint16_t) (*fixup_16 + ((grub_uint16_t)((grub_uint32_t)adjust >> 16))); ++ if (fixup_data != NULL) ++ { ++ *(grub_uint16_t *) fixup_data = *fixup_16; ++ fixup_data = fixup_data + sizeof (grub_uint16_t); ++ } ++ break; ++ case GRUB_PE32_REL_BASED_LOW: ++ fixup_16 = (grub_uint16_t *)fixup; ++ *fixup_16 = (grub_uint16_t) (*fixup_16 + (grub_uint16_t)adjust ); ++ if (fixup_data != NULL) ++ { ++ *(grub_uint16_t *) fixup_data = *fixup_16; ++ fixup_data = fixup_data + sizeof (grub_uint16_t); ++ } ++ break; ++ case GRUB_PE32_REL_BASED_HIGHLOW: ++ fixup_32 = (grub_uint32_t *)fixup; ++ *fixup_32 = *fixup_32 + (grub_uint32_t)adjust; ++ if (fixup_data != NULL) ++ { ++ fixup_data = (char *)ALIGN_UP ((grub_addr_t)fixup_data, sizeof (grub_uint32_t)); ++ *(grub_uint32_t *) fixup_data = *fixup_32; ++ fixup_data += sizeof (grub_uint32_t); ++ } ++ break; ++ case GRUB_PE32_REL_BASED_DIR64: ++ fixup_64 = (grub_uint64_t *)fixup; ++ *fixup_64 = *fixup_64 + (grub_uint64_t)adjust; ++ if (fixup_data != NULL) ++ { ++ fixup_data = (char *)ALIGN_UP ((grub_addr_t)fixup_data, sizeof (grub_uint64_t)); ++ *(grub_uint64_t *) fixup_data = *fixup_64; ++ fixup_data += sizeof (grub_uint64_t); ++ } ++ break; ++ default: ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown relocation"); ++ return GRUB_EFI_UNSUPPORTED; ++ } ++ reloc += 1; ++ } ++ reloc_base = (struct grub_pe32_data_directory *)reloc_end; ++ } ++ ++ return GRUB_EFI_SUCCESS; ++} ++ ++static grub_efi_device_path_t * ++grub_efi_get_media_file_path (grub_efi_device_path_t *dp) ++{ ++ while (1) ++ { ++ grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); ++ grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); ++ ++ if (type == GRUB_EFI_END_DEVICE_PATH_TYPE) ++ break; ++ else if (type == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE ++ && subtype == GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE) ++ return dp; ++ ++ dp = GRUB_EFI_NEXT_DEVICE_PATH (dp); ++ } ++ ++ return NULL; ++} ++ ++static grub_efi_boolean_t ++handle_image (void *data, grub_efi_uint32_t datasize) ++{ ++ grub_efi_boot_services_t *b; ++ grub_efi_loaded_image_t *li, li_bak; ++ grub_efi_status_t efi_status; ++ char *buffer = NULL; ++ char *buffer_aligned = NULL; ++ grub_efi_uint32_t i, size; ++ struct grub_pe32_section_table *section; ++ char *base, *end; ++ pe_coff_loader_image_context_t context; ++ grub_uint32_t section_alignment; ++ grub_uint32_t buffer_size; ++ ++ b = grub_efi_system_table->boot_services; ++ ++ if (read_header (data, datasize, &context)) ++ { ++ grub_dprintf ("chain", "Succeed to read header\n"); ++ } ++ else ++ { ++ grub_dprintf ("chain", "Failed to read header\n"); ++ goto error_exit; ++ } ++ ++ section_alignment = context.pe_hdr->optional_header.section_alignment; ++ buffer_size = context.image_size + section_alignment; ++ ++ efi_status = efi_call_3 (b->allocate_pool, GRUB_EFI_LOADER_DATA, ++ buffer_size, &buffer); ++ ++ if (efi_status != GRUB_EFI_SUCCESS) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ goto error_exit; ++ } ++ ++ buffer_aligned = (char *)ALIGN_UP ((grub_addr_t)buffer, section_alignment); ++ ++ grub_memcpy (buffer_aligned, data, context.size_of_headers); ++ ++ section = context.first_section; ++ for (i = 0; i < context.number_of_sections; i++) ++ { ++ size = section->virtual_size; ++ if (size > section->raw_data_size) ++ size = section->raw_data_size; ++ ++ base = image_address (buffer_aligned, context.image_size, section->virtual_address); ++ end = image_address (buffer_aligned, context.image_size, section->virtual_address + size - 1); ++ ++ if (!base || !end) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid section size"); ++ goto error_exit; ++ } ++ ++ if (section->raw_data_size > 0) ++ grub_memcpy (base, (grub_efi_uint8_t*)data + section->raw_data_offset, size); ++ ++ if (size < section->virtual_size) ++ grub_memset (base + size, 0, section->virtual_size - size); ++ ++ grub_dprintf ("chain", "copied section %s\n", section->name); ++ section += 1; ++ } ++ ++ efi_status = relocate_coff (&context, buffer_aligned); ++ ++ if (efi_status != GRUB_EFI_SUCCESS) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "relocation failed"); ++ goto error_exit; ++ } ++ ++ entry_point = image_address (buffer_aligned, context.image_size, context.entry_point); ++ ++ if (!entry_point) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid entry point"); ++ goto error_exit; ++ } ++ ++ li = grub_efi_get_loaded_image (grub_efi_image_handle); ++ if (!li) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "no loaded image available"); ++ goto error_exit; ++ } ++ ++ grub_memcpy (&li_bak, li, sizeof (grub_efi_loaded_image_t)); ++ li->image_base = buffer_aligned; ++ li->image_size = context.image_size; ++ li->load_options = cmdline; ++ li->load_options_size = cmdline_len; ++ li->file_path = grub_efi_get_media_file_path (file_path); ++ li->device_handle = dev_handle; ++ if (li->file_path) ++ { ++ grub_printf ("file path: "); ++ grub_efi_print_device_path (li->file_path); ++ } ++ else ++ { ++ grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching file path found"); ++ goto error_exit; ++ } ++ ++ efi_status = efi_call_2 (entry_point, grub_efi_image_handle, grub_efi_system_table); ++ ++ grub_memcpy (li, &li_bak, sizeof (grub_efi_loaded_image_t)); ++ efi_status = efi_call_1 (b->free_pool, buffer); ++ ++ return 1; ++ ++error_exit: ++ if (buffer) ++ efi_call_1 (b->free_pool, buffer); ++ ++ return 0; ++ ++} ++ ++static grub_err_t ++grub_secureboot_chainloader_unload (void) ++{ ++ grub_efi_boot_services_t *b; ++ ++ b = grub_efi_system_table->boot_services; ++ efi_call_2 (b->free_pages, address, pages); ++ grub_free (file_path); ++ grub_free (cmdline); ++ cmdline = 0; ++ file_path = 0; ++ dev_handle = 0; ++ ++ grub_dl_unref (my_mod); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_secureboot_chainloader_boot (void) ++{ ++ handle_image ((void *)address, fsize); ++ grub_loader_unset (); ++ return grub_errno; ++} ++#endif ++ + static grub_err_t + grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) + { + grub_file_t file = 0; +- grub_ssize_t size; + grub_efi_status_t status; + grub_efi_boot_services_t *b; + grub_device_t dev = 0; +@@ -210,7 +625,6 @@ grub_cmd_chainloader (grub_command_t cmd + grub_efi_loaded_image_t *loaded_image; + char *filename; + void *boot_image = 0; +- grub_efi_handle_t dev_handle = 0; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); +@@ -222,9 +636,36 @@ grub_cmd_chainloader (grub_command_t cmd + address = 0; + image_handle = 0; + file_path = 0; ++ dev_handle = 0; + + b = grub_efi_system_table->boot_services; + ++ if (argc > 1) ++ { ++ int i; ++ grub_efi_char16_t *p16; ++ ++ for (i = 1, cmdline_len = 0; i < argc; i++) ++ cmdline_len += grub_strlen (argv[i]) + 1; ++ ++ cmdline_len *= sizeof (grub_efi_char16_t); ++ cmdline = p16 = grub_malloc (cmdline_len); ++ if (! cmdline) ++ goto fail; ++ ++ for (i = 1; i < argc; i++) ++ { ++ char *p8; ++ ++ p8 = argv[i]; ++ while (*p8) ++ *(p16++) = *(p8++); ++ ++ *(p16++) = ' '; ++ } ++ *(--p16) = 0; ++ } ++ + file = grub_file_open (filename, GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE); + if (! file) + goto fail; +@@ -270,14 +711,14 @@ grub_cmd_chainloader (grub_command_t cmd + grub_printf ("file path: "); + grub_efi_print_device_path (file_path); + +- size = grub_file_size (file); +- if (!size) ++ fsize = grub_file_size (file); ++ if (!fsize) + { + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), + filename); + goto fail; + } +- pages = (((grub_efi_uintn_t) size + ((1 << 12) - 1)) >> 12); ++ pages = (((grub_efi_uintn_t) fsize + ((1 << 12) - 1)) >> 12); + + status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ANY_PAGES, + GRUB_EFI_LOADER_CODE, +@@ -291,7 +732,7 @@ grub_cmd_chainloader (grub_command_t cmd + } + + boot_image = (void *) ((grub_addr_t) address); +- if (grub_file_read (file, boot_image, size) != size) ++ if (grub_file_read (file, boot_image, fsize) != fsize) + { + if (grub_errno == GRUB_ERR_NONE) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), +@@ -301,7 +742,7 @@ grub_cmd_chainloader (grub_command_t cmd + } + + #if defined (__i386__) || defined (__x86_64__) +- if (size >= (grub_ssize_t) sizeof (struct grub_macho_fat_header)) ++ if (fsize >= (grub_ssize_t) sizeof (struct grub_macho_fat_header)) + { + struct grub_macho_fat_header *head = boot_image; + if (head->magic +@@ -324,20 +765,30 @@ grub_cmd_chainloader (grub_command_t cmd + > ~grub_cpu_to_le32 (archs[i].size) + || grub_cpu_to_le32 (archs[i].offset) + + grub_cpu_to_le32 (archs[i].size) +- > (grub_size_t) size) ++ > (grub_size_t) fsize) + { + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), + filename); + goto fail; + } + boot_image = (char *) boot_image + grub_cpu_to_le32 (archs[i].offset); +- size = grub_cpu_to_le32 (archs[i].size); ++ fsize = grub_cpu_to_le32 (archs[i].size); + } + } + #endif + ++#ifdef SUPPORT_SECURE_BOOT ++ /* FIXME is secure boot possible also with universal binaries? */ ++ if (debug_secureboot || (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED && grub_secure_validate ((void *)address, fsize))) ++ { ++ grub_file_close (file); ++ grub_loader_set (grub_secureboot_chainloader_boot, grub_secureboot_chainloader_unload, 0); ++ return 0; ++ } ++#endif ++ + status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path, +- boot_image, size, ++ boot_image, fsize, + &image_handle); + if (status != GRUB_EFI_SUCCESS) + { +@@ -360,33 +811,10 @@ grub_cmd_chainloader (grub_command_t cmd + } + loaded_image->device_handle = dev_handle; + +- if (argc > 1) ++ if (cmdline) + { +- int i, len; +- grub_efi_char16_t *p16; +- +- for (i = 1, len = 0; i < argc; i++) +- len += grub_strlen (argv[i]) + 1; +- +- len *= sizeof (grub_efi_char16_t); +- cmdline = p16 = grub_malloc (len); +- if (! cmdline) +- goto fail; +- +- for (i = 1; i < argc; i++) +- { +- char *p8; +- +- p8 = argv[i]; +- while (*p8) +- *(p16++) = *(p8++); +- +- *(p16++) = ' '; +- } +- *(--p16) = 0; +- + loaded_image->load_options = cmdline; +- loaded_image->load_options_size = len; ++ loaded_image->load_options_size = cmdline_len; + } + + grub_file_close (file); +@@ -408,6 +836,9 @@ grub_cmd_chainloader (grub_command_t cmd + if (address) + efi_call_2 (b->free_pages, address, pages); + ++ if (cmdline) ++ grub_free (cmdline); ++ + grub_dl_unref (my_mod); + + return grub_errno; diff --git a/grub2-secureboot-install-signed-grub.patch b/grub2-secureboot-install-signed-grub.patch new file mode 100644 index 0000000..87a5c0f --- /dev/null +++ b/grub2-secureboot-install-signed-grub.patch @@ -0,0 +1,227 @@ +From 1ff2f31d12f7235423a1eb8a117e0c6f8b2f41c7 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Tue, 4 Jun 2019 12:32:35 +0800 +Subject: [PATCH] grub-install: handle signed grub installation on arm64-efi + +Use grub2-install to handle signed grub installation for arm64 UEFI secure +boot, the default behavior is auto, which will install signed grub whenever +detected. + +Two options, --suse-force-signed and --suse-inhibit-signed, can be used to +override the default auto detecting behavior. The former will force to use +prebuilt signed image and thus will fail if missing, the latter will always use +'mkimage' to create unsigned core image per the user's running environment. + +Signed-off-by: Michael Chang +--- + util/grub-install.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 85 insertions(+), 1 deletion(-) + +Index: grub-2.06/util/grub-install.c +=================================================================== +--- grub-2.06.orig/util/grub-install.c ++++ grub-2.06/util/grub-install.c +@@ -85,6 +85,15 @@ static int suse_enable_tpm = 0; + + enum + { ++ SIGNED_GRUB_INHIBIT, ++ SIGNED_GRUB_AUTO, ++ SIGNED_GRUB_FORCE ++ }; ++ ++static int signed_grub_mode = SIGNED_GRUB_AUTO; ++ ++enum ++ { + OPTION_BOOT_DIRECTORY = 0x301, + OPTION_ROOT_DIRECTORY, + OPTION_TARGET, +@@ -109,6 +118,8 @@ enum + OPTION_NO_BOOTSECTOR, + OPTION_NO_RS_CODES, + OPTION_SUSE_ENABLE_TPM, ++ OPTION_SUSE_FORCE_SIGNED, ++ OPTION_SUSE_INHIBIT_SIGNED, + OPTION_MACPPC_DIRECTORY, + OPTION_ZIPL_DIRECTORY, + OPTION_LABEL_FONT, +@@ -238,6 +249,14 @@ argp_parser (int key, char *arg, struct + suse_enable_tpm = 1; + return 0; + ++ case OPTION_SUSE_FORCE_SIGNED: ++ signed_grub_mode = SIGNED_GRUB_FORCE; ++ return 0; ++ ++ case OPTION_SUSE_INHIBIT_SIGNED: ++ signed_grub_mode = SIGNED_GRUB_INHIBIT; ++ return 0; ++ + case OPTION_DEBUG: + verbosity++; + return 0; +@@ -300,7 +319,12 @@ static struct argp_option options[] = { + N_("Do not apply any reed-solomon codes when embedding core.img. " + "This option is only available on x86 BIOS targets."), 0}, + {"suse-enable-tpm", OPTION_SUSE_ENABLE_TPM, 0, 0, N_("install TPM modules"), 0}, +- ++ {"suse-force-signed", OPTION_SUSE_FORCE_SIGNED, 0, 0, ++ N_("force installation of signed grub" "%s." ++ "This option is only available on ARM64 EFI targets."), 0}, ++ {"suse-inhibit-signed", OPTION_SUSE_INHIBIT_SIGNED, 0, 0, ++ N_("inhibit installation of signed grub. " ++ "This option is only available on ARM64 EFI targets."), 0}, + {"debug", OPTION_DEBUG, 0, OPTION_HIDDEN, 0, 2}, + {"no-floppy", OPTION_NO_FLOPPY, 0, OPTION_HIDDEN, 0, 2}, + {"debug-image", OPTION_DEBUG_IMAGE, N_("STRING"), OPTION_HIDDEN, 0, 2}, +@@ -373,6 +397,22 @@ help_filter (int key, const char *text, + free (plats); + return ret; + } ++ case OPTION_SUSE_FORCE_SIGNED: ++ { ++ const char *t = get_default_platform (); ++ char *ret; ++ if (grub_strcmp (t, "arm64-efi") == 0) ++ { ++ char *s = grub_util_path_concat (3, grub_util_get_pkglibdir (), t, "grub.efi"); ++ char *text2 = xasprintf (" [default=%s]", s); ++ ret = xasprintf (text, text2); ++ free (text2); ++ free (s); ++ } ++ else ++ ret = xasprintf (text, ""); ++ return ret; ++ } + case ARGP_KEY_HELP_POST_DOC: + return xasprintf (text, program_name, GRUB_BOOT_DIR_NAME "/" GRUB_DIR_NAME); + default: +@@ -1636,13 +1676,34 @@ main (int argc, char *argv[]) + + char mkimage_target[200]; + const char *core_name = NULL; ++ char *signed_imgfile = NULL; + + switch (platform) + { ++ case GRUB_INSTALL_PLATFORM_ARM64_EFI: ++ ++ if (signed_grub_mode > SIGNED_GRUB_INHIBIT) ++ { ++ signed_imgfile = grub_util_path_concat (2, grub_install_source_directory, "grub.efi"); ++ if (!grub_util_is_regular (signed_imgfile)) ++ { ++ if (signed_grub_mode >= SIGNED_GRUB_FORCE) ++ grub_util_error ("signed image `%s' does not exist\n", signed_imgfile); ++ else ++ { ++ free (signed_imgfile); ++ signed_imgfile = NULL; ++ } ++ } ++ } ++ ++ if (signed_imgfile) ++ fprintf (stderr, _("Use signed file in %s for installation.\n"), signed_imgfile); ++ ++ /* fallthrough. */ + case GRUB_INSTALL_PLATFORM_I386_EFI: + case GRUB_INSTALL_PLATFORM_X86_64_EFI: + case GRUB_INSTALL_PLATFORM_ARM_EFI: +- case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: +@@ -1712,13 +1773,75 @@ main (int argc, char *argv[]) + core_name); + char *prefix = xasprintf ("%s%s", prefix_drive ? : "", + relative_grubdir); +- if (core_name != mkimage_target) ++ char *grub_efi_cfg = NULL; ++ ++ if ((core_name != mkimage_target) && !signed_imgfile) + grub_install_make_image_wrap (/* source dir */ grub_install_source_directory, + /*prefix */ prefix, + /* output */ imgfile, + /* memdisk */ NULL, + have_load_cfg ? load_cfg : NULL, + /* image target */ mkimage_target, 0); ++ else if (signed_imgfile) ++ { ++ FILE *grub_cfg_f; ++ ++ grub_install_copy_file (signed_imgfile, imgfile, 1); ++ grub_efi_cfg = grub_util_path_concat (2, platdir, "grub.cfg"); ++ grub_cfg_f = grub_util_fopen (grub_efi_cfg, "wb"); ++ if (!grub_cfg_f) ++ grub_util_error (_("Can't create file: %s"), strerror (errno)); ++ ++ if (have_abstractions) ++ { ++ fprintf (grub_cfg_f, "set prefix=(%s)%s\n", grub_drives[0], relative_grubdir); ++ fprintf (grub_cfg_f, "set root=%s\n", grub_drives[0]); ++ } ++ else if (prefix_drive) ++ { ++ char *uuid = NULL; ++ if (grub_fs->fs_uuid && grub_fs->fs_uuid (grub_dev, &uuid)) ++ { ++ grub_print_error (); ++ grub_errno = 0; ++ uuid = NULL; ++ } ++ if (!uuid) ++ grub_util_error ("cannot find fs uuid for %s", grub_fs->name); ++ ++ fprintf (grub_cfg_f, "search --fs-uuid --set=root %s\n", uuid); ++ fprintf (grub_cfg_f, "set prefix=($root)%s\n", relative_grubdir); ++ } ++ ++ if (have_load_cfg) ++ { ++ size_t len; ++ char *buf; ++ ++ FILE *fp = grub_util_fopen (load_cfg, "rb"); ++ if (!fp) ++ grub_util_error (_("Can't read file: %s"), strerror (errno)); ++ ++ fseek (fp, 0, SEEK_END); ++ len = ftell (fp); ++ fseek (fp, 0, SEEK_SET); ++ buf = xmalloc (len); ++ ++ if (fread (buf, 1, len, fp) != len) ++ grub_util_error (_("cannot read `%s': %s"), load_cfg, strerror (errno)); ++ ++ if (fwrite (buf, 1, len, grub_cfg_f) != len) ++ grub_util_error (_("cannot write `%s': %s"), grub_efi_cfg, strerror (errno)); ++ ++ free (buf); ++ fclose (fp); ++ } ++ ++ fprintf (grub_cfg_f, "source ${prefix}/grub.cfg\n"); ++ fclose (grub_cfg_f); ++ free (signed_imgfile); ++ signed_imgfile = NULL; ++ } + /* Backward-compatibility kludges. */ + switch (platform) + { +@@ -2014,6 +2137,13 @@ main (int argc, char *argv[]) + grub_set_install_backup_ponr (); + + free (dst); ++ if (grub_efi_cfg) ++ { ++ dst = grub_util_path_concat (2, efidir, "grub.cfg"); ++ grub_install_copy_file (grub_efi_cfg, dst, 1); ++ free (dst); ++ free (grub_efi_cfg); ++ } + } + if (!removable && update_nvram) + { diff --git a/grub2-secureboot-no-insmod-on-sb.patch b/grub2-secureboot-no-insmod-on-sb.patch new file mode 100644 index 0000000..360a3d5 --- /dev/null +++ b/grub2-secureboot-no-insmod-on-sb.patch @@ -0,0 +1,53 @@ +From 29c89e27805f7a6a22bce11ed9bb430e19c972a9 Mon Sep 17 00:00:00 2001 +From: Colin Watson +Date: Tue, 23 Oct 2012 10:40:49 -0400 +Subject: [PATCH 449/482] Don't allow insmod when secure boot is enabled. + +References: fate#314485 +Patch-Mainline: no + +v2: +Use grub_efi_get_secureboot to get secure boot status + +Signed-off-by: Michael Chang +--- + grub-core/kern/dl.c | 17 +++++++++++++++++ + grub-core/kern/efi/efi.c | 28 ++++++++++++++++++++++++++++ + include/grub/efi/efi.h | 1 + + 3 files changed, 46 insertions(+) + +Index: grub-2.04/grub-core/kern/dl.c +=================================================================== +--- grub-2.04.orig/grub-core/kern/dl.c ++++ grub-2.04/grub-core/kern/dl.c +@@ -38,6 +38,10 @@ + #define GRUB_MODULES_MACHINE_READONLY + #endif + ++#ifdef GRUB_MACHINE_EFI ++#include ++#endif ++ + + + #pragma GCC diagnostic ignored "-Wcast-align" +@@ -688,6 +692,19 @@ grub_dl_load_file (const char *filename) + + grub_boot_time ("Loading module %s", filename); + ++#ifdef GRUB_MACHINE_EFI ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ { ++#if 0 ++ /* This is an error, but grub2-mkconfig still generates a pile of ++ * insmod commands, so emitting it would be mostly just obnoxious. */ ++ grub_error (GRUB_ERR_ACCESS_DENIED, ++ "Secure Boot forbids loading module from %s", filename); ++#endif ++ return 0; ++ } ++#endif ++ + file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE); + if (! file) + return 0; diff --git a/grub2-setup-try-fs-embed-if-mbr-gap-too-small.patch b/grub2-setup-try-fs-embed-if-mbr-gap-too-small.patch new file mode 100644 index 0000000..30362ae --- /dev/null +++ b/grub2-setup-try-fs-embed-if-mbr-gap-too-small.patch @@ -0,0 +1,61 @@ + +V2: Add fs_ prefix to fs functions by upstream commit ad4bfee + +Index: grub-2.06~rc1/util/setup.c +=================================================================== +--- grub-2.06~rc1.orig/util/setup.c ++++ grub-2.06~rc1/util/setup.c +@@ -530,8 +530,42 @@ SETUP (const char *dir, + err = grub_util_ldm_embed (dest_dev->disk, &nsec, maxsec, + GRUB_EMBED_PCBIOS, §ors); + else if (ctx.dest_partmap) +- err = ctx.dest_partmap->embed (dest_dev->disk, &nsec, maxsec, +- GRUB_EMBED_PCBIOS, §ors, warn_small); ++ { ++ err = ctx.dest_partmap->embed (dest_dev->disk, &nsec, maxsec, ++ GRUB_EMBED_PCBIOS, §ors, warn_small); ++#ifdef GRUB_SETUP_BIOS ++ if ((err == GRUB_ERR_OUT_OF_RANGE || err == GRUB_ERR_FILE_NOT_FOUND) ++ && dest_dev->disk->id == root_dev->disk->id ++ && dest_dev->disk->dev->id == root_dev->disk->dev->id) ++ { ++ grub_fs_t root_fs; ++ ++ root_fs = grub_fs_probe (root_dev); ++ if (root_fs && root_fs->fs_embed) ++ { ++ grub_disk_addr_t *fs_sectors; ++ unsigned int fs_nsec; ++ ++ fs_sectors = NULL; ++ fs_nsec = core_sectors; ++ err = root_fs->fs_embed (root_dev, &fs_nsec, maxsec, ++ GRUB_EMBED_PCBIOS, &fs_sectors); ++ if (!err && fs_nsec >= core_sectors) ++ { ++ sectors = fs_sectors; ++ nsec = fs_nsec; ++ ctx.container = root_dev->disk->partition; ++ core_dev = root_dev; ++ } ++ else ++ { ++ if (fs_sectors) ++ grub_free (fs_sectors); ++ } ++ } ++ } ++#endif ++ } + else + err = fs->fs_embed (dest_dev, &nsec, maxsec, + GRUB_EMBED_PCBIOS, §ors); +@@ -643,7 +677,7 @@ SETUP (const char *dir, + + /* Write the core image onto the disk. */ + for (i = 0; i < nsec; i++) +- grub_disk_write (dest_dev->disk, sectors[i], 0, ++ grub_disk_write (core_dev->disk, sectors[i], 0, + GRUB_DISK_SECTOR_SIZE, + core_img + i * GRUB_DISK_SECTOR_SIZE); + #endif diff --git a/grub2-simplefb.patch b/grub2-simplefb.patch new file mode 100644 index 0000000..c24c118 --- /dev/null +++ b/grub2-simplefb.patch @@ -0,0 +1,13 @@ + + +--- grub-2.06/util/grub.d/10_linux.in 2021-12-08 14:57:02.381591797 +0100 ++++ grub-2.06/util/grub.d/10_linux.in 2021-12-08 15:09:08.563593340 +0100 +@@ -149,7 +149,7 @@ + # FIXME: We need an interface to select vesafb in case efifb can't be used. + if [ "x$GRUB_GFXPAYLOAD_LINUX" = x ]; then + echo " load_video" | sed "s/^/$submenu_indentation/" +- if grep -qx "CONFIG_FB_EFI=y" "${config}" 2> /dev/null \ ++ if grep -qx "CONFIG_\(FB_EFI\|SYSFB_SIMPLEFB\)=y" "${config}" 2> /dev/null \ + && grep -qx "CONFIG_VT_HW_CONSOLE_BINDING=y" "${config}" 2> /dev/null; then + echo " set gfxpayload=keep" | sed "s/^/$submenu_indentation/" + fi diff --git a/grub2-snapper-plugin.sh b/grub2-snapper-plugin.sh new file mode 100644 index 0000000..d1227ca --- /dev/null +++ b/grub2-snapper-plugin.sh @@ -0,0 +1,281 @@ +#!/bin/sh +set -e + +# Copyright (C) 2006,2007,2008,2009,2010 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 . + +grub_mkconfig="/usr/sbin/grub2-mkconfig" +grub_mkrelpath="/usr/bin/grub2-mkrelpath" +grub_script_check="/usr/bin/grub2-script-check" +grub_setting="/etc/default/grub" +grub_cfg="/boot/grub2/grub.cfg" +grub_snapshot_cfg="/boot/grub2/snapshot_submenu.cfg" + +snapper_snapshot_path="/.snapshots" +snapshot_submenu_name="grub-snapshot.cfg" +snapper_snapshots_cfg="${snapper_snapshot_path}/${snapshot_submenu_name}" + +# add hotkeys for s390. (bnc#885668) +hotkey= +incr_hotkey() +{ + [ -n "$hotkey" ] || return + expr $hotkey + 1 +} +print_hotkey() +{ + keys="123456789abdfgijklmnoprstuvwyz" + if [ -z "$hotkey" ]||[ $hotkey -eq 0 ]||[ $hotkey -gt 30 ]; then + return + fi + echo "--hotkey=$(expr substr $keys $hotkey 1)" +} + + +snapshot_submenu () { + + s_dir="$1" + + snapshot="${s_dir}/snapshot" + num="`basename $s_dir`" + + # bnc#864842 Important snapshots are not marked as such in grub2 menu + # the format is "important distribution version (kernel_version, timestamp, pre/post)" + date=`xmllint --xpath '/snapshot/date/text()' "${s_dir}/info.xml" || echo ""` + date=`echo $date | sed 's/\(.*\) \(.*\):.*/\1T\2/'` + important=`xmllint --xpath "/snapshot/userdata[key='important']/value/text()" "${s_dir}/info.xml" 2>/dev/null || echo ""` + stype=`xmllint --xpath '/snapshot/type/text()' "${s_dir}/info.xml" || echo ""` + kernel_ver=`readlink ${snapshot}/boot/vmlinuz | sed -e 's/^vmlinuz-//' -e 's/-default$//'` + if [ -z "$kernel_ver" -a -L ${snapshot}/boot/image ]; then + kernel_ver=`readlink ${snapshot}/boot/image | sed -e 's/^image-//' -e 's/-default$//'` + fi + eval `cat ${snapshot}/etc/os-release` + # bsc#934252 - Replace SLES 12.1 with SLES12-SP1 for the list of snapshots + if test "${NAME}" = "SLES" -o "${NAME}" = "SLED"; then + VERSION=`echo ${VERSION} | sed -e 's!^\([0-9]\{1,\}\)\.\([0-9]\{1,\}\)$!\1-SP\2!'` + fi + + # FATE#318101 + # Show user defined comments in grub2 menu for snapshots + # Use userdata tag "bootloader=[user defined text]" + full_desc=`xmllint --xpath "/snapshot/userdata[key='bootloader']/value/text()" "${s_dir}/info.xml" 2>/dev/null || echo ""` + test -z "$full_desc" && desc=`xmllint --xpath '/snapshot/description/text()' "${s_dir}/info.xml" 2>/dev/null || echo ""` + + # FATE#317972 + # If we have a post entry and the description field is empty, + # we should use the "Pre" number and add that description to the post entry. + if test -z "$full_desc" -a -z "$desc" -a "$stype" = "post"; then + pre_num=`xmllint --xpath '/snapshot/pre_num/text()' "${s_dir}/info.xml" 2>/dev/null || echo ""` + if test -n "$pre_num"; then + if test -f "${snapper_snapshot_path}/${pre_num}/info.xml" ; then + desc=`xmllint --xpath '/snapshot/description/text()' "${snapper_snapshot_path}/${pre_num}/info.xml" 2>/dev/null || echo ""` + fi + fi + fi + + test "$important" = "yes" && important="*" || important=" " + test "$stype" = "single" && stype="" + test -z "$stype" || stype=",$stype" + test -z "$desc" || desc=",$desc" + test -z "$full_desc" && full_desc="$kernel_ver,$date$stype$desc" + + if test "${NAME}" = "SLES" -o "${NAME}" = "SLED"; then + title="${important}${NAME}${VERSION} ($full_desc)" + else + title="${important}${NAME} ${VERSION} ($full_desc)" + fi + + if test "$s390" = "1"; then + subvol="\$2" + else + subvol="\$3" + fi + + cat </dev/null || true + fi + continue + fi + + done + + hk="" + [ -z "$hotkey" ] || hk="--hotkey=s" + + for c in $(printf '%s' "${cs}" | sort -Vr); do + if ! snapshot_submenu "$c" > "${c}/${snapshot_submenu_name}"; then + rm -f "${c}/${snapshot_submenu_name}" + continue + fi + snapshot_cfg="${snapshot_cfg} + if [ -f \"$c/${snapshot_submenu_name}\" ]; then + source \"$c/${snapshot_submenu_name}\" + fi" + done + + cat <"${snapper_snapshots_cfg}.new" +if [ -z "\$extra_cmdline" ]; then + submenu $hk "Start bootloader from a read-only snapshot" {${snapshot_cfg} + if [ x\$snapshot_found != xtrue ]; then + submenu "Not Found" { true; } + fi + } +fi +EOF + + if ${grub_script_check} "${snapper_snapshots_cfg}.new"; then + mv -f "${snapper_snapshots_cfg}.new" "${snapper_snapshots_cfg}" + fi + +} + + +snapshot_submenu_clean () { + + for s_dir in ${snapper_snapshot_path}/*; do + + snapper_cfg="${s_dir}/${snapshot_submenu_name}" + + if [ -f "$snapper_cfg" ]; then + rm -f "$snapper_cfg" + rmdir "$s_dir" 2>/dev/null || true + fi + + done + + if [ -f "${snapper_snapshot_path}/${snapshot_submenu_name}" ]; then + rm -f "${snapper_snapshot_path}/${snapshot_submenu_name}" + fi + +} + +set_grub_setting () { + + name=$1 + val=$2 + + if grep -q "$name" "$grub_setting"; then + sed -i -e "s!.*\($name\)=.*!\1=\"$val\"!" "$grub_setting" + else + echo "$name=\"$val\"" >> "$grub_setting" + fi +} + +enable_grub_settings () { + set_grub_setting SUSE_BTRFS_SNAPSHOT_BOOTING "true" +} + +disable_grub_settings () { + set_grub_setting SUSE_BTRFS_SNAPSHOT_BOOTING "false" +} + +update_grub () { + "${grub_mkconfig}" -o "${grub_cfg}" +} + +machine=`uname -m` +case "$machine" in +(s390|s390x) + hotkey=1 + s390=1 + ;; +esac +cmdline="$0 $* hotkey='$hotkey'" + +# Check the arguments. +while test $# -gt 0 +do + option=$1 + shift + + case "$option" in + -e | --enable) + opt_enable=true + ;; + -d | --disable) + opt_enable=false + ;; + -r | --refresh) + opt_refresh=true + ;; + -c | --clean) + opt_clean=true + ;; + -*) + ;; + esac +done + +if [ "x${opt_enable}" = "xtrue" ]; then + #enable_grub_settings + #update_grub + snapper_snapshots_cfg_refresh +elif [ "x${opt_enable}" = "xfalse" ]; then + #disable_grub_settings + update_grub + snapshot_submenu_clean +fi + +if [ x${opt_refresh} = "xtrue" ]; then + snapper_snapshots_cfg_refresh +fi + +if [ x${opt_clean} = "xtrue" ]; then + snapshot_submenu_clean +fi + diff --git a/grub2-suse-remove-linux-root-param.patch b/grub2-suse-remove-linux-root-param.patch new file mode 100644 index 0000000..53a704f --- /dev/null +++ b/grub2-suse-remove-linux-root-param.patch @@ -0,0 +1,75 @@ +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -296,7 +296,8 @@ + GRUB_DISABLE_SUBMENU \ + GRUB_CMDLINE_LINUX_RECOVERY \ + SUSE_BTRFS_SNAPSHOT_BOOTING \ +- SUSE_CMDLINE_XENEFI ++ SUSE_CMDLINE_XENEFI \ ++ SUSE_REMOVE_LINUX_ROOT_PARAM + + if test "x${grub_cfg}" != "x"; then + rm -f "${grub_cfg}.new" +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -74,7 +74,7 @@ + else + rootsubvol="`make_system_path_relative_to_its_root /`" + rootsubvol="${rootsubvol#/}" +- if [ "x${rootsubvol}" != x ]; then ++ if [ "x${rootsubvol}" != x ] && [ "x$SUSE_REMOVE_LINUX_ROOT_PARAM" != "xtrue" ]; then + GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}" + fi + fi;; +@@ -85,6 +85,10 @@ + ;; + esac + ++if [ "x$SUSE_REMOVE_LINUX_ROOT_PARAM" = "xtrue" ]; then ++ LINUX_ROOT_DEVICE="" ++fi ++ + title_correction_code= + + hotkey=1 +--- a/util/grub.d/20_linux_xen.in ++++ b/util/grub.d/20_linux_xen.in +@@ -98,7 +98,7 @@ + else + rootsubvol="`make_system_path_relative_to_its_root /`" + rootsubvol="${rootsubvol#/}" +- if [ "x${rootsubvol}" != x ]; then ++ if [ "x${rootsubvol}" != x ] && [ "x$SUSE_REMOVE_LINUX_ROOT_PARAM" != "xtrue" ]; then + GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}" + fi + fi;; +@@ -109,6 +109,10 @@ + ;; + esac + ++if [ "x$SUSE_REMOVE_LINUX_ROOT_PARAM" = "xtrue" ]; then ++ LINUX_ROOT_DEVICE="" ++fi ++ + title_correction_code= + + grub2_unquote () +--- a/util/s390x/zipl2grub.pl.in ++++ b/util/s390x/zipl2grub.pl.in +@@ -384,9 +384,13 @@ + } else { + $v = ""; + } +- if ($k eq "GRUB_DEVICE" && $v !~ /^UUID/ && ! -e $v) { +- s{root=\@$k\@}{}g; +- next; ++ if ($k eq "GRUB_DEVICE") { ++ if (($v !~ /^UUID/ && ! -e $v) || ++ (exists( $C{SUSE_REMOVE_LINUX_ROOT_PARAM}) && ++ $C{SUSE_REMOVE_LINUX_ROOT_PARAM} eq "true")) { ++ s{root=\@$k\@}{}g; ++ next; ++ } + } + s{\@$k\@}{$v}g; + } diff --git a/grub2-systemd-sleep.sh b/grub2-systemd-sleep.sh new file mode 100644 index 0000000..a5ca84c --- /dev/null +++ b/grub2-systemd-sleep.sh @@ -0,0 +1,265 @@ +#!/bin/bash +# +# Copyright (c) 2015 SUSE LINUX Products GmbH, Nuernberg, Germany. + +set -e + +GRUB_ONCE="/usr/sbin/grub2-once" +GRUB_ENV="/boot/grub2/grubenv" +GRUB_EDITENV="/usr/bin/grub2-editenv" +GRUB_CONF="/boot/grub2/grub.cfg" +GRUB_SETUP= +BLKID="/usr/sbin/blkid" +LSBLK="/usr/bin/lsblk" +ARCH=`uname -m` +VMLINUZ="vmlinuz" +case $ARCH in + ppc*) VMLINUZ="vmlinux" ;; + s390*) VMLINUZ="image"; GRUB_SETUP="/usr/sbin/grub2-zipl-setup" ;; +esac + +error_quit() +{ + echo "$1" >&2 + exit 1 +} + +check-system() +{ + [ -x "${GRUB_ONCE}" ] || error_quit "ERROR: cannot find or execute ${GRUB_ONCE}" + [ -x "${GRUB_EDITENV}" ] || error_quit "ERROR: cannot find or execute ${GRUB_EDITENV}" + [ -x "${BLKID}" ] || error_quit "ERROR: cannot find or execute ${BLKID}" + [ -r "${GRUB_CONF}" ] || error_quit "ERROR: cannot find or read ${GRUB_CONF}" +} + +compare-fsuuid() +{ + local uuids=($($LSBLK -n -o UUID $1 $2 2>/dev/null)) + if [ ${#uuids[@]} -eq 2 ] && [ "${uuids[0]}" = "${uuids[1]}" ]; then + return 0 + fi + return 1 +} + +##################################################################### +# gets a list of available kernels from /boot/grub2/grub.cfg +# kernels are in the array $KERNELS +get-kernels() +{ + local I DUMMY MNT ROOTDEV + declare -i I=0 + + # we need the root partition later to decide if this is the kernel to select + while read ROOTDEV MNT DUMMY; do + [ "$ROOTDEV" = "rootfs" ] && continue # not what we are searching for + if [ "$MNT" = "/" ]; then + break + fi + done < /proc/mounts + + + while read -r LINE; do + case $LINE in + menuentry\ *) + local PATTERN="^\\s*menuentry\\s\\+\\(.\\+\\)\\s*{.*\$" + MENUENTRY_OPTS=`echo "$LINE" | sed -n -e "s/${PATTERN}/\\1/p"` + MENU_ENTRIES[$I]=`eval "printf \"%s\n\" $MENUENTRY_OPTS | head -1"` + ;; + set\ default*) + local DEFAULT=${LINE#*default=} + + if echo $DEFAULT | grep -q saved_entry ; then + local SAVED=`$GRUB_EDITENV $GRUB_ENV list | sed -n s/^saved_entry=//p` + if [ -n "$SAVED" ]; then + DEFAULT_BOOT=$($GRUB_ONCE --show-mapped "$SAVED") + fi + fi + + ;; + linux*noresume*|module*xen*noresume*) + echo " Skipping ${MENU_ENTRIES[$I]}, because it has the noresume option" >&2 + ;; + linux*root=*|module*xen*root=*) + local ROOT + ROOT=${LINE#*root=} + DUMMY=($ROOT) + ROOT=${DUMMY[0]} + + if [ x"${ROOT:0:5}" = "xUUID=" ]; then + UUID=${ROOT#UUID=} + if [ -n "$UUID" ]; then + ROOT=$($BLKID -U $UUID || true) + if [ -z "$ROOT" ]; then + echo " Skipping ${MENU_ENTRIES[$I]}, because its root device $UUID is not found" >&2 + continue + fi + fi + fi + + if [ "$(stat -Lc '%t:%T' $ROOT || true)" != "$(stat -Lc '%t:%T' $ROOTDEV || true)" ]; then + if compare-fsuuid "$ROOT" "$ROOTDEV" ; then + echo " $ROOTDEV and $ROOT have the same filesystem UUID" + else + echo " Skipping ${MENU_ENTRIES[$I]}, because its root= parameter ($ROOT)" >&2 + echo " does not match the current root device ($ROOTDEV)." >&2 + continue + fi + fi + + DUMMY=($LINE) # kernel (hd0,1)/boot/vmlinuz-ABC root=/dev/hda2 + KERNELS[$I]=${DUMMY[1]##*/} # vmlinuz-ABC + # DEBUG "Found kernel entry #${I}: '${DUMMY[1]##*/}'" INFO + let ++I + ;; + linux*|module*xen*) + # a kernel without "root="? We better skip that one... + echo " Skipping ${MENU_ENTRIES[$I]}, because it has no root= option" >&2 + ;; + *) ;; + esac + done < "$GRUB_CONF" +} + +############################################################# +# restore grub default after (eventually failed) resume +grub-once-restore() +{ + echo "INFO: Running grub-once-restore .." + check-system + $GRUB_EDITENV $GRUB_ENV unset next_entry + echo "INFO: Done." +} + +############################################################################# +# try to find a kernel image that matches the actually running kernel. +# We need this, if more than one kernel is installed. This works reasonably +# well with grub, if all kernels are named "vmlinuz-`uname -r`" and are +# located in /boot. If they are not, good luck ;-) +# for 2021-style usrmerged kernels, the location in /usr/lib/modules/ \ +# `uname -r`/vmlinuz is resolved to match... +find-kernel-entry() +{ + NEXT_BOOT="" + declare -i I=0 + # DEBUG "running kernel: $RUNNING" DIAG + while [ -n "${KERNELS[$I]}" ]; do + BOOTING="${KERNELS[$I]}" + if IMAGE=$(readlink /boot/"$BOOTING"); then + if [[ $IMAGE == */vmlinuz ]]; then # new usrmerged setup + BOOTING=${IMAGE%/vmlinuz} # the directory name is what counts + BOOTING=${BOOTING##*/} + elif [ -e "/boot/${IMAGE##*/}" ]; then + # DEBUG "Found kernel symlink $BOOTING => $IMAGE" INFO + BOOTING=$IMAGE + fi + fi + BOOTING="${BOOTING#*${VMLINUZ}-}" + if [ "$RUNNING" == "$BOOTING" -a -n "${MENU_ENTRIES[$I]}" ]; then + NEXT_BOOT="${MENU_ENTRIES[$I]}" + echo " running kernel is grub menu entry $NEXT_BOOT (${KERNELS[$I]})" + break + fi + let ++I + done + # if we have not found a kernel, issue a warning. + # if we have found a kernel, we'll do "grub-once" later, after + # prepare_suspend finished. + if [ -z "$NEXT_BOOT" ]; then + echo "WARNING: no kernelfile matching the running kernel found" + fi +} + +############################################################################# +# if we did not find a kernel (or BOOT_LOADER is not GRUB) check, +# if the running kernel is still the one that will (probably) be booted for +# resume (default entry in menu.lst or, if there is none, the kernel file +# /boot/${VMLINUZ} points to.) +# This will only work, if you use "original" SUSE kernels. +# you can always override with the config variable set to "yes" +prepare-grub() +{ + echo "INFO: Running prepare-grub .." + check-system + get-kernels + RUNNING=`uname -r` + find-kernel-entry + + if [ -z "$NEXT_BOOT" ]; then + # which kernel is booted with the default entry? + BOOTING="${KERNELS[$DEFAULT_BOOT]}" + # if there is no default entry (no menu.lst?) we fall back to + # the default of /boot/${VMLINUZ}. + [ -z "$BOOTING" ] && BOOTING="${VMLINUZ}" + if IMAGE=$(readlink /boot/"$BOOTING"); then + if [[ $IMAGE == */vmlinuz ]]; then # new usrmerged setup + BOOTING=${IMAGE%/vmlinuz} # the directory name is what counts + BOOTING=${BOOTING##*/} + elif [ -e "/boot/${IMAGE##*/}" ]; then + BOOTING=$IMAGE + fi + fi + BOOTING="${BOOTING#*${VMLINUZ}-}" + echo "running kernel: '$RUNNING', probably booting kernel: '$BOOTING'" + check-setup "$RUNNING" + if [ "$BOOTING" != "$RUNNING" ]; then + error_quit "ERROR: kernel version mismatch, cannot suspend to disk" + fi + else + # set the bootloader to the running kernel + echo " preparing boot-loader: selecting entry $NEXT_BOOT, kernel /boot/$BOOTING" + T1=`date +"%s%N"` + sync; sync; sync # this is needed to speed up grub-once on reiserfs + T2=`date +"%s%N"` + check-setup "$RUNNING" + echo " running $GRUB_ONCE \"${NEXT_BOOT}\"" + ${GRUB_ONCE} "$NEXT_BOOT" + T3=`date +"%s%N"` + S=$(((T2-T1)/100000000)); S="$((S/10)).${S:0-1}" + G=$(((T3-T2)/100000000)); G="$((G/10)).${G:0-1}" + echo " time needed for sync: $S seconds, time needed for grub: $G seconds." + fi + + echo "INFO: Done." +} + +############################################################################# +check-setup() +{ + local WANT="$VMLINUZ-$1" + + [ -n "$GRUB_SETUP" ] || return 0 + # implementation below is s390x-only (for now) + echo "INFO: check-setup \"$WANT\" .." + HAVE="/boot/zipl/$VMLINUZ" + [ -r "$HAVE" ] || + error_quit "ERROR: no zipl kernel, cannot suspend to disk" + HAVE=$(readlink $HAVE) || + error_quit "ERROR: zipl kernel no sym-link, cannot suspend to disk" + [ "$HAVE" != "$WANT" ] || + { echo " zipl kernel already in sync, nothing to do"; return; } + echo " running $GRUB_SETUP # (incl. dracut!)" # no --image as running is preferred! + ${GRUB_SETUP} > /dev/null 2>&1 +} + +###### main() + +eval `grep LOADER_TYPE= /etc/sysconfig/bootloader` + +if [ x"$LOADER_TYPE" != "xgrub2" -a x"$LOADER_TYPE" != "xgrub2-efi" ]; then + echo "INFO: Skip running $0 for bootloader: $LOADER_TYPE" + exit 0 +fi + +if [ "$2" = suspend ]; then + echo "INFO: Skip running $0 for $2" + exit 0 +else + echo "INFO: running $0 for $2" +fi + +if [ "$1" = pre ] ; then + prepare-grub +fi +if [ "$1" = post ] ; then + grub-once-restore +fi diff --git a/grub2-use-Unifont-for-starfield-theme-terminal.patch b/grub2-use-Unifont-for-starfield-theme-terminal.patch new file mode 100644 index 0000000..b0ddea5 --- /dev/null +++ b/grub2-use-Unifont-for-starfield-theme-terminal.patch @@ -0,0 +1,15 @@ +DejaVu Sans is proportional font and looks pretty bad in terminal +window. Use GNU Unifont instead. +Index: grub-2.02~beta2/themes/starfield/theme.txt +=================================================================== +--- grub-2.02~beta2.orig/themes/starfield/theme.txt ++++ grub-2.02~beta2/themes/starfield/theme.txt +@@ -25,7 +25,7 @@ message-font: "DejaVu Sans Regular 12" + message-color: "#000" + message-bg-color: "#fff" + terminal-box: "terminal_box_*.png" +-terminal-font: "DejaVu Sans Regular 12" ++terminal-font: "Gnu Unifont Mono Regular 16" + desktop-image: "starfield.png" + + #help bar at the bottom diff --git a/grub2-use-rpmsort-for-version-sorting.patch b/grub2-use-rpmsort-for-version-sorting.patch new file mode 100644 index 0000000..caf31fc --- /dev/null +++ b/grub2-use-rpmsort-for-version-sorting.patch @@ -0,0 +1,12 @@ +diff -urN grub-2.02~beta2.old/util/grub-mkconfig_lib.in grub-2.02~beta2/util/grub-mkconfig_lib.in +--- grub-2.02~beta2.old/util/grub-mkconfig_lib.in 2014-04-11 15:20:42.451394845 +0200 ++++ grub-2.02~beta2/util/grub-mkconfig_lib.in 2014-04-11 15:58:02.940618803 +0200 +@@ -229,7 +229,7 @@ + version_test_numeric_a="$version_test_numeric_b" + version_test_numeric_b="$version_test_numeric_c" + fi +- if (echo "$version_test_numeric_a" ; echo "$version_test_numeric_b") | version_sort | head -n 1 | grep -qx "$version_test_numeric_b" ; then ++ if [ "`printf '%s\n' "$version_test_gt_a" "$version_test_gt_b" | /usr/lib/rpm/rpmsort -r | head -n1`" = "$version_test_gt_a" ] ; then + return 0 + else + return 1 diff --git a/grub2-util-30_os-prober-multiple-initrd.patch b/grub2-util-30_os-prober-multiple-initrd.patch new file mode 100644 index 0000000..2d2c60f --- /dev/null +++ b/grub2-util-30_os-prober-multiple-initrd.patch @@ -0,0 +1,22 @@ +Index: grub-2.02/util/grub.d/30_os-prober.in +=================================================================== +--- grub-2.02.orig/util/grub.d/30_os-prober.in ++++ grub-2.02/util/grub.d/30_os-prober.in +@@ -216,7 +216,7 @@ EOF + LBOOT="`echo ${LINUX} | cut -d ':' -f 2`" + LLABEL="`echo ${LINUX} | cut -d ':' -f 3 | tr '^' ' '`" + LKERNEL="`echo ${LINUX} | cut -d ':' -f 4`" +- LINITRD="`echo ${LINUX} | cut -d ':' -f 5`" ++ LINITRD="`echo ${LINUX} | cut -d ':' -f 5 | tr '^' ' '`" + LPARAMS="`echo ${LINUX} | cut -d ':' -f 6- | tr '^' ' '`" + + if [ -z "${LLABEL}" ] ; then +@@ -225,7 +225,7 @@ EOF + + if [ "${LROOT}" != "${LBOOT}" ]; then + LKERNEL="${LKERNEL#/boot}" +- LINITRD="${LINITRD#/boot}" ++ LINITRD="$(echo $LINITRD | sed -e 's!^/boot!!' -e 's!\(\s\)/boot!\1!g')" + fi + + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" diff --git a/grub2-vbe-blacklist-preferred-1440x900x32.patch b/grub2-vbe-blacklist-preferred-1440x900x32.patch new file mode 100644 index 0000000..055c844 --- /dev/null +++ b/grub2-vbe-blacklist-preferred-1440x900x32.patch @@ -0,0 +1,20 @@ +Index: grub-2.02~beta2/grub-core/video/i386/pc/vbe.c +=================================================================== +--- grub-2.02~beta2.orig/grub-core/video/i386/pc/vbe.c ++++ grub-2.02~beta2/grub-core/video/i386/pc/vbe.c +@@ -1053,6 +1053,15 @@ grub_video_vbe_setup (unsigned int width + || vbe_mode_info.y_resolution > height) + /* Resolution exceeds that of preferred mode. */ + continue; ++ ++ /* Blacklist 1440x900x32 from preferred mode handling until a ++ better solution is available. This mode causes problems on ++ many Thinkpads. ++ */ ++ if (vbe_mode_info.x_resolution == 1440 && ++ vbe_mode_info.y_resolution == 900 && ++ vbe_mode_info.bits_per_pixel == 32) ++ continue; + } + else + { diff --git a/grub2-video-limit-the-resolution-for-fixed-bimap-font.patch b/grub2-video-limit-the-resolution-for-fixed-bimap-font.patch new file mode 100644 index 0000000..4866d9d --- /dev/null +++ b/grub2-video-limit-the-resolution-for-fixed-bimap-font.patch @@ -0,0 +1,90 @@ +From 5f7f27d1198ef425f4943cc10132509415bbaf55 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Thu, 24 Jan 2019 16:41:04 +0800 +Subject: [PATCH] video: limit the resolution for fixed bimap font + +As grub uses fixed bitmap font and also its size is a fixed property, it is not +possible to accommodate to all resolutions, therefore we raise some limit to +the preferred resolution as most themes are designed on popular device and the +resolution in its prime, which is supposedly Full HD. + +This change also makes grub font readable on hiDPI device without going through +the steps in. + +https://wiki.archlinux.org/index.php/HiDPI#GRUB + +v2: efi_gop: Avoid high resolution when trying to keep current mode. + +--- + grub-core/video/efi_gop.c | 7 +++++++ + grub-core/video/i386/pc/vbe.c | 8 +++++++- + 2 files changed, 14 insertions(+), 1 deletion(-) + +Index: grub-2.02/grub-core/video/efi_gop.c +=================================================================== +--- grub-2.02.orig/grub-core/video/efi_gop.c ++++ grub-2.02/grub-core/video/efi_gop.c +@@ -360,7 +360,7 @@ grub_video_gop_setup (unsigned int width + grub_err_t err; + unsigned bpp; + int found = 0; +- int avoid_low_resolution = 1; ++ int avoid_extreme_resolution = 1; + unsigned long long best_volume = 0; + unsigned int preferred_width = 0, preferred_height = 0; + grub_uint8_t *buffer; +@@ -377,13 +377,21 @@ grub_video_gop_setup (unsigned int width + preferred_height = 600; + grub_errno = GRUB_ERR_NONE; + } ++ else ++ { ++ /* Limit the range of preferred resolution not exceeding FHD ++ to keep the fixed bitmap font readable */ ++ preferred_width = (preferred_width < 1920) ? preferred_width : 1920; ++ preferred_height = (preferred_height < 1080) ? preferred_height : 1080; ++ } + } + + again: + /* Keep current mode if possible. */ + if (gop->mode->info && +- (!avoid_low_resolution || +- (gop->mode->info->width >= 800 && gop->mode->info->height >= 600))) ++ (!avoid_extreme_resolution || ++ ((gop->mode->info->width >= 800 && gop->mode->info->height >= 600) && ++ (gop->mode->info->width <= 1920 && gop->mode->info->height <= 1080)))) + { + bpp = grub_video_gop_get_bpp (gop->mode->info); + if (bpp && ((width == gop->mode->info->width +@@ -456,9 +464,9 @@ again: + + if (!found) + { +- if (avoid_low_resolution && gop->mode->info) ++ if (avoid_extreme_resolution && gop->mode->info) + { +- avoid_low_resolution = 0; ++ avoid_extreme_resolution = 0; + goto again; + } + grub_dprintf ("video", "GOP: no mode found\n"); +Index: grub-2.02/grub-core/video/i386/pc/vbe.c +=================================================================== +--- grub-2.02.orig/grub-core/video/i386/pc/vbe.c ++++ grub-2.02/grub-core/video/i386/pc/vbe.c +@@ -994,7 +994,13 @@ grub_video_vbe_setup (unsigned int width + { + grub_vbe_get_preferred_mode (&width, &height); + if (grub_errno == GRUB_ERR_NONE) +- preferred_mode = 1; ++ { ++ preferred_mode = 1; ++ /* Limit the range of preferred resolution not exceeding FHD ++ to keep the fixed bitmap font readable */ ++ width = (width < 1920) ? width : 1920; ++ height = (height < 1080) ? height : 1080; ++ } + else + { + /* Fall back to 640x480. This is conservative, but the largest diff --git a/grub2-xen-linux16.patch b/grub2-xen-linux16.patch new file mode 100644 index 0000000..a01dca8 --- /dev/null +++ b/grub2-xen-linux16.patch @@ -0,0 +1,31 @@ +Index: grub-2.02~beta2/grub-core/loader/i386/xen.c +=================================================================== +--- grub-2.02~beta2.orig/grub-core/loader/i386/xen.c ++++ grub-2.02~beta2/grub-core/loader/i386/xen.c +@@ -688,7 +688,7 @@ fail: + return grub_errno; + } + +-static grub_command_t cmd_xen, cmd_initrd, cmd_module, cmd_multiboot; ++static grub_command_t cmd_xen, cmd_initrd, cmd_module, cmd_multiboot, cmd_xen16, cmd_initrd16; + + GRUB_MOD_INIT (xen) + { +@@ -700,6 +700,10 @@ GRUB_MOD_INIT (xen) + 0, N_("Load initrd.")); + cmd_module = grub_register_command ("module", grub_cmd_module, + 0, N_("Load module.")); ++ cmd_xen16 = grub_register_command ("linux16", grub_cmd_xen, ++ 0, N_("Load Linux.")); ++ cmd_initrd16 = grub_register_command ("initrd16", grub_cmd_initrd, ++ 0, N_("Load initrd.")); + my_mod = mod; + } + +@@ -709,4 +713,6 @@ GRUB_MOD_FINI (xen) + grub_unregister_command (cmd_initrd); + grub_unregister_command (cmd_multiboot); + grub_unregister_command (cmd_module); ++ grub_unregister_command (cmd_xen16); ++ grub_unregister_command (cmd_initrd16); + } diff --git a/grub2-xen-pv-firmware.cfg b/grub2-xen-pv-firmware.cfg new file mode 100644 index 0000000..11a2256 --- /dev/null +++ b/grub2-xen-pv-firmware.cfg @@ -0,0 +1,158 @@ +insmod part_msdos +insmod part_gpt +insmod search +insmod configfile +insmod legacy_configfile +insmod lvm +insmod mdraid09 +insmod mdraid1x + +set debian_cddev="" +set debian_cdarch="" +if [ "${grub_cpu}" = "x86_64" ]; then + debian_cdarch="amd" +fi +if [ "${grub_cpu}" = "i386" ]; then + debian_cdarch="i386" +fi +if [ -n "${debian_cdarch}" ]; then + set debian_kern="/install.${debian_cdarch}/xen/vmlinuz" + set debian_initrd="/install.${debian_cdarch}/xen/initrd.gz" + search -s debian_domUcfg -f "/install.${debian_cdarch}/xen/debian.cfg" + search -s debian_cdkern -f "${debian_kern}" + search -s debian_cdinitrd -f "${debian_initrd}" + if [ -n "${debian_domUcfg}" -a -n "${debian_cdinitrd}" -a -n "${debian_cdkern}" -a "${debian_domUcfg}" = "${debian_cdinitrd}" -a "${debian_domUcfg}" = "${debian_cdkern}" ]; then + debian_cddev="${debian_domUcfg}" + fi +fi + +set fedora_cddev="" +if [ "${grub_cpu}" = "x86_64" ]; then + set fedora_kern="/images/pxeboot/vmlinuz" + set fedora_initrd="/images/pxeboot/initrd.img" + search -s fedora_cdkern -f "${fedora_kern}" + search -s fedora_cdinitrd -f "${fedora_initrd}" + if [ -n "${fedora_cdkern}" -a -n "${fedora_cdinitrd}" -a "${fedora_cdkern}" = "${fedora_cdinitrd}" ]; then + set fedora_cddev="${fedora_cdkern}" + fi +fi + +set suse_cddev="" +if [ "${grub_cpu}" = "i386" ]; then + set suse_cdarch="i586" +else + set suse_cdarch="${grub_cpu}" +fi +if [ -n "${suse_cdarch}" ]; then + set suse_kern="/boot/${suse_cdarch}/loader/linux" + set suse_initrd="/boot/${suse_cdarch}/loader/initrd" + search -s suse_cdkern -f "${suse_kern}" + search -s suse_cdinitrd -f "${suse_initrd}" + if [ -n "${suse_cdkern}" -a -n "${suse_cdinitrd}" -a "${suse_cdkern}" = "${suse_cdinitrd}" ]; then + set suse_cddev="${suse_cdkern}" + fi +fi + +set hdcfg_list="\ +/boot/grub2/grub.cfg \ +/grub2/grub.cfg\ +" + +set hdlst_list="\ +/boot/grub/menu.lst \ +/grub/menu.lst\ +" + +for c in ${hdcfg_list}; do + btrfs_relative_path=1 + if search -s hddev -f "${c}"; then + btrfs_relative_path=0 + menuentry "${hddev} Boot From Hard Disk (${c})" "${hddev}" "${c}" { + set root="${2}" + set cfg="${3}" + btrfs-get-default-subvol -p -o btrfs_default_subvol ($root) + if [ -n "${btrfs_default_subvol}" ]; then + configfile "${btrfs_default_subvol}${cfg}" + else + configfile "${cfg}" + fi + } + break + fi + btrfs_relative_path=0 +done + +for c in ${hdlst_list}; do + btrfs_relative_path=1 + if search -s hddev -f "${c}"; then + btrfs_relative_path=0 + menuentry "${hddev} Boot From Hard Disk (${c})" "${hddev}" "${c}" { + set root="${2}" + set cfg="${3}" + btrfs-get-default-subvol -p -o btrfs_default_subvol ($root) + if [ -n "${btrfs_default_subvol}" ]; then + legacy_configfile "${btrfs_default_subvol}${cfg}" + else + legacy_configfile "${cfg}" + fi + } + break + fi + btrfs_relative_path=0 +done + +set timeout=0 +if [ -n "${debian_cddev}" ]; then + set timeout=8 + menuentry "${debian_cddev} Debian Install" { + set root="${debian_cddev}" + linux "${debian_kern}" ignore_loglevel + initrd "${debian_initrd}" + } +fi + +if [ -n "${fedora_cddev}" ]; then + set timeout=8 + menuentry "${fedora_cddev} Fedora Install" { + set root="${fedora_cddev}" + linux "${fedora_kern}" ignore_loglevel + initrd "${fedora_initrd}" + } + menuentry "${fedora_cddev} Fedora Rescue" { + set root="${fedora_cddev}" + linux "${fedora_kern}" ignore_loglevel rescue + initrd "${fedora_initrd}" + } +fi + +if [ -n "${suse_cddev}" ]; then + set timeout=8 + set root="${suse_cddev}" + set suse_cdcfg="/boot/${suse_cdarch}/grub2-xen/grub.cfg" + if [ -e "/boot/${suse_cdarch}/vmlinuz-xen" ]; then + set suse_kern="/boot/${suse_cdarch}/vmlinuz-xen" + set suse_initrd="/boot/${suse_cdarch}/initrd-xen" + fi + if [ -f "${suse_cdcfg}" ]; then + menuentry "${suse_cddev} SUSE Install menu" { + set root="${suse_cddev}" + configfile "${suse_cdcfg}" + } + elif [ -f "${suse_kern}" -a -f "$suse_initrd" ]; then + menuentry "${suse_cddev} SUSE Install" { + linux "${suse_kern}" xencons=hvc0 + initrd "${suse_initrd}" + } + menuentry "${suse_cddev} SUSE Rescue" { + linux "${suse_kern}" xencons=hvc0 rescue=1 + initrd "${suse_initrd}" + } + menuentry "${suse_cddev} SUSE Upgrade" { + linux "${suse_kern}" xencons=hvc0 upgrade=1 + initrd "${suse_initrd}" + } + else + echo "the device ${suse_cddev} is not xen pv bootable" + fi +fi + diff --git a/grub2-zipl-setup-fix-btrfs-multipledev.patch b/grub2-zipl-setup-fix-btrfs-multipledev.patch new file mode 100644 index 0000000..895103d --- /dev/null +++ b/grub2-zipl-setup-fix-btrfs-multipledev.patch @@ -0,0 +1,17 @@ +--- + util/s390x/zipl2grub.pl.in | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/util/s390x/zipl2grub.pl.in ++++ b/util/s390x/zipl2grub.pl.in +@@ -384,6 +384,10 @@ while ( ) { + } else { + $v = ""; + } ++ if ($k eq "GRUB_DEVICE" && $v !~ /^UUID/ && ! -e $v) { ++ s{root=\@$k\@}{}g; ++ next; ++ } + s{\@$k\@}{$v}g; + } + Info( 3, $_); diff --git a/grub2.changes b/grub2.changes new file mode 100644 index 0000000..75ef380 --- /dev/null +++ b/grub2.changes @@ -0,0 +1,2358 @@ +* Fri Oct 6 2023 mchang@suse.com +- Fix CVE-2023-4692 (bsc#1215935) +- Fix CVE-2023-4693 (bsc#1215936) + * 0001-fs-ntfs-Fix-an-OOB-write-when-parsing-the-ATTRIBUTE_.patch + * 0002-fs-ntfs-Fix-an-OOB-read-when-reading-data-from-the-r.patch + * 0003-fs-ntfs-Fix-an-OOB-read-when-parsing-directory-entri.patch + * 0004-fs-ntfs-Fix-an-OOB-read-when-parsing-bitmaps-for-ind.patch + * 0005-fs-ntfs-Fix-an-OOB-read-when-parsing-a-volume-label.patch + * 0006-fs-ntfs-Make-code-more-readable.patch +- Bump upstream SBAT generation to 4 +* Wed Sep 20 2023 mchang@suse.com +- Fix a boot delay regression in PowerPC PXE boot (bsc#1201300) + * 0001-ieee1275-ofdisk-retry-on-open-and-read-failure.patch +* Thu May 4 2023 mchang@suse.com +- grub2-once: Fix 'sh: terminal_output: command not found' error (bsc#1204563) +* Fri Apr 21 2023 mchang@suse.com +- Fix PowerVS deployment fails to boot with 90 cores (bsc#1208581) + * 0001-kern-ieee1275-init-Convert-plain-numbers-to-constant.patch + * 0002-kern-ieee1275-init-Extended-support-in-Vec5.patch +* Tue Apr 18 2023 mchang@suse.com +- Fix no prep partition error on non-PReP architectures by making the + prep_loadenv module exclusive to powerpc_ieee1275 platform (bsc#1210489) + * 0004-Introduce-prep_load_env-command.patch +- Fix the issue of freeing an uninitialized pointer + * 0002-prep_loadenv-Fix-regex-for-Open-Firmware-device-spec.patch +- Rediff + * 0005-export-environment-at-start-up.patch +* Tue Apr 11 2023 mchang@suse.com +- Resolve some issues with OS boot failure on PPC NVMe-oF disks and made + enhancements to PPC secure boot's root device discovery config (bsc#1207230) +- Ensure get_devargs and get_devname functions are consistent + * 0001-openfw-Ensure-get_devargs-and-get_devname-functions-.patch +- Fix regex for Open Firmware device specifier with encoded commas + * 0002-prep_loadenv-Fix-regex-for-Open-Firmware-device-spec.patch +- Fix regular expression in PPC secure boot config to prevent escaped commas + from being treated as delimiters when retrieving partition substrings. +- Use prep_load_env in PPC secure boot config to handle unset host-specific + environment variables and ensure successful command execution. + * 0004-Introduce-prep_load_env-command.patch +- Refreshed + * 0005-export-environment-at-start-up.patch +* Thu Apr 6 2023 mchang@suse.com +- Fix installation over serial console ends up in infinite boot loop + (bsc#1187810) (bsc#1209667) (bsc#1209372) + * 0001-Fix-infinite-boot-loop-on-headless-system-in-qemu.patch +* Thu Mar 23 2023 mchang@suse.com +- Fix aarch64 kiwi image's file not found due to '/@' prepended to path in + btrfs filesystem. (bsc#1209165) + * grub2-btrfs-05-grub2-mkconfig.patch +* Fri Mar 3 2023 mchang@suse.com +- Make grub more robust against storage race condition causing system boot + failures (bsc#1189036) + * 0001-ieee1275-ofdisk-retry-on-open-and-read-failure.patch +* Thu Feb 23 2023 glin@suse.com +- Move unsupported zfs modules into 'extras' packages + (bsc#1205554) (PED-2947) +* Wed Feb 22 2023 mchang@suse.com +- Fix out of memory error on lpar installation from virtual cdrom (bsc#1208024) + * 0001-ieee1275-Further-increase-initially-allocated-heap-f.patch + * 0002-tpm-Disable-tpm-verifier-if-tpm-is-not-present.patch +- Fix lpar got hung at grub after inactive migration (bsc#1207684) + * 0002-ieee1275-implement-vec5-for-cas-negotiation.patch +* Wed Feb 8 2023 mchang@suse.com +- Fix nvmf boot device setup (bsc#1207811) + * 0001-grub2-Can-t-setup-a-default-boot-device-correctly-on.patch +* Tue Feb 7 2023 mchang@suse.com +- Fix unknown filesystem error on disks with 4096 sector size (bsc#1207064) + * 0001-grub-core-modify-sector-by-sysfs-as-disk-sector.patch +* Fri Dec 23 2022 mchang@suse.com +- Make grub.cfg invariant to efi and legacy platforms (bsc#1205200) +- Removed patch linuxefi + * grub2-secureboot-provide-linuxefi-config.patch + * grub2-secureboot-use-linuxefi-on-uefi-in-os-prober.patch + * grub2-secureboot-use-linuxefi-on-uefi.patch +- Rediff + * grub2-btrfs-05-grub2-mkconfig.patch + * grub2-efi-xen-cmdline.patch + * grub2-s390x-05-grub2-mkconfig.patch + * grub2-suse-remove-linux-root-param.patch +* Mon Dec 19 2022 mchang@suse.com +- Setup multiple device paths for a nvmf boot device (bsc#1205666) + * 0001-grub2-Set-multiple-device-path-for-a-nvmf-boot-devic.patch +* Mon Dec 5 2022 mchang@suse.com +- Add tpm to signed grub.elf image (PED-1990) (bsc#1205912) +- Increase initial heap size from 1/4 to 1/3 + * 0001-ieee1275-Increase-initially-allocated-heap-from-1-4-.patch +* Tue Nov 22 2022 mchang@suse.com +- Support grub2-install on LUKS2 encrypted device + * 0001-devmapper-getroot-Have-devmapper-recognize-LUKS2.patch + * 0002-devmapper-getroot-Set-up-cheated-LUKS2-cryptodisk-mo.patch + * 0003-disk-cryptodisk-When-cheatmounting-use-the-sector-in.patch +* Fri Nov 4 2022 mchang@suse.com +- Security fixes and hardenings + * 0001-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch + * 0002-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch +- Fix CVE-2022-2601 (bsc#1205178) + * 0003-font-Fix-several-integer-overflows-in-grub_font_cons.patch + * 0004-font-Remove-grub_font_dup_glyph.patch + * 0005-font-Fix-integer-overflow-in-ensure_comb_space.patch + * 0006-font-Fix-integer-overflow-in-BMP-index.patch + * 0007-font-Fix-integer-underflow-in-binary-search-of-char-.patch + * 0008-fbutil-Fix-integer-overflow.patch +- Fix CVE-2022-3775 (bsc#1205182) + * 0009-font-Fix-an-integer-underflow-in-blit_comb.patch + * 0010-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch + * 0011-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch + * 0012-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch +- Bump upstream SBAT generation to 3 +* Fri Oct 28 2022 mchang@suse.com +- NVMeoFC support on grub (jsc#PED-996) + * 0001-ieee1275-add-support-for-NVMeoFC.patch + * 0002-ieee1275-ofpath-enable-NVMeoF-logical-device-transla.patch + * 0003-ieee1275-change-the-logic-of-ieee1275_get_devargs.patch + * 0004-ofpath-controller-name-update.patch +- TDX: Enhance grub2 measurement to TD RTMR (jsc#PED-1265) + * 0001-commands-efi-tpm-Refine-the-status-of-log-event.patch + * 0002-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch + * 0003-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch +- Measure the kernel on POWER10 and extend TPM PCRs (PED-1990) + * 0001-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch + * 0002-ieee1275-implement-vec5-for-cas-negotiation.patch +* Mon Oct 24 2022 mchang@suse.com +- Include loopback into signed grub2 image (jsc#PED-2150) +* Tue Oct 4 2022 mchang@suse.com +- Add patches for automatic TPM disk unlock (jsc#SLE-24018) (bsc#1196668) (jsc#PED-1276) + * 0001-luks2-Add-debug-message-to-align-with-luks-and-geli-.patch + * 0002-cryptodisk-Refactor-to-discard-have_it-global.patch + * 0003-cryptodisk-Return-failure-in-cryptomount-when-no-cry.patch + * 0004-cryptodisk-Improve-error-messaging-in-cryptomount-in.patch + * 0005-cryptodisk-Improve-cryptomount-u-error-message.patch + * 0006-cryptodisk-Add-infrastructure-to-pass-data-from-cryp.patch + * 0007-cryptodisk-Refactor-password-input-out-of-crypto-dev.patch + * 0008-cryptodisk-Move-global-variables-into-grub_cryptomou.patch + * 0009-cryptodisk-Improve-handling-of-partition-name-in-cry.patch + * 0010-protectors-Add-key-protectors-framework.patch + * 0011-tpm2-Add-TPM-Software-Stack-TSS.patch + * 0012-protectors-Add-TPM2-Key-Protector.patch + * 0013-cryptodisk-Support-key-protectors.patch + * 0014-util-grub-protect-Add-new-tool.patch +- Fix no disk unlocking happen (bsc#1196668) + * 0001-crytodisk-fix-cryptodisk-module-looking-up.patch +- Fix build error + * fix-tpm2-build.patch +* Fri Sep 16 2022 mchang@suse.com +- Fix installation failure due to unavailable nvram device on + ppc64le (bsc#1201361) + * 0001-grub-install-set-point-of-no-return-for-powerpc-ieee1275.patch +* Tue May 31 2022 mchang@suse.com +- Security fixes and hardenings for boothole 3 / boothole 2022 (bsc#1198581) + * 0001-video-Remove-trailing-whitespaces.patch + * 0002-loader-efi-chainloader-Simplify-the-loader-state.patch + * 0003-commands-boot-Add-API-to-pass-context-to-loader.patch +- Fix CVE-2022-28736 (bsc#1198496) + * 0004-loader-efi-chainloader-Use-grub_loader_set_ex.patch +- Fix CVE-2022-28735 (bsc#1198495) + * 0005-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch + * 0006-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch + * 0007-video-readers-png-Abort-sooner-if-a-read-operation-f.patch + * 0008-video-readers-png-Refuse-to-handle-multiple-image-he.patch +- Fix CVE-2021-3695 (bsc#1191184) + * 0009-video-readers-png-Drop-greyscale-support-to-fix-heap.patch +- Fix CVE-2021-3696 (bsc#1191185) + * 0010-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch + * 0011-video-readers-png-Sanity-check-some-huffman-codes.patch + * 0012-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch + * 0013-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch + * 0014-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch +- Fix CVE-2021-3697 (bsc#1191186) + * 0015-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch + * 0016-normal-charset-Fix-array-out-of-bounds-formatting-un.patch +- Fix CVE-2022-28733 (bsc#1198460) + * 0017-net-ip-Do-IP-fragment-maths-safely.patch + * 0018-net-netbuff-Block-overly-large-netbuff-allocs.patch + * 0019-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch + * 0020-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch + * 0021-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch + * 0022-net-tftp-Avoid-a-trivial-UAF.patch + * 0023-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch +- Fix CVE-2022-28734 (bsc#1198493) + * 0024-net-http-Fix-OOB-write-for-split-http-headers.patch +- Fix CVE-2022-28734 (bsc#1198493) + * 0025-net-http-Error-out-on-headers-with-LF-without-CR.patch + * 0026-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch + * 0027-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch + * 0028-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch + * 0029-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch + * 0030-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch + * 0031-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch + * 0032-Use-grub_loader_set_ex-for-secureboot-chainloader.patch +- Update SBAT security contact (boo#1193282) +- Bump grub's SBAT generation to 2 +* Tue May 31 2022 mchang@suse.com +- Use boot disks in OpenFirmware, fixing regression caused by + 0001-ieee1275-implement-FCP-methods-for-WWPN-and-LUNs.patch, when + the root LV is completely in the boot LUN (bsc#1197948) + * 0001-ofdisk-improve-boot-time-by-lookup-boot-disk-first.patch +* Thu Apr 21 2022 mchang@suse.com +- Fix Power10 LPAR error "The partition fails to activate as partition went + into invalid state" (bsc#1198714) + * 0001-powerpc-do-CAS-in-a-more-compatible-way.patch +* Fri Mar 11 2022 mchang@suse.com +- Fix grub-install error when efi system partition is created as mdadm software + raid1 device (bsc#1179981) (bsc#1195204) + * 0001-install-fix-software-raid1-on-esp.patch +* Thu Mar 10 2022 mchang@suse.com +- Fix riscv64 build error + * 0001-RISC-V-Adjust-march-flags-for-binutils-2.38.patch +* Thu Mar 10 2022 mchang@suse.com +- Fix error in grub-install when linux root device is on lvm thin volume + (bsc#1192622) (bsc#1191974) + * 0001-grub-install-bailout-root-device-probing.patch +* Fri Mar 4 2022 mchang@suse.com +- Support saving grub environment for POWER signed grub images (jsc#SLE-23854) + * 0001-Add-grub_envblk_buf-helper-function.patch + * 0002-Add-grub_disk_write_tail-helper-function.patch + * 0003-grub-install-support-prep-environment-block.patch + * 0004-Introduce-prep_load_env-command.patch + * 0005-export-environment-at-start-up.patch +- Use enviroment variable in early boot config to looking up root device + * grub2.spec +* Tue Mar 1 2022 msuchanek@suse.com +- Remove obsolete openSUSE 12.2 conditionals in spec file +- Clean up powerpc certificate handling. +* Thu Feb 10 2022 bjorn.lie@gmail.com +- Set grub2-check-default shebang to "#!/bin/bash", as the the code + uses many instructions which are undefined for a POSIX sh. + (boo#1195794). +* Fri Jan 14 2022 mchang@suse.com +- Power guest secure boot with static keys: GRUB2 signing portion + (jsc#SLE-18271) (bsc#1192764) + * 0001-grub-install-Add-SUSE-signed-image-support-for-power.patch +* Thu Jan 13 2022 mchang@suse.com +- Fix wrong default entry when booting snapshot (bsc#1159205) + * grub2-btrfs-08-workaround-snapshot-menu-default-entry.patch +* Tue Jan 11 2022 mchang@suse.com +- Power guest secure boot with static keys: GRUB2 signing portion + (jsc#SLE-18271) (bsc#1192764) + * grub2.spec +- Power guest secure boot with static keys: GRUB2 portion (jsc#SLE-18144) + (bsc#1192686) + * 0001-ieee1275-Drop-HEAP_MAX_ADDR-and-HEAP_MIN_SIZE-consta.patch + * 0002-ieee1275-claim-more-memory.patch + * 0003-ieee1275-request-memory-with-ibm-client-architecture.patch + * 0004-Add-suport-for-signing-grub-with-an-appended-signatu.patch + * 0005-docs-grub-Document-signing-grub-under-UEFI.patch + * 0006-docs-grub-Document-signing-grub-with-an-appended-sig.patch + * 0007-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch + * 0008-pgp-factor-out-rsa_pad.patch + * 0009-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch + * 0010-posix_wrap-tweaks-in-preparation-for-libtasn1.patch + * 0011-libtasn1-import-libtasn1-4.18.0.patch + * 0012-libtasn1-disable-code-not-needed-in-grub.patch + * 0013-libtasn1-changes-for-grub-compatibility.patch + * 0014-libtasn1-compile-into-asn1-module.patch + * 0015-test_asn1-test-module-for-libtasn1.patch + * 0016-grub-install-support-embedding-x509-certificates.patch + * 0017-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch + * 0018-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch + * 0019-appended-signatures-support-verifying-appended-signa.patch + * 0020-appended-signatures-verification-tests.patch + * 0021-appended-signatures-documentation.patch + * 0022-ieee1275-enter-lockdown-based-on-ibm-secure-boot.patch + * 0023-x509-allow-Digitial-Signature-plus-other-Key-Usages.patch +* Mon Jan 10 2022 mchang@suse.com +- Fix no menuentry is found if hibernation on btrfs RAID1 (bsc#1193090) + * grub2-systemd-sleep-plugin +* Tue Dec 21 2021 mchang@suse.com +- Fix CVE-2021-3981 (bsc#1189644) + * 0001-grub-mkconfig-restore-umask-for-grub.cfg.patch +* Fri Dec 17 2021 mchang@suse.com +- Fix can't allocate initrd error (bsc#1191378) + * 0001-Factor-out-grub_efi_linux_boot.patch + * 0002-Fix-race-in-EFI-validation.patch + * 0003-Handle-multi-arch-64-on-32-boot-in-linuxefi-loader.patch + * 0004-Try-to-pick-better-locations-for-kernel-and-initrd.patch + * 0005-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch + * 0006-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch + * 0007-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch + * 0008-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch + * 0009-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch + * 0010-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch + * 0011-Also-define-GRUB_EFI_MAX_ALLOCATION_ADDRESS-for-RISC.patch +* Wed Dec 8 2021 msuchanek@suse.com +- Add support for simplefb (boo#1193532). + + grub2-simplefb.patch +* Mon Dec 6 2021 mchang@suse.com +- Fix extent not found when initramfs contains shared extents (bsc#1190982) + * 0001-fs-btrfs-Make-extent-item-iteration-to-handle-gaps.patch +* Thu Nov 11 2021 mchang@suse.com +- Fix arm64 kernel image not aligned on 64k boundary (bsc#1192522) + * 0001-arm64-Fix-EFI-loader-kernel-image-allocation.patch + * 0002-Arm-check-for-the-PE-magic-for-the-compiled-arch.patch +* Thu Oct 21 2021 mchang@suse.com +- Remove openSUSE Tumbleweed specific handling for default grub + distributor (bsc#1191198) +- Use /usr/lib/os-release as fallback (bsc#1191196) + * grub2-default-distributor.patch + * grub2-check-default.sh +- VUL-0: grub2: grub2-once uses fixed file name in /var/tmp (bsc#1190474) (CVE-2021-46705) + * grub2-once + * grub2-once.service +- Fix unknown TPM error on buggy uefi firmware (bsc#1191504) + * 0001-tpm-Pass-unknown-error-as-non-fatal-but-debug-print-.patch +- Fix error /boot/grub2/locale/POSIX.gmo not found (bsc#1189769) + * 0001-Filter-out-POSIX-locale-for-translation.patch +- Fix error lvmid disk cannot be found after second disk added to the root + volume group (bsc#1189874) (bsc#1071559) + * 0001-ieee1275-implement-FCP-methods-for-WWPN-and-LUNs.patch +- Fix error in grub installation due to unnecessary requirement to support + excessive device for the root logical volume (bsc#1184135) + * 0001-disk-diskfilter-Use-nodes-in-logical-volume-s-segmen.patch +- Fix regression in reading xfs v4 + * 0001-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch +* Tue Oct 19 2021 fvogt@suse.com +- Fix installation on usrmerged s390x +* Wed Sep 22 2021 rw@suse.com +- Improve support for SLE Micro 5.1 on s390x. (bsc#1190395) + * amend grub2-s390x-04-grub2-install.patch + * refresh grub2-s390x-11-secureboot.patch +* Tue Sep 7 2021 mchang@suse.com +- Follow usr merge for looking up kernel config (bsc#1189782) (bsc#1190061) + * 0001-templates-Follow-the-path-of-usr-merged-kernel-confi.patch +* Wed Sep 1 2021 mchang@suse.com +- Add btrfs zstd compression on i386-pc and also make sure it won't break + existing grub installations (bsc#1161823) + * deleted 0001-btrfs-disable-zstd-support-for-i386-pc.patch + * added 0001-i386-pc-build-btrfs-zstd-support-into-separate-modul.patch +* Tue Aug 31 2021 pvorel@suse.cz +- Delete the author list from %%description (the %%description section is + literally for package descriptions (only) these days, encoding was also + problematic). +- Add %%doc AUTHORS to get packaged that info +* Wed Aug 4 2021 seife+obs@b1-systems.com +- update grub2-systemd-sleep.sh to fix hibernation by avoiding the + error "no kernelfile matching the running kernel found" on + usrmerged setup +* Wed Aug 4 2021 fvogt@suse.com +- Use %%autosetup +* Thu Jul 22 2021 pvorel@suse.cz +- Replace grub2-use-stat-instead-of-udevadm-for-partition-lookup.patch and + fix-grub2-use-stat-instead-of-udevadm-for-partition-lookup-with-new-glibc.patch + with upstream backport: + 0001-osdep-Introduce-include-grub-osdep-major.h-and-use-i.patch and + 0002-osdep-linux-hostdisk-Use-stat-instead-of-udevadm-for.patch. +* Mon Jun 28 2021 mchang@suse.com +- Fix error not a btrfs filesystem on s390x (bsc#1187645) + * 80_suse_btrfs_snapshot +* Wed Jun 23 2021 mchang@suse.com +- Fix error gfxterm isn't found with multiple terminals (bsc#1187565) + * grub2-fix-error-terminal-gfxterm-isn-t-found.patch +* Mon Jun 21 2021 mchang@suse.com +- Fix boot failure after kdump due to the content of grub.cfg is not + completed with pending modificaton in xfs journal (bsc#1186975) + * grub-install-force-journal-draining-to-ensure-data-i.patch +- Patch refreshed + * grub2-mkconfig-default-entry-correction.patch +* Thu Jun 3 2021 mchang@suse.com +- Version bump to 2.06 + * rediff + - 0001-add-support-for-UEFI-network-protocols.patch + - 0002-net-read-bracketed-ipv6-addrs-and-port-numbers.patch + - 0003-Make-grub_error-more-verbose.patch + - 0003-bootp-New-net_bootp6-command.patch + - 0005-grub.texi-Add-net_bootp6-doument.patch + - 0006-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch + - 0006-efi-Set-image-base-address-before-jumping-to-the-PE-.patch + - 0008-efinet-Setting-DNS-server-from-UEFI-protocol.patch + - 0046-squash-verifiers-Move-verifiers-API-to-kernel-image.patch + - grub-install-force-journal-draining-to-ensure-data-i.patch + - grub2-btrfs-01-add-ability-to-boot-from-subvolumes.patch + - grub2-diskfilter-support-pv-without-metadatacopies.patch + - grub2-efi-HP-workaround.patch + - grub2-efi-xen-cfg-unquote.patch + - grub2-efi-xen-chainload.patch + - grub2-fix-menu-in-xen-host-server.patch + - grub2-gfxmenu-support-scrolling-menu-entry-s-text.patch + - grub2-install-remove-useless-check-PReP-partition-is-empty.patch + - grub2-lvm-allocate-metadata-buffer-from-raw-contents.patch + - grub2-mkconfig-default-entry-correction.patch + - grub2-pass-corret-root-for-nfsroot.patch + - grub2-s390x-03-output-7-bit-ascii.patch + - grub2-s390x-04-grub2-install.patch + - grub2-secureboot-install-signed-grub.patch + - grub2-setup-try-fs-embed-if-mbr-gap-too-small.patch + - use-grub2-as-a-package-name.patch + * update by patch squashed: + - 0001-Add-support-for-Linux-EFI-stub-loading-on-aarch64.patch + - grub2-efi-chainload-harder.patch + - grub2-secureboot-no-insmod-on-sb.patch + - grub2-secureboot-chainloader.patch + - grub2-secureboot-add-linuxefi.patch + * remove squashed patches: + - 0008-squash-Add-support-for-Linux-EFI-stub-loading-on-aar.patch + - 0009-squash-Add-support-for-linuxefi.patch + - 0041-squash-Add-secureboot-support-on-efi-chainloader.patch + - 0042-squash-grub2-efi-chainload-harder.patch + - 0043-squash-Don-t-allow-insmod-when-secure-boot-is-enable.patch + - 0045-squash-Add-support-for-Linux-EFI-stub-loading-on-aar.patch + * drop upstream patches: + - 0001-Warn-if-MBR-gap-is-small-and-user-uses-advanced-modu.patch + - 0001-include-grub-i386-linux.h-Include-missing-grub-types.patch + - 0001-kern-efi-sb-Add-chainloaded-image-as-shim-s-verifiab.patch + - 0001-mdraid1x_linux-Fix-gcc10-error-Werror-array-bounds.patch + - 0001-normal-Move-common-datetime-functions-out-of-the-nor.patch + - 0001-yylex-Make-lexer-fatal-errors-actually-be-fatal.patch + - 0002-efi-Make-shim_lock-GUID-and-protocol-type-public.patch + - 0002-grub-install-Avoid-incompleted-install-on-i386-pc.patch + - 0002-kern-Add-X-option-to-printf-functions.patch + - 0002-safemath-Add-some-arithmetic-primitives-that-check-f.patch + - 0002-zfs-Fix-gcc10-error-Werror-zero-length-bounds.patch + - 0003-calloc-Make-sure-we-always-have-an-overflow-checking.patch + - 0003-efi-Return-grub_efi_status_t-from-grub_efi_get_varia.patch + - 0003-normal-main-Search-for-specific-config-files-for-net.patch + - 0004-calloc-Use-calloc-at-most-places.patch + - 0004-datetime-Enable-the-datetime-module-for-the-emu-plat.patch + - 0004-efi-Add-a-function-to-read-EFI-variables-with-attrib.patch + - 0005-Make-linux_arm_kernel_header.hdr_offset-be-at-the-ri.patch + - 0005-efi-Add-secure-boot-detection.patch + - 0005-malloc-Use-overflow-checking-primitives-where-we-do-.patch + - 0006-efi-Only-register-shim_lock-verifier-if-shim_lock-pr.patch + - 0006-iso9660-Don-t-leak-memory-on-realloc-failures.patch + - 0007-font-Do-not-load-more-than-one-NAME-section.patch + - 0007-verifiers-Move-verifiers-API-to-kernel-image.patch + - 0008-efi-Move-the-shim_lock-verifier-to-the-GRUB-core.patch + - 0008-script-Remove-unused-fields-from-grub_script_functio.patch + - 0009-kern-Add-lockdown-support.patch + - 0009-script-Avoid-a-use-after-free-when-redefining-a-func.patch + - 0010-kern-lockdown-Set-a-variable-if-the-GRUB-is-locked-d.patch + - 0010-linux-Fix-integer-overflows-in-initrd-size-handling.patch + - 0011-efi-Lockdown-the-GRUB-when-the-UEFI-Secure-Boot-is-e.patch + - 0012-efi-Use-grub_is_lockdown-instead-of-hardcoding-a-dis.patch + - 0013-acpi-Don-t-register-the-acpi-command-when-locked-dow.patch + - 0014-mmap-Don-t-register-cutmem-and-badram-commands-when-.patch + - 0015-commands-Restrict-commands-that-can-load-BIOS-or-DT-.patch + - 0016-commands-setpci-Restrict-setpci-command-when-locked-.patch + - 0017-commands-hdparm-Restrict-hdparm-command-when-locked-.patch + - 0018-gdb-Restrict-GDB-access-when-locked-down.patch + - 0019-loader-xnu-Don-t-allow-loading-extension-and-package.patch + - 0020-dl-Only-allow-unloading-modules-that-are-not-depende.patch + - 0021-usb-Avoid-possible-out-of-bound-accesses-caused-by-m.patch + - 0022-lib-arg-Block-repeated-short-options-that-require-an.patch + - 0023-commands-menuentry-Fix-quoting-in-setparams_prefix.patch + - 0024-kern-parser-Fix-resource-leak-if-argc-0.patch + - 0025-kern-parser-Fix-a-memory-leak.patch + - 0026-kern-parser-Introduce-process_char-helper.patch + - 0027-kern-parser-Introduce-terminate_arg-helper.patch + - 0028-kern-parser-Refactor-grub_parser_split_cmdline-clean.patch + - 0029-kern-buffer-Add-variable-sized-heap-buffer.patch + - 0030-kern-parser-Fix-a-stack-buffer-overflow.patch + - 0031-util-mkimage-Remove-unused-code-to-add-BSS-section.patch + - 0032-util-mkimage-Use-grub_host_to_target32-instead-of-gr.patch + - 0033-util-mkimage-Always-use-grub_host_to_target32-to-ini.patch + - 0034-util-mkimage-Unify-more-of-the-PE32-and-PE32-header-.patch + - 0035-util-mkimage-Reorder-PE-optional-header-fields-set-u.patch + - 0036-util-mkimage-Improve-data_size-value-calculation.patch + - 0037-util-mkimage-Refactor-section-setup-to-use-a-helper.patch + - 0038-util-mkimage-Add-an-option-to-import-SBAT-metadata-i.patch + - 0039-grub-install-common-Add-sbat-option.patch + - 0040-shim_lock-Only-skip-loading-shim_lock-verifier-with-.patch + - grub-install-define-default-platform-for-risc-v.patch + - grub2-editenv-add-warning-message.patch + - grub2-efi-gop-add-blt.patch + - grub2-efi-uga-64bit-fb.patch + - grub2-verifiers-fix-system-freeze-if-verify-failed.patch + - risc-v-add-clzdi2-symbol.patch + - risc-v-fix-computation-of-pc-relative-relocation-offset.patch +- Add grub2-instdev-fixup.pl for correcting /etc/default/grub_installdevice to + use disk devie if grub has been installed to it +- Add 0001-30_uefi-firmware-fix-printf-format-with-null-byte.patch to fix + detection of efi fwsetup support +* Mon May 31 2021 mchang@suse.com +- Fix running grub2-once leads to failure of starting systemd service in the + boot sequence (bsc#1169460) + * grub2-once + * grub2-once.service +* Fri May 28 2021 mchang@suse.com +- Fix crash in launching gfxmenu without theme file (bsc#1186481) + * grub2-gfxmenu-support-scrolling-menu-entry-s-text.patch +* Tue May 11 2021 mchang@suse.com +- Fix plaintext password in grub config didn't work to unlock menu entry if + enabling secure boot in UEFI (bsc#1181892) +* Fri Apr 23 2021 mchang@suse.com +- Fix obsolete syslog in systemd unit file and updating to use journal as + StandardOutput (bsc#1185149) + * grub2-once.service +* Mon Apr 19 2021 mchang@suse.com +- Fix build error on armv6/armv7 (bsc#1184712) + * 0001-emu-fix-executable-stack-marking.patch +* Thu Apr 8 2021 mchang@suse.com +- Fix error grub_file_filters not found in Azure virtual machine (bsc#1182012) + * 0001-Workaround-volatile-efi-boot-variable.patch +* Tue Mar 16 2021 mchang@suse.com +- Fix powerpc-ieee1275 lpar takes long time to boot with increasing number of + nvme namespace (bsc#1177751) + 0001-ieee1275-Avoiding-many-unecessary-open-close.patch +* Thu Mar 11 2021 mchang@suse.com +- Fix chainloading windows on dual boot machine (bsc#1183073) + * 0001-kern-efi-sb-Add-chainloaded-image-as-shim-s-verifiab.patch +* Fri Feb 26 2021 mchang@suse.com +- VUL-0: grub2,shim: implement new SBAT method (bsc#1182057) + * 0031-util-mkimage-Remove-unused-code-to-add-BSS-section.patch + * 0032-util-mkimage-Use-grub_host_to_target32-instead-of-gr.patch + * 0033-util-mkimage-Always-use-grub_host_to_target32-to-ini.patch + * 0034-util-mkimage-Unify-more-of-the-PE32-and-PE32-header-.patch + * 0035-util-mkimage-Reorder-PE-optional-header-fields-set-u.patch + * 0036-util-mkimage-Improve-data_size-value-calculation.patch + * 0037-util-mkimage-Refactor-section-setup-to-use-a-helper.patch + * 0038-util-mkimage-Add-an-option-to-import-SBAT-metadata-i.patch + * 0039-grub-install-common-Add-sbat-option.patch +- Fix CVE-2021-20225 (bsc#1182262) + * 0022-lib-arg-Block-repeated-short-options-that-require-an.patch +- Fix CVE-2020-27749 (bsc#1179264) + * 0024-kern-parser-Fix-resource-leak-if-argc-0.patch + * 0025-kern-parser-Fix-a-memory-leak.patch + * 0026-kern-parser-Introduce-process_char-helper.patch + * 0027-kern-parser-Introduce-terminate_arg-helper.patch + * 0028-kern-parser-Refactor-grub_parser_split_cmdline-clean.patch + * 0029-kern-buffer-Add-variable-sized-heap-buffer.patch + * 0030-kern-parser-Fix-a-stack-buffer-overflow.patch +- Fix CVE-2021-20233 (bsc#1182263) + * 0023-commands-menuentry-Fix-quoting-in-setparams_prefix.patch +- Fix CVE-2020-25647 (bsc#1177883) + * 0021-usb-Avoid-possible-out-of-bound-accesses-caused-by-m.patch +- Fix CVE-2020-25632 (bsc#1176711) + * 0020-dl-Only-allow-unloading-modules-that-are-not-depende.patch +- Fix CVE-2020-27779, CVE-2020-14372 (bsc#1179265) (bsc#1175970) + * 0001-include-grub-i386-linux.h-Include-missing-grub-types.patch + * 0002-efi-Make-shim_lock-GUID-and-protocol-type-public.patch + * 0003-efi-Return-grub_efi_status_t-from-grub_efi_get_varia.patch + * 0004-efi-Add-a-function-to-read-EFI-variables-with-attrib.patch + * 0005-efi-Add-secure-boot-detection.patch + * 0006-efi-Only-register-shim_lock-verifier-if-shim_lock-pr.patch + * 0007-verifiers-Move-verifiers-API-to-kernel-image.patch + * 0008-efi-Move-the-shim_lock-verifier-to-the-GRUB-core.patch + * 0009-kern-Add-lockdown-support.patch + * 0010-kern-lockdown-Set-a-variable-if-the-GRUB-is-locked-d.patch + * 0011-efi-Lockdown-the-GRUB-when-the-UEFI-Secure-Boot-is-e.patch + * 0012-efi-Use-grub_is_lockdown-instead-of-hardcoding-a-dis.patch + * 0013-acpi-Don-t-register-the-acpi-command-when-locked-dow.patch + * 0014-mmap-Don-t-register-cutmem-and-badram-commands-when-.patch + * 0015-commands-Restrict-commands-that-can-load-BIOS-or-DT-.patch + * 0016-commands-setpci-Restrict-setpci-command-when-locked-.patch + * 0017-commands-hdparm-Restrict-hdparm-command-when-locked-.patch + * 0018-gdb-Restrict-GDB-access-when-locked-down.patch + * 0019-loader-xnu-Don-t-allow-loading-extension-and-package.patch + * 0040-shim_lock-Only-skip-loading-shim_lock-verifier-with-.patch + * 0041-squash-Add-secureboot-support-on-efi-chainloader.patch + * 0042-squash-grub2-efi-chainload-harder.patch + * 0043-squash-Don-t-allow-insmod-when-secure-boot-is-enable.patch + * 0044-squash-kern-Add-lockdown-support.patch + * 0045-squash-Add-support-for-Linux-EFI-stub-loading-on-aar.patch + * 0046-squash-verifiers-Move-verifiers-API-to-kernel-image.patch +- Drop patch supersceded by the new backport + * 0001-linuxefi-fail-kernel-validation-without-shim-protoco.patch + * 0001-shim_lock-Disable-GRUB_VERIFY_FLAGS_DEFER_AUTH-if-se.patch + * 0007-linuxefi-fail-kernel-validation-without-shim-protoco.patch +- Add SBAT metadata section to grub.efi +- Drop shim_lock module as it is part of core of grub.efi + * grub2.spec +* Mon Feb 22 2021 mchang@suse.com +- Fix build error in binutils 2.36 (bsc#1181741) + * 0001-Fix-build-error-in-binutils-2.36.patch +- Fix executable stack in grub-emu (bsc#1181696) + * 0001-emu-fix-executable-stack-marking.patch +* Thu Feb 18 2021 mchang@suse.com +- Restore compatibilty sym-links + * grub2.spec +- Use rpmlintrc to filter out rpmlint 2.0 error (bsc#1179044) + * grub2.rpmlintrc +* Wed Jan 27 2021 mchang@suse.com +- Complete Secure Boot support on aarch64 (jsc#SLE-15020) + * 0001-Add-support-for-Linux-EFI-stub-loading-on-aarch64.patch + * 0002-arm64-make-sure-fdt-has-address-cells-and-size-cells.patch + * 0003-Make-grub_error-more-verbose.patch + * 0004-arm-arm64-loader-Better-memory-allocation-and-error-.patch + * 0005-Make-linux_arm_kernel_header.hdr_offset-be-at-the-ri.patch + * 0006-efi-Set-image-base-address-before-jumping-to-the-PE-.patch + * 0007-linuxefi-fail-kernel-validation-without-shim-protoco.patch + * 0008-squash-Add-support-for-Linux-EFI-stub-loading-on-aar.patch + * 0009-squash-Add-support-for-linuxefi.patch +* Thu Jan 21 2021 mchang@suse.com +- Fix rpmlint 2.0 error for having arch specific path in noarch package aiming + for compatibility with old package (bsc#1179044) + * grub2.spec +- Fix non POSIX sed argument which failed in sed from busybox (bsc#1181091) + * grub2-check-default.sh +* Mon Nov 2 2020 mchang@suse.com +- Fix boot failure in blocklist installation (bsc#1178278) + * Modified 0002-grub-install-Avoid-incompleted-install-on-i386-pc.patch +* Thu Oct 22 2020 mchang@suse.com +- Fix grub2-install error with "failed to get canonical path of + `/boot/grub2/i386-pc'." (bsc#1177957) + * Modified 0002-grub-install-Avoid-incompleted-install-on-i386-pc.patch +* Wed Oct 14 2020 mchang@suse.com +- Fix https boot interrupted by unrecognised network address error message + (bsc#1172952) + * 0001-add-support-for-UEFI-network-protocols.patch +* Tue Oct 13 2020 mchang@suse.com +- grub2.spec: Fix bare words used as string in expression which is no longer + allowed in rpm 4.16 +* Fri Sep 25 2020 mchang@suse.com +- Improve the error handling when grub2-install fails with short mbr gap + (bsc#1176062) + * 0001-Warn-if-MBR-gap-is-small-and-user-uses-advanced-modu.patch + * 0002-grub-install-Avoid-incompleted-install-on-i386-pc.patch +* Wed Sep 9 2020 mchang@suse.com +- Make efi hand off the default entry point of the linux command (bsc#1176134) + * 0001-efi-linux-provide-linux-command.patch +* Thu Aug 27 2020 mchang@suse.com +- Fix verification requested but nobody cares error when loading external + module in secure boot off (bsc#1175766) + * 0001-shim_lock-Disable-GRUB_VERIFY_FLAGS_DEFER_AUTH-if-se.patch +* Sat Aug 22 2020 mchang@suse.com +- Make consistent check to enable relative path on btrfs (bsc#1174567) + * 0001-Unify-the-check-to-enable-btrfs-relative-path.patch +* Fri Aug 21 2020 mchang@suse.com +- Add fibre channel device's ofpath support to grub-ofpathname and search hint + to speed up root device discovery (bsc#1172745) + * 0001-ieee1275-powerpc-implements-fibre-channel-discovery-.patch + * 0002-ieee1275-powerpc-enables-device-mapper-discovery.patch +* Tue Aug 18 2020 mchang@suse.com +- Fix for CVE-2020-15705 (bsc#1174421) + * 0001-linuxefi-fail-kernel-validation-without-shim-protoco.patch + * 0002-cmdline-Provide-cmdline-functions-as-module.patch +* Thu Aug 13 2020 mchang@suse.com +- Make grub-calloc inline to avoid symbol not found error as the system may not + use updated grub to boot the system (bsc#1174782) (bsc#1175060) (bsc#1175036) + * 0001-kern-mm.c-Make-grub_calloc-inline.patch +* Mon Jul 27 2020 mchang@suse.com +- Fix for CVE-2020-10713 (bsc#1168994) + * 0001-yylex-Make-lexer-fatal-errors-actually-be-fatal.patch +- Fix for CVE-2020-14308 CVE-2020-14309, CVE-2020-14310, CVE-2020-14311 + (bsc#1173812) + * 0002-safemath-Add-some-arithmetic-primitives-that-check-f.patch + * 0003-calloc-Make-sure-we-always-have-an-overflow-checking.patch + * 0004-calloc-Use-calloc-at-most-places.patch + * 0005-malloc-Use-overflow-checking-primitives-where-we-do-.patch + * 0006-iso9660-Don-t-leak-memory-on-realloc-failures.patch + * 0007-font-Do-not-load-more-than-one-NAME-section.patch +- Fix CVE-2020-15706 (bsc#1174463) + * 0008-script-Remove-unused-fields-from-grub_script_functio.patch + * 0009-script-Avoid-a-use-after-free-when-redefining-a-func.patch +- Fix CVE-2020-15707 (bsc#1174570) + * 0010-linux-Fix-integer-overflows-in-initrd-size-handling.patch +- Use overflow checking primitives where the arithmetic expression for buffer + allocations may include unvalidated data +- Use grub_calloc for overflow check and return NULL when it would occur + * 0001-add-support-for-UEFI-network-protocols.patch + * 0003-bootp-New-net_bootp6-command.patch + * grub2-btrfs-01-add-ability-to-boot-from-subvolumes.patch + * grub2-btrfs-09-get-default-subvolume.patch + * grub2-gfxmenu-support-scrolling-menu-entry-s-text.patch + * grub2-grubenv-in-btrfs-header.patch +* Thu Jul 16 2020 normand@linux.vnet.ibm.com +- No 95_textmode for PowerPC (boo#1174166) +* Mon May 18 2020 mchang@suse.com +- Skip zfcpdump kernel from the grub boot menu (bsc#1166513) + * grub2-s390x-skip-zfcpdump-image.patch +* Tue May 5 2020 mchang@suse.com +- Fix boot failure as journaled data not get drained due to abrupt power + off after grub-install (bsc#1167756) + * grub-install-force-journal-draining-to-ensure-data-i.patch +* Thu Apr 16 2020 mchang@suse.com +- Fix executable stack in grub-probe and other grub utility (bsc#1169137) + * grub2-btrfs-06-subvol-mount.patch +* Tue Mar 24 2020 mchang@suse.com +- Fix GCC 10 build fail (bsc#1158189) + * 0001-mdraid1x_linux-Fix-gcc10-error-Werror-array-bounds.patch + * 0002-zfs-Fix-gcc10-error-Werror-zero-length-bounds.patch +* Fri Mar 20 2020 mchang@suse.com +- Backport to support searching for specific config files for netboot + (bsc#1166409) + * 0001-normal-Move-common-datetime-functions-out-of-the-nor.patch + * 0002-kern-Add-X-option-to-printf-functions.patch + * 0003-normal-main-Search-for-specific-config-files-for-net.patch + * 0004-datetime-Enable-the-datetime-module-for-the-emu-plat.patch +* Mon Mar 16 2020 lnussel@suse.de +- move *.module files to separate -debug subpackage (boo#1166578) +* Thu Mar 12 2020 fvogt@suse.com +- Fix EFI console detection to make it a runtime decision (bsc#1164385) + * grub2-SUSE-Add-the-t-hotkey.patch +* Tue Mar 10 2020 lnussel@suse.de +- Downgrade mtools to Suggests for consistency with xorriso (boo#1165839) +- remove info requirements, file triggers are used now (boo#1152105) +* Fri Feb 28 2020 rw@suse.com +- Add secure boot support for s390x. (jsc#SLE-9425) + * grub2-s390x-11-secureboot.patch +* Tue Feb 18 2020 mchang@suse.com +- Fix grub hangs after loading rogue image without valid signature for uefi + secure boot (bsc#1159102) + * grub2-verifiers-fix-system-freeze-if-verify-failed.patch +* Tue Feb 4 2020 mchang@suse.com +- From Stefan Seyfried : Fix grub2-install fails + with "not a directory" error (boo#1161641, bsc#1162403) + * grub2-install-fix-not-a-directory-error.patch +* Wed Nov 27 2019 olaf@aepfle.de +- Correct awk pattern in 20_linux_xen (bsc#900418, bsc#1157912) +- Correct linux and initrd handling in 20_linux_xen (bsc#1157912) + M grub2-efi-xen-cfg-unquote.patch + M grub2-efi-xen-chainload.patch + M grub2-efi-xen-cmdline.patch + M grub2-efi-xen-removable.patch +* Wed Oct 30 2019 mchang@suse.com +- Disable btrfs zstd support for i386-pc to workaround core.img too large to be + embedded in btrfs bootloader area or MBR gap (boo#1154809) + * 0001-btrfs-disable-zstd-support-for-i386-pc.patch +* Mon Oct 28 2019 bwiedemann@suse.com +- Fix grub2.sleep to load old kernel after hibernation (boo#1154783) +* Tue Oct 22 2019 schwab@suse.de +- Enable support for riscv64 +- Backports from upstream: + * risc-v-fix-computation-of-pc-relative-relocation-offset.patch + * risc-v-add-clzdi2-symbol.patch + * grub-install-define-default-platform-for-risc-v.patch +* Thu Oct 17 2019 mchang@suse.com +- Version bump to 2.04 + * removed + - translations-20170427.tar.xz + * grub2.spec + - Make signed grub-tpm.efi specific to x86_64-efi build, the platform + currently shipped with tpm module from upstream codebase + - Add shim_lock to signed grub.efi in x86_64-efi build + - x86_64: linuxefi now depends on linux, both will verify kernel via + shim_lock + - Remove translation tarball and po file hacks as it's been included in + upstream tarball + * rediff + - grub2-setup-try-fs-embed-if-mbr-gap-too-small.patch + - grub2-commands-introduce-read_file-subcommand.patch + - grub2-secureboot-add-linuxefi.patch + - 0001-add-support-for-UEFI-network-protocols.patch + - grub2-efi-HP-workaround.patch + - grub2-secureboot-install-signed-grub.patch + - grub2-linux.patch + - use-grub2-as-a-package-name.patch + - grub2-pass-corret-root-for-nfsroot.patch + - grub2-secureboot-use-linuxefi-on-uefi.patch + - grub2-secureboot-no-insmod-on-sb.patch + - grub2-secureboot-provide-linuxefi-config.patch + - grub2-secureboot-chainloader.patch + - grub2-s390x-01-Changes-made-and-files-added-in-order-to-allow-s390x.patch + - grub2-s390x-02-kexec-module-added-to-emu.patch + - grub2-s390x-04-grub2-install.patch + - grub2-btrfs-01-add-ability-to-boot-from-subvolumes.patch + - grub2-efi-chainloader-root.patch + - grub2-ppc64le-disable-video.patch + - grub2-ppc64-cas-reboot-support.patch + - grub2-Fix-incorrect-netmask-on-ppc64.patch + - 0003-bootp-New-net_bootp6-command.patch + - 0006-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch + - 0012-tpm-Build-tpm-as-module.patch + - grub2-emu-4-all.patch + - grub2-btrfs-09-get-default-subvolume.patch + - grub2-ppc64le-memory-map.patch + - grub2-ppc64-cas-fix-double-free.patch + - 0008-efinet-Setting-DNS-server-from-UEFI-protocol.patch + * drop upstream patches + - grub2-fix-locale-en.mo.gz-not-found-error-message.patch + - grub2-fix-build-with-flex-2.6.4.patch + - grub2-accept-empty-module.patch + - 0001-Fix-packed-not-aligned-error-on-GCC-8.patch + - 0001-Fix-PCIe-LER-when-GRUB2-accesses-non-enabled-MMIO-da.patch + - unix-exec-avoid-atexit-handlers-when-child-exits.patch + - 0001-xfs-Accept-filesystem-with-sparse-inodes.patch + - grub2-binutils2.31.patch + - grub2-msdos-fix-overflow.patch + - 0001-tsc-Change-default-tsc-calibration-method-to-pmtimer.patch + - grub2-efi-Move-grub_reboot-into-kernel.patch + - grub2-efi-Free-malloc-regions-on-exit.patch + - grub2-move-initrd-upper.patch + - 0002-Add-Virtual-LAN-support.patch + - 0001-ofnet-Initialize-structs-in-bootpath-parser.patch + - 0001-misc-fix-invalid-character-recongition-in-strto-l.patch + - 0001-tpm-Core-TPM-support.patch + - 0002-tpm-Measure-kernel-initrd.patch + - 0003-tpm-Add-BIOS-boot-measurement.patch + - 0004-tpm-Rework-linux-command.patch + - 0005-tpm-Rework-linux16-command.patch + - 0006-tpm-Measure-kernel-and-initrd-on-BIOS-systems.patch + - 0007-tpm-Measure-the-kernel-commandline.patch + - 0008-tpm-Measure-commands.patch + - 0009-tpm-Measure-multiboot-images-and-modules.patch + - 0010-tpm-Fix-boot-when-there-s-no-TPM.patch + - 0011-tpm-Fix-build-error.patch + - 0013-tpm-i386-pc-diskboot-img.patch + - grub2-freetype-pkgconfig.patch + - 0001-cpio-Disable-gcc9-Waddress-of-packed-member.patch + - 0002-jfs-Disable-gcc9-Waddress-of-packed-member.patch + - 0003-hfs-Fix-gcc9-error-Waddress-of-packed-member.patch + - 0004-hfsplus-Fix-gcc9-error-with-Waddress-of-packed-membe.patch + - 0005-acpi-Fix-gcc9-error-Waddress-of-packed-member.patch + - 0006-usbtest-Disable-gcc9-Waddress-of-packed-member.patch + - 0007-chainloader-Fix-gcc9-error-Waddress-of-packed-member.patch + - 0008-efi-Fix-gcc9-error-Waddress-of-packed-member.patch +* Tue Oct 15 2019 rw@suse.com +- Consistently find btrfs snapshots on s390x. (bsc#1136970) + * grub2-s390x-04-grub2-install.patch +* Fri Aug 16 2019 mchang@suse.com +- Fix fallback embed doesn't work when no post mbr gap at all (boo#1142229) + * Refresh grub2-setup-try-fs-embed-if-mbr-gap-too-small.patch +* Thu Jul 18 2019 mchang@suse.com +- Revert grub2-ieee1275-FCP-methods-for-WWPN-and-LUNs.patch until merged by + upstream (bsc#1134287, bsc#1139345, LTC#177836, LTC#174229). +* Mon Jun 24 2019 msuchanek@suse.de +- Fix iteration of FCP LUNs (bsc#1134287, bsc#1139345, LTC#177836, LTC#174229). + * Refresh grub2-ieee1275-FCP-methods-for-WWPN-and-LUNs.patch +* Mon Jun 17 2019 mchang@suse.com +- Use grub2-install to handle signed grub installation for UEFI secure + boot and also provide options to override default (bsc#1136601) + * grub2-secureboot-install-signed-grub.patch +- Remove arm64 linuxefi patches as it's not needed for secure boot + * 0001-efi-refactor-grub_efi_allocate_pages.patch + * 0002-Remove-grub_efi_allocate_pages.patch + * 0003-arm64-efi-move-EFI_PAGE-definitions-to-efi-memory.h.patch + * 0004-efi-Add-central-copy-of-grub_efi_find_mmap_size.patch + * 0005-efi-Add-grub_efi_get_ram_base-function-for-arm64.patch + * 0006-Add-support-for-EFI-handover-on-ARM64.patch +* Fri Jun 14 2019 mchang@suse.com +- Avoid high resolution when trying to keep current mode (bsc#1133842) + * grub2-video-limit-the-resolution-for-fixed-bimap-font.patch +- Make GRUB_SAVEDEFAULT working with btrfs (bsc#1128592) + * grub2-grubenv-in-btrfs-header.patch +* Fri May 17 2019 rw@suse.com +- Check/refresh zipl-kernel before hibernate on s390x. (bsc#940457) + (Getting rid of hardcoded 'vmlinuz', which failed on PPC as well.) + * grub2-systemd-sleep.sh +* Fri May 17 2019 rw@suse.com +- Try to refresh zipl-kernel on failed kexec. (bsc#1127293) + * grub2-s390x-04-grub2-install.patch +- Fully support "previous" zipl-kernel, + with 'mem=1G' being available on dedicated entries. (bsc#928131) + * grub2-s390x-09-improve-zipl-setup.patch +- Refresh + * grub2-zipl-setup-fix-btrfs-multipledev.patch +* Fri May 3 2019 mchang@suse.com +- Fix GCC 9 build failure (bsc#1121208) + * 0001-cpio-Disable-gcc9-Waddress-of-packed-member.patch + * 0002-jfs-Disable-gcc9-Waddress-of-packed-member.patch + * 0003-hfs-Fix-gcc9-error-Waddress-of-packed-member.patch + * 0004-hfsplus-Fix-gcc9-error-with-Waddress-of-packed-membe.patch + * 0005-acpi-Fix-gcc9-error-Waddress-of-packed-member.patch + * 0006-usbtest-Disable-gcc9-Waddress-of-packed-member.patch + * 0007-chainloader-Fix-gcc9-error-Waddress-of-packed-member.patch + * 0008-efi-Fix-gcc9-error-Waddress-of-packed-member.patch +* Tue Mar 19 2019 mchang@suse.com +- Use %%doc for older products for compatibility, or may end up with + unsuccessful build result + * grub2.spec +* Tue Mar 19 2019 mchang@suse.com +- Revert grub2-ieee1275-open-raw-mode.patch for regression of crashing lvm on + multipath SAN (bsc#1113702) + * deleted grub2-ieee1275-open-raw-mode.patch +- Add exception handling to FCP lun enumeration (bsc#1113702) + * grub2-ieee1275-FCP-methods-for-WWPN-and-LUNs.patch +* Wed Feb 20 2019 mchang@suse.com +- Fix LOADER_TYPE parsing in grub2-once (boo#1122569) +* Tue Feb 12 2019 mchang@suse.com +- Create compatibility sym-link of grub.xen in the old location to which + old VM definition is pointing (bsc#1123942) +* Mon Jan 28 2019 guillaume.gardet@opensuse.org +- Add patch to fix ARM boot, when kernel become too big: + * grub2-move-initrd-upper.patch (boo#1123350) +* Fri Jan 25 2019 jengelh@inai.de +- Replace old $RPM_* shell vars. +* Fri Jan 25 2019 mchang@suse.com +- Support long menu entry by scrolling its text left and right through + the key stroke ctrl+l and ctrl+r (FATE#325760) + * grub2-gfxmenu-support-scrolling-menu-entry-s-text.patch +* Thu Jan 24 2019 mchang@suse.com +- Improved hiDPI device support (FATE#326680) + * grub2-video-limit-the-resolution-for-fixed-bimap-font.patch +* Wed Jan 23 2019 rw@suse.com +- Build platform-packages 'noarch' and move to '/usr/share/efi' + for SUSE Manager. (FATE#326960) + * grub2-efi-xen-chainload.patch (bsc#1122563) + * grub2-efi-xen-removable.patch (refresh) +* Thu Dec 20 2018 mchang@suse.com +- Support for UEFI Secure Boot on AArch64 (FATE#326541) + * 0001-efi-refactor-grub_efi_allocate_pages.patch + * 0002-Remove-grub_efi_allocate_pages.patch + * 0003-arm64-efi-move-EFI_PAGE-definitions-to-efi-memory.h.patch + * 0004-efi-Add-central-copy-of-grub_efi_find_mmap_size.patch + * 0005-efi-Add-grub_efi_get_ram_base-function-for-arm64.patch + * 0006-Add-support-for-EFI-handover-on-ARM64.patch +* Mon Nov 26 2018 mchang@suse.com +- Change default tsc calibration method to pmtimer on EFI (bsc#1114754) + * 0001-tsc-Change-default-tsc-calibration-method-to-pmtimer.patch +* Fri Oct 19 2018 mchang@suse.com +- ieee1275: Fix double free in CAS reboot (bsc#1111955) + * grub2-ppc64-cas-fix-double-free.patch +* Thu Oct 4 2018 glin@suse.com +- Support NVDIMM device names (bsc#1110073) + * grub2-getroot-support-nvdimm.patch +* Wed Oct 3 2018 mchang@suse.com +- Translate caret back to space as the initrd stanza could use space to + delimit multiple files loaded (bsc#1101942) + * grub2-util-30_os-prober-multiple-initrd.patch +* Wed Sep 26 2018 mchang@suse.com +- ieee1275: implement FCP methods for WWPN and LUNs (bsc#1093145) + * grub2-ieee1275-FCP-methods-for-WWPN-and-LUNs.patch +* Thu Sep 13 2018 mchang@suse.com +- Fix broken network interface with random address and same name (bsc#1084508) + * 0001-ofnet-Initialize-structs-in-bootpath-parser.patch +* Fri Aug 31 2018 mchang@suse.com +- Fix outputting invalid btrfs subvol path on non btrfs filesystem due to bogus + return code handling. (bsc#1106381) + * modified grub2-btrfs-10-config-directory.patch +* Thu Aug 23 2018 mchang@suse.com +- Fix overflow in sector count calculation (bsc#1105163) + * grub2-msdos-fix-overflow.patch +* Thu Aug 9 2018 mchang@suse.com +- Downgrade libburnia-tools to suggest as minimal system can't afford pulling + in tcl/tk and half of the x11 stack (bsc#1102515) + * modified grub2.spec +* Wed Aug 8 2018 dimstar@opensuse.org +- Add grub2-binutils2.31.patch: x86-64: Treat R_X86_64_PLT32 as + R_X86_64_PC32. Starting from binutils commit bd7ab16b x86-64 + assembler generates R_X86_64_PLT32, instead of R_X86_64_PC32, for + 32-bit PC-relative branches. Grub2 should treat R_X86_64_PLT32 + as R_X86_64_PC32. +* Mon Aug 6 2018 josef.moellers@suse.com +- The grubxenarch packages are now architecture-independent. + [bsc#953297, grub2.spec, grub2-rpmlintrc] +* Tue Jul 24 2018 mchang@suse.com +- Fix config_directory on btrfs to follow path scheme (bsc#1063443) + * grub2-btrfs-10-config-directory.patch +- Fix grub2-install --root-directory does not work for /boot/grub2/ on + separate btrfs subvolume (boo#1098420) + * grub2-btrfs-06-subvol-mount.patch +- Fix setparams doesn't work as expected from boot-last-label NVRAM var, after + inital CAS reboot on ieee1275 (bsc#1088830) + * grub2-ppc64-cas-new-scope.patch +* Mon Jul 16 2018 mchang@suse.com +- Fix install on xfs error (bsc#1101283) + * 0001-xfs-Accept-filesystem-with-sparse-inodes.patch +* Tue Jul 10 2018 jbohac@suse.cz +- grub2.spec: change %%config to %%config(noreplace) + Don't overwrite user changes to config files on upgrades. +* Wed Jul 4 2018 josef.moellers@suse.com +- Marked %%{_sysconfdir}/grub.d/40_custom as (noreplace) + [bsc#1079332, grub2.spec] +* Wed Jun 27 2018 josef.moellers@suse.com +- Replace "GRUB_DISABLE_LINUX_RECOVERY" by "GRUB_DISABLE_RECOVERY" + in /etc/default/grub and remove test from s390x install + section in upec file. + [bsc#1042433, grub.default, grub2.spec] +* Wed Jun 20 2018 josef.moellers@suse.com +- Added "# needssslcertforbuild", which got lost somewhere, + to spec file + [grub2.spec] +* Fri Jun 15 2018 josef.moellers@suse.com +- Replace confusing menu on btrfs "snapper rollback" by help text. + [bsc#1027588, grub2-btrfs-help-on-snapper-rollback.patch] +* Thu May 24 2018 kukuk@suse.de +- Use %%license instead of %%doc [bsc#1082318] +* Wed May 16 2018 Thomas.Blume@suse.com +- grub2-emu on s390 keep network during kexec boot (bsc#1089493) + * grub2-s390x-10-keep-network-at-kexec.patch +* Fri May 4 2018 idonmez@suse.com +- Add grub2-freetype-pkgconfig.patch to fix build with new freetype + use pkgconfig to find Freetype libraries. +* Tue Apr 17 2018 mchang@suse.com +- Fallback to raw mode if Open Firmware returns invalid ihandler (bsc#1071559) + * grub2-ieee1275-open-raw-mode.patch +* Thu Apr 12 2018 mchang@suse.com +- Fix error of essential directory not found on UEFI Xen host (bsc#1085842) + * add grub2-efi-xen-removable.patch + * rediff grub2-suse-remove-linux-root-param.patch +* Tue Apr 10 2018 jdelvare@suse.de +- Fix corruption of "grub2-install --help" and grub2-install manual + page (bsc#1086670) + * unix-exec-avoid-atexit-handlers-when-child-exits.patch +* Mon Apr 2 2018 mchang@suse.com +- Fix Nvidia GPU in legacy I/O slot 2 disappears during system + startup (bsc#1082914) + * 0001-Fix-PCIe-LER-when-GRUB2-accesses-non-enabled-MMIO-da.patch +* Fri Mar 30 2018 mchang@suse.com +- Fix packed-not-aligned error on GCC 8 (bsc#1084632) + * 0001-Fix-packed-not-aligned-error-on-GCC-8.patch +* Mon Mar 26 2018 msuchanek@suse.com +- Fix incorrect netmask on ppc64 (bsc#1085419) + * grub2-Fix-incorrect-netmask-on-ppc64.patch +* Mon Mar 12 2018 mchang@suse.com +- Fix UEFI HTTPS Boot from ISO installation image (bsc#1076132) + * 0001-add-support-for-UEFI-network-protocols.patch +* Tue Mar 6 2018 mchang@suse.com +- fix wrong command output when default subvolume is toplevel tree with + id 5 (bsc#1078775) + * grub2-btrfs-09-get-default-subvolume.patch +- insert mdraid modules to support software RAID (bsc#1078775) + * grub2-xen-pv-firmware.cfg +* Thu Mar 1 2018 iforster@suse.com +- Rename grub2-btrfs-workaround-grub2-once.patch to + grub2-grubenv-in-btrfs-header.patch +- Store GRUB environment variable health_checker_flag in Btrfs header +* Tue Feb 13 2018 mchang@suse.com +- Fix incorrect check preventing the script from running (bsc#1078481) + * 80_suse_btrfs_snapshot +* Wed Feb 7 2018 mchang@suse.com +- Fix disappeared snapshot menu entry (bsc#1078481) + * 80_suse_btrfs_snapshot +* Tue Feb 6 2018 mchang@suse.com +- Fix unquoted string error and add some more checks (bsc#1079330) + * grub2-check-default.sh +* Mon Feb 5 2018 olaf@aepfle.de +- The %%prep section applies patches, the %%build section builds. + Remove mixup of patching and building from %%prep for quilt setup + Related to bsc#1065703 +* Tue Jan 23 2018 mchang@suse.com +- Check if default entry need to be corrected for updated distributor version + and/or use fallback entry if default kernel entry removed (bsc#1065349) + * grub2-check-default.sh + * grub2-mkconfig-default-entry-correction.patch +- Fix grub2-mkconfig warning when disk is LVM PV (bsc#1071239) + * grub2-getroot-scan-disk-pv.patch +* Fri Dec 8 2017 mchang@suse.com +- Filter out autofs and securityfs from /proc/self/mountinfo to speed + up nfsroot test in large number of autofs mounts (bsc#1069094) + * modified grub2-pass-corret-root-for-nfsroot.patch +* Tue Nov 28 2017 mchang@suse.com +- Fix http(s) boot security review (bsc#1058090) + * 0002-AUDIT-0-http-boot-tracker-bug.patch +* Tue Nov 14 2017 mchang@suse.com +- 0001-add-support-for-UEFI-network-protocols.patch: + * Workaround http data access in firmware + * Fix DNS device path parsing for efinet device + * Relaxed UEFI Protocol requirement + * Support Intel OPA (Omni-Path Architecture) PXE Boot (bsc#1015589) +* Wed Nov 8 2017 olaf@aepfle.de +- grub2-xen-pv-firmware.cfg: remove linemode=1 from cmdline for + SUSE installer. openQA expects ncurses interface. (bsc#1066919) +* Mon Nov 6 2017 jmatejek@suse.com +- use python3 for autogen.sh (fate#323526) +* Tue Oct 31 2017 msuchanek@suse.com +- Do not check that PReP partition does not contain an ELF during installation + (bsc#1065738). + * grub2-install-remove-useless-check-PReP-partition-is-empty.patch +* Tue Sep 26 2017 mchang@suse.com +- Build diskboot_tpm.img as separate image to diskboot.img to prevent failure + in booting on some bogus firmware. To use the TPM image you have to use + suse-enable-tpm option of grub2-install (bsc#1052401) + * 0013-tpm-i386-pc-diskboot-img.patch +* Wed Sep 20 2017 mlatimer@suse.com +- Use /boot//loader/linux to determine if install media + is SUSE instead of /contents file (bsc#1054453) +* Tue Sep 19 2017 mlatimer@suse.com +- Use the pvops-enabled default kernel if the traditional xen + pv kernel and initrd are not found (bsc#1054453) +* Fri Sep 8 2017 agraf@suse.com +- Fix reboot in UEFI environments (bsc#1047331) + * Add grub2-efi-Move-grub_reboot-into-kernel.patch + * Refresh grub2-efi-Free-malloc-regions-on-exit.patch +* Sun Sep 3 2017 mchang@suse.com +- Add preliminary patch for UEFI HTTPS and related network protocol support + (fate#320130) + * 0001-add-support-for-UEFI-network-protocols.patch +* Sun Sep 3 2017 mchang@suse.com +- grub2-s390x-04-grub2-install.patch : remove arybase dependency in + grub2-zipl-setup by not referencing to $[ (bsc#1055280) +* Wed Aug 23 2017 rw@suse.com +- Fix minor oversights in and the exit value of the grub2-install + helper on s390x. (bsc#1055343, fate#323298) + * grub2-s390x-09-improve-zipl-setup.patch +* Mon Jul 24 2017 bwiedemann@suse.com +- Make grub2.info build reproducible (boo#1047218) +* Tue Jul 4 2017 arvidjaar@gmail.com +- add grub2-fix-build-with-flex-2.6.4.patch - fix build with flex 2.6.4+ + that removed explicit (void) cast from fprintf call in yy_fatal_error. +* Thu Jun 1 2017 mchang@suse.com +- Support LVM physical volume created without metadatacopies (bsc#1027526) + * grub2-diskfilter-support-pv-without-metadatacopies.patch +- Fix page fault exception when grub loads with Nvidia cards (bsc#1038533) + * grub2-efi-uga-64bit-fb.patch +- Require 'kexec-tools' for System z. (bsc#944358) + * modified grub2.spec +* Thu May 11 2017 mchang@suse.com +- grub2-xen-pv-firmware.cfg: insmod lvm module as it's not auto-loaded + to support booting from lvm volume (bsc#1004324) +- Grub not working correctly with xen and btrfs snapshots (bsc#1026511) + * Add grub2-btrfs-09-get-default-subvolume.patch + * grub2-xen-pv-firmware.cfg : search path in default subvolume +* Thu Apr 27 2017 arvidjaar@gmail.com +- new upstream version 2.02 + * rediff + - use-grub2-as-a-package-name.patch + * drop upstream patches + - grub2-fix-uninitialized-variable-in-btrfs-with-GCC7.patch + - grub2-add-FALLTHROUGH-annotations.patch +- update translations +* Sun Mar 26 2017 arvidjaar@gmail.com +- update grub2-btrfs-workaround-grub2-once.patch to also store saved_entry + in additional environment block (boo#1031025) +* Wed Mar 22 2017 arvidjaar@gmail.com +- fix building with GCC (bsc#1030247) + * add grub2-fix-uninitialized-variable-in-btrfs-with-GCC7.patch + * grub2-add-FALLTHROUGH-annotations.patch +* Mon Mar 20 2017 mchang@suse.com +- Fix out of memory error on lvm detection (bsc#1016536) (bsc#1027401) + * grub2-lvm-allocate-metadata-buffer-from-raw-contents.patch +- Fix boot failure if /boot is separate btrfs partition (bsc#1023160) + * grub2-btrfs-06-subvol-mount.patch +* Fri Mar 17 2017 mchang@suse.com +- 0004-tpm-Rework-linux-command.patch : Fix out of bound memory copy + (bsc#1029187) +* Thu Mar 16 2017 arvidjaar@gmail.com +- new upstream version 2.02~rc2 + * rediff + - use-grub2-as-a-package-name.patch + - grub2-linguas.sh-no-rsync.patch + * drop upstream patches + - 0001-efi-strip-off-final-NULL-from-File-Path-in-grub_efi_.patch +* Mon Mar 6 2017 mchang@suse.com +- TPM Support (FATE#315831) + * 0001-tpm-Core-TPM-support.patch + * 0002-tpm-Measure-kernel-initrd.patch + * 0003-tpm-Add-BIOS-boot-measurement.patch + * 0004-tpm-Rework-linux-command.patch + * 0005-tpm-Rework-linux16-command.patch + * 0006-tpm-Measure-kernel-and-initrd-on-BIOS-systems.patch + * 0007-tpm-Measure-the-kernel-commandline.patch + * 0008-tpm-Measure-commands.patch + * 0009-tpm-Measure-multiboot-images-and-modules.patch + * 0010-tpm-Fix-boot-when-there-s-no-TPM.patch + * 0011-tpm-Fix-build-error.patch + * 0012-tpm-Build-tpm-as-module.patch +- grub2.spec : Add grub-tpm.efi for Secure Boot +* Fri Mar 3 2017 mchang@suse.com +- Fix invalid Xen EFI config files if xen_args include GRUB2 quoting + (bsc#900418) (bsc#951748) + * grub2-efi-xen-cfg-unquote.patch +- Fix linuxefi erroneously initialize linux's boot_params with non-zero + values. (bsc#1025563) + * grub2-linuxefi-fix-boot-params.patch +- Removed grub2-fix-multi-device-root-kernel-argument.patch as it has + regression on how GRUB_DISABLE_LINUX_UUID=true interpreted (bsc#1015138) +* Wed Mar 1 2017 mchang@suse.com +- Fix for openQA UEFI USB Boot failure with upstream patch (bsc#1026344) + * added 0001-efi-strip-off-final-NULL-from-File-Path-in-grub_efi_.patch + * removed 0001-Revert-efi-properly-terminate-filepath-with-NULL-in-.patch +* Thu Feb 23 2017 mchang@suse.com +- Temporary fix for openQA UEFI USB Boot failure (bsc#1026344) + * 0001-Revert-efi-properly-terminate-filepath-with-NULL-in-.patch +* Fri Feb 17 2017 mchang@suse.com +- grub2.spec: fix s390x file list. +* Thu Feb 16 2017 msuchanek@suse.com +- require efibootmgr in efi package (boo#1025520) +* Wed Feb 15 2017 mchang@suse.com +- Merge changes from SLE12 +- add grub2-emu-4-all.patch + * Build 'grub2-emu' wherever possible, to allow a better + implementation of that feature. +- add grub2-s390x-06-loadparm.patch, +- add grub2-commands-introduce-read_file-subcommand.patch: + * allow s390x to telecontrol grub2. (bsc#891946, bsc#892852) +- add grub2-s390x-06-loadparm.patch: + * ignore case and fix transliteration of parameter. (bsc#891946) +- add grub2-s390x-07-add-image-param-for-zipl-setup.patch + * Add --image switch to force zipl update to specific kernel + (bsc#928131) +- add grub2-s390x-08-workaround-part-to-disk.patch + * Ignore partition tables on s390x. (bsc#935127) +- add grub2-efi-chainload-harder.patch: + * allow XEN to be chain-loaded despite firmware flaws. (bnc#887793) + * Do not use shim lock protocol for reading pe header, it won't be + available when secure boot disabled (bsc#943380) + * Make firmware flaw condition be more precisely detected and add + debug message for the case + * Check msdos header to find PE file header (bsc#954126) +- grub2-s390x-04-grub2-install.patch: + * streamline boot to grub menu. (bsc#898198) + * Force '/usr' to read-only before calling kexec. (bsc#932951) +- grub2-once: + * add '--enum' option to enumerate boot-entries in a way + actually understood by 'grub2'. (bsc#892852, bsc#892811) + * Examine variables from grub environment in 'grub2-once'. (fate#319632) +* Fri Feb 10 2017 arvidjaar@gmail.com +- new upstream version 2.02~rc1 + * rediff + - use-grub2-as-a-package-name.patch + - grub2-s390x-04-grub2-install.patch + - grub2-accept-empty-module.patch + - grub2-btrfs-04-grub2-install.patch + - grub2-btrfs-06-subvol-mount.patch + * drop upstream patches + - 0001-dns-fix-buffer-overflow-for-data-addresses-in-recv_h.patch + - 0001-build-Use-AC_HEADER_MAJOR-to-find-device-macros.patch + - 0002-configure-fix-check-for-sys-sysmacros.h-under-glibc-.patch + - 0001-Fix-fwpath-in-efi-netboot.patch + - 0001-arm64-Move-firmware-fdt-search-into-global-function.patch + - 0002-arm-efi-Use-fdt-from-firmware-when-available.patch + - grub2-arm64-mknetdir-add-suport-for-arm64-efi.patch + - 0001-10_linux-Fix-grouping-of-tests-for-GRUB_DEVICE.patch + - 0002-20_linux_xen-fix-test-for-GRUB_DEVICE.patch + - 0001-xen-make-xen-loader-callable-multiple-times.patch + - 0002-xen-avoid-memleaks-on-error.patch + - 0003-xen-reduce-number-of-global-variables-in-xen-loader.patch + - 0004-xen-add-elfnote.h-to-avoid-using-numbers-instead-of-.patch + - 0005-xen-synchronize-xen-header.patch + - 0006-xen-factor-out-p2m-list-allocation-into-separate-fun.patch + - 0007-xen-factor-out-allocation-of-special-pages-into-sepa.patch + - 0008-xen-factor-out-allocation-of-page-tables-into-separa.patch + - 0009-xen-add-capability-to-load-initrd-outside-of-initial.patch + - 0010-xen-modify-page-table-construction.patch + - 0011-xen-add-capability-to-load-p2m-list-outside-of-kerne.patch + * add + - fix-grub2-use-stat-instead-of-udevadm-for-partition-lookup-with-new-glibc.patch + fix compilation with new glibc +* Thu Feb 9 2017 mchang@suse.com +- Fix build error on glibc-2.25 + * 0001-build-Use-AC_HEADER_MAJOR-to-find-device-macros.patch + * 0002-configure-fix-check-for-sys-sysmacros.h-under-glibc-.patch +- Fix fwpath in efi netboot (fate#321993) (bsc#1022294) + * 0001-Fix-fwpath-in-efi-netboot.patch +* Fri Feb 3 2017 mchang@suse.com +- grub2-systemd-sleep.sh: Fix prematurely abort by commands error return code + and skip the offending menu entry (bsc#1022880) +* Wed Feb 1 2017 agraf@suse.com +- Add support for BLT only EFI GOP adapters (FATE#322332) + * grub2-efi-gop-add-blt.patch +* Wed Jan 25 2017 schwab@linux-m68k.org +- info-dir-entry.patch: Update info dir entry to follow renaming to grub2 +* Mon Jan 16 2017 matwey.kornilov@gmail.com +- Add serial module to efi image. + Serial terminal is still useful even with EFI Secure Boot +* Wed Jan 11 2017 mchang@suse.com +- Support %%posttrans with marcos provided by update-bootloader-rpm-macros + package (bsc#997317) +* Wed Jan 4 2017 mchang@suse.com +- Remove outdated README.openSUSE (bsc#907693) +* Fri Dec 30 2016 sor.alexei@meowr.ru +- 20_memtest86+: avoid adding memtest86+ to the list with UEFI + booting. +* Fri Oct 28 2016 mchang@suse.com +- Fix new line character in distributor (bsc#1007212) + * modified grub2-default-distributor.patch +* Fri Oct 21 2016 mchang@suse.com +- From Juergen Gross : grub-xen: support booting huge + pv-domains (bsc#1004398) (bsc#899465) + * 0001-xen-make-xen-loader-callable-multiple-times.patch + * 0002-xen-avoid-memleaks-on-error.patch + * 0003-xen-reduce-number-of-global-variables-in-xen-loader.patch + * 0004-xen-add-elfnote.h-to-avoid-using-numbers-instead-of-.patch + * 0005-xen-synchronize-xen-header.patch + * 0006-xen-factor-out-p2m-list-allocation-into-separate-fun.patch + * 0007-xen-factor-out-allocation-of-special-pages-into-sepa.patch + * 0008-xen-factor-out-allocation-of-page-tables-into-separa.patch + * 0009-xen-add-capability-to-load-initrd-outside-of-initial.patch + * 0010-xen-modify-page-table-construction.patch + * 0011-xen-add-capability-to-load-p2m-list-outside-of-kerne.patch +* Tue Oct 11 2016 dmueller@suse.com +- add support for netboot on arm64-efi platforms (bsc#998097) + * grub2-arm64-mknetdir-add-suport-for-arm64-efi.patch +* Fri Sep 2 2016 mchang@suse.com +- use $PRETTY_NAME instead of $NAME $VERSION for $GRUB_DISTRIBUTOR + in openSUSE Tumbleweed (bsc#995549) + * modified grub2-default-distributor.patch +- grub2.spec: add http module to grub.efi (fate#320129) +* Wed Aug 31 2016 matz@suse.com +- binutils 2.27 creates empty modules without a symtab. + Add patch grub2-accept-empty-module.patch to not reject them. +* Sat Aug 20 2016 arvidjaar@gmail.com +- since version 1.7 cryptsetup defaults to SHA256 for LUKS - include + gcry_sha256 in signed EFI image +* Fri Aug 12 2016 mchang@suse.com +- Workaround default entry in snapshot menu (bsc#956046) + * grub2-btrfs-08-workaround-snapshot-menu-default-entry.patch +- grub2.spec: Add true command to grub.efi (bsc#993274) +* Wed Aug 3 2016 mchang@suse.com +- grub.default: Empty GRUB_CMDLINE_LINUX_DEFAULT, the value will be fully + taken from YaST settings. (bsc#989803) +* Wed Aug 3 2016 mchang@suse.com +- Add patches from Roberto Sassu +- Fix grub2-10_linux-avoid-multi-device-root-kernel-argument.patch, + device path is not tested if GRUB_DISABLE_LINUX_UUID="true" + - added grub2-fix-multi-device-root-kernel-argument.patch + (bsc#960776) +- grub2-zipl-setup: avoid multi-device root= kernel argument + * added grub2-zipl-setup-fix-btrfs-multipledev.patch + (bsc#960776) +- Add SUSE_REMOVE_LINUX_ROOT_PARAM configuration option + to /etc/default/grub, to remove root= and rootflags= from the + kernel command line in /boot/grub2/grub.cfg and /boot/zipl/config + - added grub2-suse-remove-linux-root-param.patch + (bsc#962585) +* Tue Aug 2 2016 mchang@suse.com +- Support HTTP Boot IPv4 and IPv6 (fate#320129) + * 0001-misc-fix-invalid-character-recongition-in-strto-l.patch + * 0002-net-read-bracketed-ipv6-addrs-and-port-numbers.patch + * 0003-bootp-New-net_bootp6-command.patch + * 0004-efinet-UEFI-IPv6-PXE-support.patch + * 0005-grub.texi-Add-net_bootp6-doument.patch + * 0006-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch + * 0007-efinet-Setting-network-from-UEFI-device-path.patch + * 0008-efinet-Setting-DNS-server-from-UEFI-protocol.patch +- Fix heap corruption after dns lookup + * 0001-dns-fix-buffer-overflow-for-data-addresses-in-recv_h.patch +* Mon Jun 27 2016 ro@suse.de +- fix filelist for s390x +* Tue Jun 21 2016 mchang@suse.com +- Fix grub2-editenv error on encrypted lvm installation (bsc#981621) + * modified grub2-btrfs-workaround-grub2-once.patch +- Add missing closing bracket in 'grub2-snapper-plugin.sh'. +- Fix snapshot booting on s390x (bsc#955115) + * modified grub2-snapper-plugin.sh +- Fallback to old subvol name scheme to support old snapshot config + (bsc#953538) + * added grub2-btrfs-07-subvol-fallback.patch +* Thu Jun 2 2016 arvidjaar@gmail.com +- update grub2-once with patch from Björn Voigt - skip comments in + /etc/sysconfig/bootloader (boo#963610) +* Fri May 20 2016 jengelh@inai.de +- Make sure all systemd unit files are passed to %%service_ macros. +* Thu May 19 2016 agraf@suse.com +- Add patch to free memory on exit in efi environments (bsc#980739) + * grub2-efi-Free-malloc-regions-on-exit.patch +* Mon May 2 2016 olaf@aepfle.de +- Remove xen-devel from BuildRequires + required headers are included in grub-2.0.2 +* Thu Apr 28 2016 agraf@suse.com +- Add support for "t" hotkey to switch to text mode (bsc#976836) + * added grub2-SUSE-Add-the-t-hotkey.patch +- Add support for hidden menu entries (bsc#976836) + * added grub2-Add-hidden-menu-entries.patch +* Tue Apr 19 2016 mchang@suse.com +- Correct show user defined comments in menu for snapshots (bsc#956698) + * modified grub2-snapper-plugin.sh +* Mon Mar 21 2016 mchang@suse.com +- Fix GRUB_DISABLE_LINUX_UUID to be ignore and also fallback kernel device + won't be used if fs uuid not detected (bsc#971867) + * added 0001-10_linux-Fix-grouping-of-tests-for-GRUB_DEVICE.patch + * added 0002-20_linux_xen-fix-test-for-GRUB_DEVICE.patch +* Tue Mar 1 2016 arvidjaar@gmail.com +- new upstream version 2.02~beta3 + * highlights of user visible changes not yet present in openSUSE package + - arm-uboot now generates position independent self relocating image, so + single binary should run on all supported systems + - loader for Xen on aarch64. grub-mkconfig support was not in time for + beta3 yet. + - improved ZFS support (extensible_dataset, large_blocks, embedded_data, + hole_birth features) + - support for IPv6 Router Advertisements + - support for persistent memory (we do not overwrite it and pass correct + information to OS) + - try to display more specific icons for os-prober generated menu entries + - grub-install detects EFI bit size and selects correct platform (x86_64-efi + or i386-efi) independent of OS bit size; needs kernel 4.0 or higher. + - LVM RAID1 support + - xnu loader fixes which should make OS X menu entry generated by os-prober + work again + - key modifiers (Ctrl-X etc) should work on EFI too + - ... and lot of fixes over entire tree + * rediff + - rename-grub-info-file-to-grub2.patch + - use-grub2-as-a-package-name.patch + - grub2-GRUB_CMDLINE_LINUX_RECOVERY-for-recovery-mode.patch + - grub2-fix-menu-in-xen-host-server.patch + - grub2-efi-HP-workaround.patch + - grub2-secureboot-chainloader.patch + - grub2-s390x-02-kexec-module-added-to-emu.patch + - grub2-s390x-04-grub2-install.patch + - grub2-s390x-05-grub2-mkconfig.patch + - grub2-efi-xen-chainload.patch + - grub2-mkconfig-aarch64.patch + - grub2-btrfs-04-grub2-install.patch + - grub2-ppc64-cas-reboot-support.patch + - 0002-Add-Virtual-LAN-support.patch + * fix grub2-secureboot-add-linuxefi.patch - use grub_memset and + grub_memcpy instead of memset and memcpy (caused errors due to + compiler warning) + * drop upstream patches + - 0001-grub-core-kern-efi-efi.c-Ensure-that-the-result-star.patch + - 0001-look-for-DejaVu-also-in-usr-share-fonts-truetype.patch + - 0001-efidisk-move-device-path-helpers-in-core-for-efinet.patch + - 0002-efinet-skip-virtual-IPv4-and-IPv6-devices-when-enume.patch + - 0003-efinet-open-Simple-Network-Protocol-exclusively.patch + - 0001-efinet-Check-for-immediate-completition.patch + - 0001-efinet-enable-hardware-filters-when-opening-interfac.patch + - grub2-xen-legacy-config-device-name.patch + - grub2-getroot-support-NVMe-device-names.patch + - grub2-netboot-hang.patch + - grub2-btrfs-fix-incorrect-address-reference.patch + - aarch64-reloc.patch + - grub2-glibc-2.20.patch (related code dropped upstream) + - grub2-Initialized-initrd_ctx-so-we-don-t-free-a-random-poi.patch + - grub2-btrfs-fix-get_root-key-comparison-failures-due-to-en.patch + - grub2-getroot-fix-get-btrfs-fs-prefix-big-endian.patch + - grub2-ppc64-qemu.patch + - grub2-xfs-Add-helper-for-inode-size.patch + - grub2-xfs-Fix-termination-loop-for-directory-iteration.patch + - grub2-xfs-Convert-inode-numbers-to-cpu-endianity-immediate.patch + - grub2-xfs-V5-filesystem-format-support.patch + - 0001-Add-bootargs-parser-for-open-firmware.patch + - grub2-arm64-set-correct-length.patch + - grub2-arm64-setjmp-Add-missing-license-macro.patch + - grub2-arm64-efinet-handle-get_status-on-buggy-firmware-properly.patch + - 0001-unix-password-Fix-file-descriptor-leak.patch + - 0002-linux-getroot-fix-descriptor-leak.patch + - 0003-util-grub-mount-fix-descriptor-leak.patch + - 0004-linux-ofpath-fix-descriptor-leak.patch + - 0005-grub-fstest-fix-descriptor-leak.patch + - ppc64le.patch + - libgcc-prereq.patch + - libgcc.patch + - 0001-Fix-security-issue-when-reading-username-and-passwor.patch + - 0001-menu-fix-line-count-calculation-for-long-lines.patch + - grub2-arm64-Reduce-timer-event-frequency-by-10.patch + - 0001-unix-do-not-close-stdin-in-grub_passwd_get.patch + - 0001-grub-core-kern-i386-tsc.c-calibrate_tsc-Ensure-that.patch + - 0002-i386-tsc-Fix-unused-function-warning-on-xen.patch + - 0003-acpi-do-not-skip-BIOS-scan-if-EBDA-length-is-zero.patch + - 0004-tsc-Use-alternative-delay-sources-whenever-appropria.patch + - 0005-i386-fix-TSC-calibration-using-PIT.patch + - biendian.patch + - ppc64_opt.patch + * drop workarounds for gdb_grub and grub.chrp, they are now installed under fixed name + * do not patch docs/Makefile.in, it is regenerated anyway +* Tue Mar 1 2016 agraf@suse.com +- Make mkconfig search for zImage on arm + * grub2-mkconfig-arm.patch +* Sun Feb 28 2016 agraf@suse.com +- Add support to directly pass an EFI FDT table to a kernel on 32bit arm + * 0001-arm64-Move-firmware-fdt-search-into-global-function.patch + * 0002-arm-efi-Use-fdt-from-firmware-when-available.patch +* Fri Jan 29 2016 mchang@suse.com +- Add config option to set efi xen loader command line option (bsc#957383) + * added grub2-efi-xen-cmdline.patch +* Thu Jan 28 2016 dvaleev@suse.com +- Drop ppc64le patches. Build stage1 as BE for Power + Droped patches: + - grub2-ppc64le-01-Add-Little-Endian-support-for-Power64-to-the-build.patch + - grub2-ppc64le-02-Build-grub-as-O1-until-we-add-savegpr-and-restgpr-ro.patch + - grub2-ppc64le-03-disable-creation-of-vsx-and-altivec-instructions.patch + - grub2-ppc64le-04-powerpc64-LE-s-linker-knows-how-to-handle-the-undefi.patch + - grub2-ppc64le-05-grub-install-can-now-recognize-and-install-a-LE-grub.patch + - grub2-ppc64le-06-set-the-ABI-version-to-0x02-in-the-e_flag-of-the-PPC.patch + - grub2-ppc64le-07-Add-IEEE1275_ADDR-helper.patch + - grub2-ppc64le-08-Fix-some-more-warnings-when-casting.patch + - grub2-ppc64le-09-Add-powerpc64-types.patch + - grub2-ppc64le-10-powerpc64-is-not-necessarily-BigEndian-anymore.patch + - grub2-ppc64le-11-Fix-warnings-when-building-powerpc-linux-loader-64bi.patch + - grub2-ppc64le-12-GRUB_ELF_R_PPC_-processing-is-applicable-only-for-32.patch + - grub2-ppc64le-13-Fix-powerpc-setjmp-longjmp-64bit-issues.patch + - grub2-ppc64le-14-Add-powerpc64-ieee1275-trampoline.patch + - grub2-ppc64le-15-Add-64bit-support-to-powerpc-startup-code.patch + - grub2-ppc64le-16-Add-grub_dl_find_section_addr.patch + - grub2-ppc64le-17-Add-ppc64-relocations.patch + - grub2-ppc64le-18-ppc64-doesn-t-need-libgcc-routines.patch + - grub2-ppc64le-19-Use-FUNC_START-FUNC_END-for-powerpc-function-definit.patch + - grub2-ppc64le-20-.TOC.-symbol-is-special-in-ppc64le-.-It-maps-to-the-.patch + - grub2-ppc64le-21-the-.toc-section-in-powerpc64le-modules-are-sometime.patch + - grub2-ppc64le-22-all-parameter-to-firmware-calls-should-to-be-BigEndi.patch + - grub2-ppc64le-fix-64bit-trampoline-in-dyn-linker.patch + - grub2-ppc64le-timeout.patch + - grub2-ppc64-build-ppc64-32bit.patch +- Added patches: + - biendian.patch + - grub2-ppc64-cas-reboot-support.patch + - libgcc-prereq.patch + - libgcc.patch + - ppc64_opt.patch + - ppc64le.patch +* Wed Jan 20 2016 mchang@suse.com +- Backport upstream patches for HyperV gen2 TSC timer calbration without + RTC (bsc#904647) + * added 0001-grub-core-kern-i386-tsc.c-calibrate_tsc-Ensure-that.patch + * added 0002-i386-tsc-Fix-unused-function-warning-on-xen.patch + * added 0003-acpi-do-not-skip-BIOS-scan-if-EBDA-length-is-zero.patch + * added 0004-tsc-Use-alternative-delay-sources-whenever-appropria.patch + * added 0005-i386-fix-TSC-calibration-using-PIT.patch +* Mon Dec 28 2015 arvidjaar@gmail.com +- Add 0001-menu-fix-line-count-calculation-for-long-lines.patch (bsc#943585) +* Thu Dec 17 2015 olaf@aepfle.de +- grub2-xen-pv-firmware.cfg: fix hd boot (boo#926795) +* Wed Dec 16 2015 arvidjaar@gmail.com +- Add 0001-Fix-security-issue-when-reading-username-and-passwor.patch + Fix for CVE-2015-8370 [boo#956631] +* Wed Dec 9 2015 arvidjaar@gmail.com +- Update grub2-efi-xen-chainload.patch - fix copying of Linux kernel + and initrd to ESP (boo#958193) +* Mon Dec 7 2015 olaf@aepfle.de +- Rename grub2-xen.cfg to grub2-xen-pv-firmware.cfg (boo#926795) +* Fri Dec 4 2015 olaf@aepfle.de +- grub2-xen.cfg: to handle grub1 menu.lst in PV guest (boo#926795) +* Thu Nov 26 2015 mchang@suse.com +- Expand list of grub.cfg search path in PV Xen guest for systems + installed to btrfs snapshot. (bsc#946148) (bsc#952539) + * modified grub2-xen.cfg +- drop grub2-fix-Grub2-with-SUSE-Xen-package-install.patch (bsc#774666) +* Wed Nov 18 2015 arvidjaar@gmail.com +- Add 0001-unix-do-not-close-stdin-in-grub_passwd_get.patch + Fix reading password by grub2-mkpasswd-pbdk2 without controlling + tty, e.g. when called from Xfce menu (boo#954519) +* Sun Nov 1 2015 arvidjaar@gmail.com +- Modify grub2-linguas.sh-no-rsync.patch to re-enable en@quot catalog + (boo#953022). Other autogenerated catalogs still fail to build due + to missing C.UTF-8 locale. +* Fri Oct 30 2015 mchang@suse.com +- Allow to execute menuentry unrestricted as default (fate#318574) + * added grub2-menu-unrestricted.patch +* Thu Oct 29 2015 mchang@suse.com +- Add missing quoting for linuxefi (bsc#951962) + * modified grub2-secureboot-use-linuxefi-on-uefi.patch + * refreshed grub2-secureboot-provide-linuxefi-config.patch +* Sun Oct 18 2015 eich@suse.com +- Include custom.cfg into the files scanned by grub2-once. + Allows to chose manually added entries as well (FATE#319632). +* Wed Oct 7 2015 mchang@suse.com +- Upstream patches for fixing file descriptor leakage (bsc#943784) + * added 0001-unix-password-Fix-file-descriptor-leak.patch + * added 0002-linux-getroot-fix-descriptor-leak.patch + * added 0003-util-grub-mount-fix-descriptor-leak.patch + * added 0004-linux-ofpath-fix-descriptor-leak.patch + * added 0005-grub-fstest-fix-descriptor-leak.patch +* Tue Oct 6 2015 mchang@suse.com +- Do not force ro option in linuxefi patch (bsc#948555) + * modified grub2-secureboot-use-linuxefi-on-uefi.patch + * refrehed grub2-secureboot-provide-linuxefi-config.patch +* Wed Sep 23 2015 dmueller@suse.com +- add 0001-efinet-Check-for-immediate-completition.patch, + 0001-efinet-enable-hardware-filters-when-opening-interfac.patch, + grub2-arm64-efinet-handle-get_status-on-buggy-firmware-properly.patch + (bsc#947203) +* Mon Sep 14 2015 mchang@suse.com +- Set default GRUB_DISTRIBUTOR from /etc/os-release if it is empty + or not set by user (bsc#942519) + * added grub2-default-distributor.patch + * modified grub.default +* Tue Aug 18 2015 mchang@suse.com +- add systemd-sleep-plugin subpackage (bsc#941758) +- evaluate the menu entry's title string by printf + * modified grub2-once + * added grub2-systemd-sleep.sh +* Fri Jul 31 2015 mchang@suse.com +- fix for 'rollback' hint (bsc#901487) + * modified grub2-btrfs-05-grub2-mkconfig.patch: +* Fri Jul 17 2015 mchang@suse.com +- Replace 12.1 with 12 SP1 for the list of snapshots (bsc#934252) + * modified grub2-snapper-plugin.sh +* Thu Jun 18 2015 mchang@suse.com +- Fix btrfs subvol detection on BigEndian systems (bsc#933541) + * modified grub2-btrfs-06-subvol-mount.patch +- Fix grub2-mkrelpath outputs wrong path on BigEndian system + * added grub2-getroot-fix-get-btrfs-fs-prefix-big-endian.patch +* Fri Jun 12 2015 mchang@suse.com +- If we have a post entry and the description field is empty, we should use the + "Pre" number and add that description to the post entry. (fate#317972) +- Show user defined comments in grub2 menu for snapshots (fate#318101) + * modified grub2-snapper-plugin.sh +* Sun Jun 7 2015 arvidjaar@gmail.com +- add 0001-grub-core-kern-efi-efi.c-Ensure-that-the-result-star.patch + make sure firmware path starts with '/' (boo#902982) +* Fri Jun 5 2015 mchang@suse.com +- Fix btrfs patch on BigEndian systems (bsc#933541) + * modified grub2-btrfs-01-add-ability-to-boot-from-subvolumes.patch + * modified grub2-btrfs-06-subvol-mount.patch +* Wed Jun 3 2015 agraf@suse.com +- Fix license for setjmp module + * added grub2-arm64-setjmp-Add-missing-license-macro.patch +* Thu May 21 2015 mchang@suse.com +- Fix install into snapper controlled btrfs subvolume and can't + load grub modules from separate subvolume (fate#318392) + * added grub2-btrfs-06-subvol-mount.patch + * grub2-snapper-plugin.sh: use absolute subvol name +* Tue May 19 2015 arvidjaar@gmail.com +- also Recommends mtools for grub2-mkrescue (used to create EFI + boot image) in addition to libburnia-tools. +* Mon May 11 2015 mchang@suse.com +- Support booting opensuse installer as PV DomU (boo#926795) + * added grub2-xen.cfg for tracking default pvgrub2 xen configs rather than + generating it from spec file + * grub2-xen.cfg: from Olaf Hering +* Sun May 10 2015 arvidjaar@gmail.com +- replace grub2-efinet-reopen-SNP-protocol-for-exclusive-use-by-grub.patch + with upstream version: + * 0001-efidisk-move-device-path-helpers-in-core-for-efinet.patch + * 0002-efinet-skip-virtual-IPv4-and-IPv6-devices-when-enume.patch + * 0003-efinet-open-Simple-Network-Protocol-exclusively.patch + Fixes EFI network boot in some QEMU configurations. +* Wed Apr 29 2015 dmueller@suse.com +- fix grub2-mkconfig-aarch64.patch: fix arch detection broken + by malformed patch rediffing +* Wed Apr 15 2015 mchang@suse.com +- Cleanup patch not applied + * remove grub2-enable-theme-for-terminal-window.patch + * grub2.rpmlintrc: remove addFilter("patch-not-applied") +* Thu Apr 2 2015 mchang@suse.com +- Merge changes from SLE12 +- Do not pass root= when root is on nfs (bnc#894374) + * modified grub2-pass-corret-root-for-nfsroot.patch + * modified grub2-secureboot-provide-linuxefi-config.patch + * modified grub2-secureboot-use-linuxefi-on-uefi.patch +- Fix xen pvops kernel not appear on menu (bnc#895286) + * modified grub2-fix-menu-in-xen-host-server.patch +- Workaround grub2-once (bnc#892358) + * added grub2-btrfs-workaround-grub2-once.patch + * added grub2-once.service + * modified grub2-once +- Fix busy-loop and hang while network booting (bnc#870613) + * added grub2-netboot-hang.patch +- Add warning in grubenv file about editing it directly (bnc#887008) + * added grub2-editenv-add-warning-message.patch +- Fix broken graphics with efifb on QEMU/KVM and nomodeset (bnc#884558) + * added grub2-efi-disable-video-cirrus-and-bochus.patch +- Disable video support on Power (bnc#877142) + * added grub2-ppc64le-disable-video.patch +- Track occupied memory so it can be released on exit (bnc#885026) + * added grub2-ppc64le-memory-map.patch +- Fix grub.xen config searching path on boot partition (bnc#884828) +- Add linux16 and initrd16 to grub.xen (bnc#884830) + * added grub2-xen-linux16.patch +- VLAN tag support (fate#315753) + * added 0001-Add-bootargs-parser-for-open-firmware.patch + * added 0002-Add-Virtual-LAN-support.patch +- Use chainloader to boot xen.efi under UEFI (bnc#871857) + * added grub2-efi-xen-chainload.patch +- Use device part of chainloader target, if present (bnc#871857) + * added grub2-efi-chainloader-root.patch +- Create only hypervisor pointed by /boot/xen.gz symlink (bnc#877040) + * modified grub2-fix-Grub2-with-SUSE-Xen-package-install.patch +- Fix xen and native entries differ in grub.cfg (bnc#872014) + * modified grub2-linux.patch +- Fix install error on ddf md device (bnc#872360) + * added grub2-getroot-treat-mdadm-ddf-as-simple-device.patch +- Fix booting from NVMe device (bnc#873132) + * added grub2-getroot-support-NVMe-device-names.patch +- Document peculiarities of s390 terminals + * added README.ibm3215 +- Grub2 for System z (fate#314213) + * added grub2-s390x-02-kexec-module-added-to-emu.patch + * added grub2-s390x-03-output-7-bit-ascii.patch + * added grub2-s390x-04-grub2-install.patch + * added grub2-s390x-05-grub2-mkconfig.patch +* Mon Mar 16 2015 schwab@suse.de +- grub2-arm64-set-correct-length.patch: arm64: set correct length of + device path end entry +* Wed Mar 4 2015 mchang@suse.com +- grub2-efi-HP-workaround.patch: + * try to read config from all-uppercase prefix as last resort. + (bnc#872503) (boo#902982) +* Mon Feb 16 2015 arvidjaar@gmail.com +- add luks, gcry_rijndael, gcry_sha1 to signed EFI image to support + LUKS partition in default setup (boo#917427) +* Thu Feb 5 2015 mchang@suse.com +- enable i386-xen (boo#891043) +* Wed Feb 4 2015 mchang@suse.com +- Downgrade os-prober dependency to Recommends (boo#898610) +* Thu Dec 25 2014 mchang@suse.com +- grub2-snapper-plugin.sh: cleanup grub-snapshot.cfg not referring + to any snapshot (boo#909359) +* Thu Dec 25 2014 mpluskal@suse.com +- Require efibootmgr also on i586 +* Tue Dec 16 2014 schwab@suse.de +- Require efibootmgr also on aarch64 +* Thu Dec 11 2014 schwab@suse.de +- grub2-snapper-plugin.sh: fix use of printf without format string; fix + quoting +* Wed Dec 10 2014 schwab@suse.de +- grub2-arm64-Reduce-timer-event-frequency-by-10.patch: fix periodic timer + on arm64 +* Thu Dec 4 2014 agraf@suse.com +- enable 32bit arm targets for uboot and efi +* Sat Nov 29 2014 ledest@gmail.com +- Replace 'echo -e' command in grub2-snapper-plugin.sh script to + 'printf' command. '-e' option of 'echo' command may be + unsupported in some POSIX-complete shells. +* Fri Nov 14 2014 ledest@gmail.com +- fix bashism in post script +* Thu Oct 30 2014 jdelvare@suse.de +- grub2.spec: Fix conditional construct which wasn't supported by + older versions of rpmbuild (caused error message + "parseExpressionBoolean returns -1".) +* Thu Oct 30 2014 mchang@suse.com +- fix errors when boot is btrfs with Windows partition scheme. The + first partition is created on cylinder boundary that can't offer + enough room for core.img and also the installation has to be in + logical paritition which made MBR the only location to install. + (bnc#841247) + * add grub2-setup-try-fs-embed-if-mbr-gap-too-small.patch +* Tue Sep 30 2014 mchang@suse.com +- packaging 20_memtest86+ and 20_ppc_terminfo in corresponing grubarch + package +* Mon Sep 29 2014 fcastelli@suse.com +- Add '80_suse_btrfs_snapshot' required to show btrfs snapshots inside + of the boot menu. +* Sun Sep 28 2014 arvidjaar@gmail.com +- fix btrfs on big endian systems (ppc/ppc64) + * add grub2-btrfs-fix-get_root-key-comparison-failures-due-to-en.patch +* Sun Sep 21 2014 arvidjaar@gmail.com +- update translations +- fix possible access to uninitialized pointer in linux loader + * add grub2-Initialized-initrd_ctx-so-we-don-t-free-a-random-poi.patch + * drop superceded grub2-ppc64le-23-grub-segfaults-if-initrd-is-specified-before-specify.patch +* Thu Sep 18 2014 mchang@suse.com +- fix grub.xen not able to handle legacy menu.lst hdX names (bnc#863821) + * add grub2-xen-legacy-config-device-name.patch from arvidjaar +- fix the performance of grub2 uefi pxe is bad (bnc#871555) + * add grub2-efinet-reopen-SNP-protocol-for-exclusive-use-by-grub.patch +* Tue Sep 16 2014 schwab@suse.de +- grub2-mkconfig-aarch64.patch: Look for Image-* instead of vmlinuz-* on + aarch64 +* Mon Sep 15 2014 arvidjaar@gmail.com +- add grub2-glibc-2.20.patch - fix build with glibc 2.20+ + (use _DEFAULT_SOURCE to avoid warning) +* Fri Sep 12 2014 mchang@suse.com +- fix xen pvops kernel not appear on menu (bnc#895286) + * refresh grub2-fix-menu-in-xen-host-server.patch +* Wed Sep 10 2014 mchang@suse.com +- fix extraneous comma in printf shell command (bnc#895884) + * refresh grub2-btrfs-04-grub2-install.patch +* Wed Aug 27 2014 schwab@suse.de +- aarch64-reloc.patch: replace with upstream solution +* Mon Aug 25 2014 mchang@suse.com +- remove unused patch, which's supersceded by new snapper rollback + support patches + * 0001-script-provide-overridable-root-by-subvol.patch + * 0002-script-create-menus-for-btrfs-snapshot.patch +* Fri Aug 22 2014 mchang@suse.com +- fix openqa boot error on separate boot partition + * refresh grub2-btrfs-05-grub2-mkconfig.patch +* Thu Aug 21 2014 mchang@suse.com +- update snapper plugin for rollback support + * refresh grub2-snapper-plugin.sh +* Fri Aug 15 2014 mchang@suse.com +- snapper rollback support patches. +- rename patch + * 0002-btrfs-add-ability-to-boot-from-subvolumes.patch to + grub2-btrfs-01-add-ability-to-boot-from-subvolumes.patch + * 0004-btrfs-export-subvolume-envvars.patch to + grub2-btrfs-02-export-subvolume-envvars.patch +- added patches + * grub2-btrfs-03-follow_default.patch + * grub2-btrfs-04-grub2-install.patch + * grub2-btrfs-05-grub2-mkconfig.patch +- remove patch + * 0003-cmdline-add-envvar-loader_cmdline_append.patch +* Thu Aug 14 2014 mchang@suse.com +- grub2-btrfs-fix-incorrect-address-reference.patch + * Fix incorrect address reference in GRUB_BTRFS_EXTENT_REGULAR + range check (bnc#869748) +* Wed Aug 13 2014 mchang@suse.com +- grub2-vbe-blacklist-preferred-1440x900x32.patch + * Blacklist preferred resolution 1440x900x32 which is broken on + many Thinkpads (bnc#888727) +* Tue Aug 12 2014 schwab@suse.de +- Enable building on aarch64 +- aarch64-reloc.patch: support R_AARCH64_PREL32 relocation +- Build host tools with RPM_OPT_FLAGS +* Mon Aug 11 2014 dvaleev@suse.com +- Fix the 64-bit trampoline code in dynamic linker (bnc#890999) + grub2-ppc64le-fix-64bit-trampoline-in-dyn-linker.patch +* Tue Jul 29 2014 tiwai@suse.de +- Prefer a higher resolution in efi_gop driver if the mode taking + over is too small like 640x480 (bnc#887972): + grub2-efi_gop-avoid-low-resolution.patch +* Wed Jul 9 2014 dvlaeev@suse.com +- Fix ppc64le build by fixing + grub2-xfs-V5-filesystem-format-support.patch +* Wed Jun 25 2014 jack@suse.cz +- xfs V5 superblock support (bnc#880166 bnc#883942) +- added patches: + * grub2-xfs-Add-helper-for-inode-size.patch + * grub2-xfs-Fix-termination-loop-for-directory-iteration.patch + * grub2-xfs-Convert-inode-numbers-to-cpu-endianity-immediate.patch + * grub2-xfs-V5-filesystem-format-support.patch +* Fri Jun 20 2014 jeffm@suse.com +- grub2: use stat instead of udevadm for partition lookup (bnc#883635) + * Added grub2-use-stat-instead-of-udevadm-for-partition-lookup.patch +* Tue Apr 15 2014 tchvatal@suse.com +- Fix sorting of RC kernels to be older than first regular of the + series. Fixes bnc#827531. +- added patches: + * grub2-use-rpmsort-for-version-sorting.patch +* Thu Apr 10 2014 dvaleev@suse.com +- Build GRUB2 for ppc64le as LittleEndian and 64bit +- Fix timeout issue on ppc64le (bnc#869166) +- Add powerpc-utils requires to grub2-powerpc-ieee1275 +- added patches: + * grub2-ppc64-build-ppc64-32bit.patch + * grub2-ppc64-qemu.patch + * grub2-ppc64le-01-Add-Little-Endian-support-for-Power64-to-the-build.patch + * grub2-ppc64le-02-Build-grub-as-O1-until-we-add-savegpr-and-restgpr-ro.patch + * grub2-ppc64le-03-disable-creation-of-vsx-and-altivec-instructions.patch + * grub2-ppc64le-04-powerpc64-LE-s-linker-knows-how-to-handle-the-undefi.patch + * grub2-ppc64le-05-grub-install-can-now-recognize-and-install-a-LE-grub.patch + * grub2-ppc64le-06-set-the-ABI-version-to-0x02-in-the-e_flag-of-the-PPC.patch + * grub2-ppc64le-07-Add-IEEE1275_ADDR-helper.patch + * grub2-ppc64le-08-Fix-some-more-warnings-when-casting.patch + * grub2-ppc64le-09-Add-powerpc64-types.patch + * grub2-ppc64le-10-powerpc64-is-not-necessarily-BigEndian-anymore.patch + * grub2-ppc64le-11-Fix-warnings-when-building-powerpc-linux-loader-64bi.patch + * grub2-ppc64le-12-GRUB_ELF_R_PPC_-processing-is-applicable-only-for-32.patch + * grub2-ppc64le-13-Fix-powerpc-setjmp-longjmp-64bit-issues.patch + * grub2-ppc64le-14-Add-powerpc64-ieee1275-trampoline.patch + * grub2-ppc64le-15-Add-64bit-support-to-powerpc-startup-code.patch + * grub2-ppc64le-16-Add-grub_dl_find_section_addr.patch + * grub2-ppc64le-17-Add-ppc64-relocations.patch + * grub2-ppc64le-18-ppc64-doesn-t-need-libgcc-routines.patch + * grub2-ppc64le-19-Use-FUNC_START-FUNC_END-for-powerpc-function-definit.patch + * grub2-ppc64le-20-.TOC.-symbol-is-special-in-ppc64le-.-It-maps-to-the-.patch + * grub2-ppc64le-21-the-.toc-section-in-powerpc64le-modules-are-sometime.patch + * grub2-ppc64le-22-all-parameter-to-firmware-calls-should-to-be-BigEndi.patch + * grub2-ppc64le-23-grub-segfaults-if-initrd-is-specified-before-specify.patch + * grub2-ppc64le-timeout.patch +- removed patches: + * grub2-powerpc-libgcc.patch + * grub2-ppc64le-core-bigendian.patch + * grub2-ppc64le-platform.patch +* Thu Apr 10 2014 mchang@suse.com +- add grub2-x86_64-xen subpackage (bnc#863821) +* Sat Apr 5 2014 arvidjaar@gmail.com +- rename grub2.chrp back into grub.chrp, otherwise it is not found by + grub tools +- replace grub2-use-DejaVuSansMono-for-starfield-theme.patch with + grub2-use-Unifont-for-starfield-theme-terminal.patch - use Unifont + font for terminal window +* Thu Feb 27 2014 mchang@suse.com +- grub2-snapper-plugin: fix important snapshots are not marked as such + in grub2 menu, also display the snapshot entries in the format + "important distribution version (kernel_version, timestamp, pre/post)" + (bnc#864842) +* Mon Feb 24 2014 mchang@suse.com +- refresh grub2-fix-menu-in-xen-host-server.patch (bnc#859361) + * prevent 10_linux from booting xen kernel without pv_opt support + on systems other than xen PV domU guest + * prevent 20_linux_xen.in from setting up nested virt running from + Xen domU +- refresh grub2-fix-Grub2-with-SUSE-Xen-package-install.patch + * adjust accordingly +* Thu Feb 20 2014 jw@suse.com +- updating grub2-once + - added --list switch. + - improved --help and error handling. +* Tue Feb 11 2014 mchang@suse.com +- add Supplements: packageand(snapper:grub2) in grub2-snapper-plugin + to install it while both snapper and grub2 are installed +* Wed Feb 5 2014 mchang@suse.com +- add grub2-snapper-plugin.sh (fate#316232) + * grub2's snapper plugin for advanced btrfs snapshot menu management + * package as grub2-snapper-plugin.noarch +- refresh 0002-script-create-menus-for-btrfs-snapshot.patch + * when booting btrfs snapshots disabled, deleting snapshot master config + if it's not customized +* Fri Jan 31 2014 dvaleev@suse.com +- Enable grub2 for PowerPC LE (ppc64le) +- Add ppc64le to exclusive arches +- Don't require gcc-32bit (PowerLE don't have 32bit toolchain) +- added patches: + * grub2-powerpc-libgcc.patch + Provide 32bit libgcc functions for PowerLE + * grub2-ppc64le-core-bigendian.patch + Build grub kernel and images as BE on ppc64le (BL is BE there) + * grub2-ppc64le-platform.patch + Enable ppc64le platform +* Fri Jan 24 2014 jjolly@suse.com +- Add changes to allow build for s390x arch: added + grub2-s390x-01-Changes-made-and-files-added-in-order-to-allow-s390x.patch +* Wed Jan 22 2014 mchang@suse.com +- refresh 0002-script-create-menus-for-btrfs-snapshot.patch + * Fix bootable snapshots not found while root is on Btrfs subvolume + (bnc#859587) + * Create missing slave config in /.snapshots// + * Prefix with SUSE_ for related options +* Fri Jan 17 2014 mchang@suse.com +- refresh 0001-script-provide-overridable-root-by-subvol.patch + * Introduce $boot_prefix for setting prefix on seeking other /boot + directory. +- refresh 0002-script-create-menus-for-btrfs-snapshot.patch + * Support existing snapshots by creating their missing slave configs. + * Temporarily default to disable this feature until receiving more + tests from QA. + * Introduce GRUB_ENABLE_CUSTOM_SNAPSHOT_SUBMENU to allow custom + submenu for listing snapshots rather than the default one. +* Wed Jan 15 2014 arvidjaar@gmail.com +- package autoiso.cfg and osdetect.cfg as documentation +- add 0001-look-for-DejaVu-also-in-usr-share-fonts-truetype.patch - + fix configure test for DejaVu font +- add dejavu-fonts to BR (needed to build starfield theme) +- package starfield theme as grub2-branding-upstream +- add grub2-use-DejaVuSansMono-for-starfield-theme.patch - use fixed width + font for starfield theme +- clarify that grub2 subpackage contains only user space tools +* Wed Jan 15 2014 mchang@suse.com +- add new patches for booting btrfs snapshot (fate#316522) (fate#316232) + * 0001-script-provide-overridable-root-by-subvol.patch + * 0002-script-create-menus-for-btrfs-snapshot.patch +* Fri Dec 27 2013 arvidjaar@gmail.com +- update to grub-2.02 beta2 + * drop upstream patches + - grub2-fix-unquoted-string-in-class.patch (different) + - grub2-cdpath.patch (modified) + - grub2-fix-parsing-of-short-LVM-PV-names.patch + - grub2-fix-descriptor-leak-in-grub_util_is_imsm.patch + - grub2-install-opt-skip-fs-probe.patch (file it patched no more exists, + functionality included upstream) + - grub2-fix-x86_64-efi-startup-stack-alignment.patch + - grub2-fix-x86_64-efi-callwrap-stack-alignment.patch + - 0001-Fix-build-with-FreeType-2.5.1.patch + * rediff + - grub2-linux.patch + - use-grub2-as-a-package-name.patch (do not patch generated configure) + - grub2-GRUB_CMDLINE_LINUX_RECOVERY-for-recovery-mode.patch + - grub2-fix-locale-en.mo.gz-not-found-error-message.patch (upstream added + explicit exclusion for en_* language only; I do not see reason to stop + with error in this case for any language). + - not-display-menu-when-boot-once.patch + - grub2-secureboot-provide-linuxefi-config.patch + - grub2-pass-corret-root-for-nfsroot.patch + - 0002-btrfs-add-ability-to-boot-from-subvolumes.patch + - grub2-fix-menu-in-xen-host-server.patch + - grub2-fix-Grub2-with-SUSE-Xen-package-install.patch + - grub2-secureboot-add-linuxefi.patch + - grub2-secureboot-no-insmod-on-sb.patch + - rename-grub-info-file-to-grub2.patch + * drop Makefile.util.am and Makefile.core.am, they are now generated + during build + * call ./autogen.sh again now when it does not need autogen anymore; drop + autoreconf call, it is called by autogen.sh + * drop 0001-btrfs-rename-skip_default-to-follow_default.patch - is not + needed anymore due to upstream changes + * package /usr/bin/grub2-file, /usr/bin/grub2-syslinux2cfg and + /usr/sbin/grub2-macbless + * use grub-install --no-bootsector instead of --grub-setup=/bin/true + in postinstall script +* Tue Dec 17 2013 mchang@suse.com +- add new patches for booting btrfs snapshot (fate#316522) (fate#316232) + * 0001-btrfs-rename-skip_default-to-follow_default.patch + * 0002-btrfs-add-ability-to-boot-from-subvolumes.patch + * 0003-cmdline-add-envvar-loader_cmdline_append.patch + * 0004-btrfs-export-subvolume-envvars.patch +* Tue Dec 10 2013 arvidjaar@gmail.com +- add patch 0001-Fix-build-with-FreeType-2.5.1.patch - fix build with + freetype2 >= 2.5.1 (backport from fd0df6d098b1e6a4f60275c48a3ec88d15ba1fbb) +* Sun Dec 1 2013 arvidjaar@gmail.com +- reset executable bits on *module, *.exec and *.image files. They are not + executable. +* Fri Nov 22 2013 glin@suse.com +- add grub2-fix-x86_64-efi-startup-stack-alignment.patch and + grub2-fix-x86_64-efi-callwrap-stack-alignment.patch: fix the + stack alignment of x86_64 efi. (bnc#841426) +* Wed Sep 11 2013 mchang@suse.com +- use new update-bootloader option --reinit to install and update + bootloader config +- refresh grub2-secureboot-no-insmod-on-sb.patch to fobid module + loading completely. +* Mon Sep 9 2013 lnussel@suse.de +- replace openSUSE UEFI certificate with new 2048 bit certificate. +* Sat Jul 27 2013 arvidjaar@gmail.com +- add grub2-fix-parsing-of-short-LVM-PV-names.patch - fix PV detection in + grub-probe when PV name is less than 10 charaters +- add grub2-fix-descriptor-leak-in-grub_util_is_imsm.patch - fix decriptor + leak which later caused LVM warnings during grub-probe invocation +- remove --enable-grub-emu-usb - it is not needed on physical platform +* Tue Jul 9 2013 mchang@suse.com +- refresh grub2-fix-menu-in-xen-host-server.patch: In domU we + have to add xen kernel to config. (bnc#825528) +* Wed Jun 26 2013 elchevive@opensuse.org +- updated existent translations and include new ones + (es, lt, pt_BR, sl, tr) +* Sun Jun 16 2013 arvidjaar@gmail.com +- update to current upstream trunk rev 5042 + * drop upstream patches + - grub2-correct-font-path.patch + - grub2-fix-mo-not-copied-to-grubdir-locale.patch + - grub2-stdio.in.patch + - grub2-fix-build-error-on-flex-2.5.37.patch + - grub2-quote-messages-in-grub.cfg.patch + - 30_os-prober_UEFI_support.patch + - grub2-fix-enumeration-of-extended-partition.patch + - grub2-add-device-to-os_prober-linux-menuentry.patch + - grub2-fix-tftp-endianness.patch + - efidisk-ahci-workaround + - grub2-grub-mount-return-failure-if-FUSE-failed.patch + * rediff + - rename-grub-info-file-to-grub2.patch + - grub2-linux.patch + - use-grub2-as-a-package-name.patch + - grub2-iterate-and-hook-for-extended-partition.patch + - grub2-secureboot-add-linuxefi.patch + - grub2-secureboot-no-insmod-on-sb.patch + - grub2-secureboot-chainloader.patch + * add + - grub2-linguas.sh-no-rsync.patch + + disable rsync in linguas.sh so it can be used during RPM build + + disable auto-generated catalogs, they fail at the moment due to + missing C.UTF-8 locale + * update Makefile.util.am and Makefile.core.am + * grub2-mknetdir is now in /usr/bin + * generate po/LINGUAS for message catalogs using distributed linguas.sh + * remove po/stamp-po during setup to trigger message catalogs rebuild + * package bootinfo.txt on PPC (used by grub2-mkrescue) +* Sat Apr 13 2013 arvidjaar@gmail.com +- BuildRequires: help2man to generate man pages and package them too +* Fri Apr 5 2013 arvidjaar@gmail.com +- add grub2-secureboot-use-linuxefi-on-uefi-in-os-prober.patch (bnc#810912) + * use linuxefi in 30_os-prober if secure boot is enabled +* Wed Apr 3 2013 arvidjaar@gmail.com +- update rename-grub-info-file-to-grub2.patch + * do not rename docs/grub2.texi here, do it in %%%%prep (we do it there + conditionally already). It simplifies patch refreshing using quilt + which does not support file rename. +* Wed Apr 3 2013 mchang@suse.com +- refresh grub2-secureboot-chainloader.patch: Fix wrongly aligned + buffer address (bnc#811608) +* Thu Mar 28 2013 mchang@suse.com +- package Secure Boot CA file as /usr/lib64/efi/grub.der which + could be used to verify signed image from build server +- add openSUSE-UEFI-CA-Certificate.crt, openSUSE Secure Boot CA +- add SLES-UEFI-CA-Certificate.crt, SUSE Linux Enterprise Secure + Boot CA +* Mon Mar 25 2013 dvaleev@suse.com +- extraconfigure macro is not defined on ppc +* Sat Mar 23 2013 arvidjaar@gmail.com +- corretly set chainloaded image device handle in secure boot mode (bnc#809038) +* Wed Mar 13 2013 mchang@suse.com +- remove all compatible links in grub2-efi as now all concerned + utilities are fixed +- superseding grub2-efi by grub2-x86_64-efi and grub2-i386-efi on + x86_64 and ix86 respectively +- make grub2-x86_64-efi and grub2-i386-efi providing grub2-efi + capability to not break package dependency +- handle upgrade from 12.2 by preseving grubenv and custom.cfg to + new directory /boot/grub2, rename /boot/grub2-efi to + /boot/grub2-efi.rpmsave to avoid confusion. +* Mon Mar 11 2013 arvidjaar@gmail.com +- move post scripts into corresponding subpackages to ensure they are + run after updated binaries are installed. Currently it may happen + that update-bootlader picks up old binaries. +- move requires for perl-Bootloader to target subpackages. Make sure + efi requires minimal version that supports /boot/grub2. +- add requires(post) to force order of installation: grub2 => grub2-arch + => grub2-efi +- split efi post in two parts. One that updates configuration and is part + of grub2-efiarch and second that migrates settings and is part of + grub2-efi. Only custom.cfg and grubenv may need migration. device.map + is not relevant for EFI and new grub.cfg had been created at this point. +* Mon Mar 11 2013 mchang@suse.com +- add grub2-fix-tftp-endianness.patch from upstream (bnc#808582) +- add efinet and tftp to grub.efi (bnc#808582) +* Thu Mar 7 2013 seife+obs@b1-systems.com +- convert spec file to UTF-8 +* Thu Mar 7 2013 mchang@suse.com +- add lvm to grub.efi (bnc#807989) +- add loadenv to grub.efi (bnc#807992) +* Mon Mar 4 2013 arvidjaar@gmail.com +- grub2-grub-mount-return-failure-if-FUSE-failed.patch - return error + if fuse_main failed (bnc#802983) +* Mon Feb 25 2013 fcrozat@suse.com +- Fix build for SLES 11. +* Tue Feb 19 2013 duwe@suse.com + Fix up bogus items from the previous merge: + - efi_libdir = _libdir = /usr/lib + - package /usr/lib/grub2 dir only once + - move grub.efi to /usr/lib/grub2/%%{grubefiarch}/ + - create a symlink so that scripts can find it there. +* Thu Feb 14 2013 duwe@suse.com +- merge internal+external BS changes into superset spec file, + remove obsolete dependencies +- merge SLES+openSUSE patches, restrict "grub-efi" to 12.2 +- add efidisk-ahci-workaround (bnc#794674) +- fix unquoted-string-in-class.patch (bnc#788322) +* Fri Feb 8 2013 mchang@suse.com +- adapt to pesign-obs-integration changes +* Thu Feb 7 2013 mchang@suse.com +- grub.efi signing on build server. +* Thu Jan 31 2013 duwe@suse.com +- switch to out of source / subdir build +* Wed Jan 30 2013 mchang@suse.com +- sync from SLE-11 SP3 to date +- set empty prefix to grub.efi for looking up in current directory +- grub2-cdpath.patch: fix the grub.cfg not found when booting from + optical disk +- put grub.efi in grub2's source module directory +- create links in system's efi directory to grub.efi +- arvidjaar: do not overwrite device path in grub2-cdpath.patch +* Wed Jan 30 2013 arvidjaar@gmail.com +- remove obsolete reference to /boot/grub2-efi and /usr/sbin/grub2-efi + from grub2-once +- add GRUB_SAVEDFAULT description to /etc/default/grub +* Tue Jan 29 2013 mchang@suse.com +- set empty prefix to grub.efi for looking up in current directory +- remove grubcd.efi, as grub.efi can now be used for cdrom booting +* Mon Jan 28 2013 snwint@suse.de +- add fat module to grubcd +- explicitly set empty prefix to get grub to set $prefix to the currrent + directory +* Fri Jan 18 2013 mchang@suse.com +- ship a Secure Boot UEFI compatible bootloader (fate#314485) +- add grub2-secureboot-chainloader.patch, which expands the efi + chainloader to be able to verify images via shim lock protocol. +* Fri Jan 18 2013 mchang@suse.com +- ship a Secure Boot UEFI compatible bootloader (fate#314485). +- update for cdrom boot support. +- grub2-cdpath.patch: fix the grub.cfg not found when booting from + optical disk. +- grubcd.efi: the efi image used for optial disk booting, with + reduced size and $prefix set to /EFI/BOOT. +* Tue Jan 8 2013 mchang@suse.com +- add grub2-fix-unquoted-string-in-class.patch (bnc#788322) +* Tue Jan 8 2013 arvidjaar@gmail.com +- add grub2-add-device-to-os_prober-linux-menuentry.patch (bnc#796919) +* Sun Jan 6 2013 arvidjaar@gmail.com +- add patch grub2-fix-enumeration-of-extended-partition.patch to + fix enumeration of extended partitions with non-standard EBR (bnc#779534) +* Fri Jan 4 2013 arvidjaar@gmail.com +- add support for chainloading another UEFI bootloader to + 30_os-prober (bnc#775610) +* Fri Dec 21 2012 mchang@suse.com +- put 32-bit grub2 modules to /usr/lib/grub2 +- put 64-bit grub2 modules to /usr/lib64/grub2 (x86_64-efi) +- put grub.efi to /usr/lib64/efi(x86_64) or /usr/lib/efi(i586) +* Tue Dec 18 2012 mchang@suse.com +- ship a Secure Boot UEFI compatible bootloader (fate#314485) +- add grub2-secureboot-chainloader.patch, which expands the efi + chainloader to be able to verify images via shim lock protocol. +* Fri Nov 30 2012 mchang@suse.com +- replace %%{sles_version} by %%{suse_version} +- use correct product name +* Mon Nov 26 2012 mchang@suse.com +- ship a Secure Boot UEFI compatible bootloader (fate#314485) +- added secureboot patches which introduces new linuxefi module + that is able to perform verifying signed images via exported + protocol from shim. The insmod command will not function if + secure boot enabled (as all modules should built in grub.efi + and signed). + - grub2-secureboot-add-linuxefi.patch + - grub2-secureboot-use-linuxefi-on-uefi.patch + - grub2-secureboot-no-insmod-on-sb.patch + - grub2-secureboot-provide-linuxefi-config.patch +- Makefile.core.am : support building linuxefi module +- Make grub.efi image that is with all relevant modules incorporated + and signed, it will be the second stage to the shim loader which + will verified it when secureboot enabled. +- Make grub.efi's path to align with shim loader's default loader + lookup path. +- The changes has been verified not affecting any factory instalation, + but will allow us to run & test secure boot setup manually with shim. +* Thu Nov 22 2012 mchang@suse.com +- ship a Secure Boot UEFI compatible bootloader (fate#314485) +- In SLE-11 SP3, don't include any other architecture binaries + except EFI, so we split packages by architecture binaries to + meet the requirement. + - grub2 : common utilties and config etc + - grub2-efi : provide compatibilty to grub2-efi package + - grub2-i386-pc : binaries for x86 legacy pc firmware + - grub2-i386-efi : binaries for ia32 EFI firmware + - grub2-x86_64-efi : binaries for x86_64 firmware + - grub2-powerpc-ieee1275: binaries for powerpc open firmware +* Tue Nov 20 2012 arvidjaar@gmail.com +- update grub2-quote-messages-in-grub.cfg.patch to use upstream commit +* Mon Nov 19 2012 arvidjaar@gmail.com +- quote localized "Loading ..." messages in grub.cfg (bnc#790195) +* Mon Nov 5 2012 aj@suse.de +- We really only need makeinfo, so require that one where it exists. +* Thu Nov 1 2012 mchang@suse.com +- ship a Secure Boot UEFI compatible bootloader (fate#314485) +- Secure boot support in installer DVD (fate#314489) +- prime support for package on SLE-11 (SP3) + - remove buildrequire to libuse and ncurses 32-bit devel packages + as they are needed by grub-emu which we don't support + - remove buildrequire to freetype2-devel-32bit as it's not need + by grub2-mkfont and others + - buildrequire to xz instead of lzma + - buildrequire to texinfo instead of makeinfo + - remove buildrequire to autogen as it's not available in SLE-11 + - add Makefile.util.am Makefile.core.am generated by autogen + - run autoreconf -vi instead of ./autogen.sh + - For SLE-11 remove buildrequire to gnu-unifont as it's not + yet available. Also do not package pf fonts created from it. + - workaround SLE-11 patch utility not rename file for us + - add -fno-inline-functions-called-once to CFLAGS to fix build + error on gcc 4.3.x + - not require os-prober for SLE-11, as package not yet ready +* Sat Oct 27 2012 arvidjaar@gmail.com +- grub2-efi now depends on exact grub2 version +* Thu Oct 25 2012 arvidjaar@gmail.com +- build grub2-efi with standard "grub2" prefix (bnc#782891) + - remove use-grub2-efi-as-a-package-name.patch + - migrate settings from /boot/grub2-efi to /boot/grub2 in efi post + - provide some compatibility links grub2-efi-xxx for perl-Bootloader + - workaround for /boot/grub2-efi linkk and /boot/grub2/grub.cfg + missing on update from older versions +* Thu Oct 25 2012 mchang@suse.com +- add grub2-fix-build-error-on-flex-2.5.37.patch +* Thu Oct 18 2012 arvidjaar@gmail.com +- modify patch grub2-iterate-and-hook-for-extended-partition.patch to + ignore extended partitions other then primary (bnc#785341) +* Wed Sep 26 2012 mchang@suse.com +- refresh grub2-fix-locale-en.mo.gz-not-found-error-message.patch + with the correct fix in upstream bugzilla #35880 by Colin Watson + (bnc#771393) +* Fri Sep 21 2012 mchang@suse.com +- grub2-fix-locale-en.mo.gz-not-found-error-message.patch (bnc#771393) +* Wed Sep 19 2012 arvidjaar@gmail.com +- add 20_memtest86+ (bnc#780622) +* Tue Sep 18 2012 mchang@suse.com +- Fix un-bootable grub2 testing entry in grub's menu.lst (bnc#779370) +- Not add new grub2 testing entry if it's not found in menu.lst +- Update grub2 stuff and config if there's grub2 entry in menu.lst +- Check for current bootloader as update-bootloader acts on it +* Thu Aug 30 2012 mchang@suse.com +- add grub2-fix-Grub2-with-SUSE-Xen-package-install.patch (bnc#774666) +- add grub2-pass-corret-root-for-nfsroot.patch (bnc#774548) +* Mon Aug 20 2012 mchang@suse.com +- disable grub2-enable-theme-for-terminal-window.patch to use + default black background due to current background has poor + contrast to the font color (bnc#776244). +* Fri Aug 10 2012 jslaby@suse.de +- rename grub2once to grub2-once +* Wed Aug 1 2012 mchang@suse.com +- add grub2once (bnc#771587) +- add not-display-menu-when-boot-once.patch +* Sat Jul 28 2012 aj@suse.de +- Fix build with missing gets declaration (glibc 2.16) +* Fri Jul 27 2012 tittiatcoke@gmail.com +- Add grub2-enable-theme-for-terminal-window.patch (bnc#770107) +* Thu Jul 19 2012 mchang@suse.com +- add grub2-fix-menu-in-xen-host-server.patch (bnc#757895) +* Wed Jul 18 2012 mchang@suse.com +- add grub2-fix-error-terminal-gfxterm-isn-t-found.patch +- add grub2-fix-mo-not-copied-to-grubdir-locale.patch +* Wed Jul 18 2012 aj@suse.de +- We only need makeinfo, not texinfo for building. +* Tue Jul 17 2012 jslaby@suse.de +- fix build by adding texinfo to buildrequires. +* Fri Jul 6 2012 mchang@suse.com +- grub2-GRUB_CMDLINE_LINUX_RECOVERY-for-recovery-mode.patch. We + don't run in sigle user mode for recovery, instead use different + set kernel command line options which could be specified by this + GRUB_CMDLINE_LINUX_RECOVERY setting. +* Wed Jul 4 2012 mchang@suse.com +- add use-grub2-efi-as-a-package-name.patch (bnc#769916) +* Fri Jun 29 2012 dvaleev@suse.com +- Add configuration support for serial terminal consoles. This will + set the maximum screen size so that text is not overwritten. +* Fri Jun 29 2012 dvaleev@suse.com +- don't enable grub-emu-usb on ppc ppc641 +* Thu Jun 28 2012 jslaby@suse.de +- update to 2.0 final + * see ChangeLog for changes +* Mon Jun 25 2012 adrian@suse.de +- enable xz/lzma support for image file generation +* Sun Jun 24 2012 jslaby@suse.de +- update to 2.0 beta6, a snapshot from today + * see ChangeLog for changes +* Fri Jun 22 2012 mchang@suse.com +- do not package grub.cfg, as it's generated at runtime and the + presence of it would confuse pygrub (bnc#768063) +* Wed May 16 2012 mchang@suse.com +- fix build error on 12.1 caused by autogen aborts because of + absence of guile package +* Wed May 2 2012 mchang@suse.com +- grub2-automake-1-11-2.patch : fix grub2 build error on newer + autotools (automake >= 1.11.2) +- call ./autogen.sh +* Thu Apr 19 2012 mchang@suse.com +- grub2-probe-disk-mountby.patch : fix grub2-probe fails on + probing mount-by devices under /dev/disk/by-(id|uuid|path). + (bnc#757746) +* Thu Mar 29 2012 mchang@suse.com +- Add Requires to os-prober as script depends on it for probing + foreign os (bnc#753229) +* Wed Mar 21 2012 mchang@suse.com +- Mark %%config(noreplace) to /etc/default/grub (bnc#753246) +* Fri Mar 16 2012 aj@suse.de +- Fix build with gcc 4.7 (needs -fno-strict-aliasing for zfs code). +* Tue Mar 13 2012 mchang@suse.com +- Fix error in installation to extended partition (bnc#750897) + add grub2-iterate-and-hook-for-extended-partition.patch + add grub2-install-opt-skip-fs-probe.patch +* Mon Mar 12 2012 tittiatcoke@gmail.com +- Added BuildRequires for gnu-unifont in order to create the + necessary fonts for a graphical boot menu. +* Mon Feb 20 2012 andrea.turrini@gmail.com +- fixed typos in grub2.spec +* Mon Jan 2 2012 mchang@suse.com +- platforms without efi should not specify exclusion of it +* Thu Dec 29 2011 mchang@suse.com +- set --target=%%{_target_plaform) explicitly to %%configure in case + it wouldn't do that for us implicitly +- when making x86_64-efi image not use i386 target build and keep + use of x86_64. otherwise it would have error "invalid ELF header" +* Fri Dec 2 2011 coolo@suse.com +- add automake as buildrequire to avoid implicit dependency +* Mon Nov 28 2011 jslaby@suse.de +- remove doubly packaged files +- remove INSTALL from docs +- handle duplicate bindir files +* Mon Oct 31 2011 meissner@suse.de +- make efi exclusion more complete +* Thu Oct 27 2011 aj@suse.de +- efibootmgr only exists on x86-64 and ia64. +* Tue Oct 25 2011 aj@suse.de +- Add requires from efi subpackage to main package (bnc#72596) +* Mon Oct 24 2011 jslaby@suse.de +- update it and pl translations +- cleanup spec file + * don't package efi files to non-efi package +* Thu Aug 25 2011 aj@suse.de +- Fix directory ownership. +* Tue Aug 23 2011 aj@suse.de +- Build an efi subpackage [bnc#713595]. +* Tue Aug 2 2011 dvaleev@novell.com +- enable ppc build +- patch unused-but-set-variable +* Tue Jul 12 2011 aj@suse.de +- Create submenu for all besides primary Linux kernels. +- Only run preun section during package install but not during + upgrade. +* Tue Jul 12 2011 aj@suse.de +- Update README.openSUSE +* Tue May 31 2011 jslaby@suse.de +- update translations +- update to 1.99 final + * See NEWS file for changes +* Sat May 7 2011 jslaby@suse.de +- fix build with gcc 4.6 +- build in parallel (fixed finally in 1.99) +- add translations from translations project +- update to 1.99-rc2 + * See NEWS file for changes +* Wed Oct 27 2010 jslaby@suse.de +- fix vanishing of /boot/grub2/* if /boot/grub/device.map + doesn't exist +* Mon Oct 25 2010 jslaby@suse.de +- add missing " in the default file; add "fi" to grub2-linux.patch +* Mon Oct 11 2010 jslaby@suse.de +- repack gz to bz2 (0.5M saving) +* Sat Oct 9 2010 aj@suse.de +- Do not output vmlinux if vmlinuz of same version exists. +- Update default grub file. +* Sat Oct 9 2010 aj@suse.de +- Add patch grub-1.98-follow-dev-mapper-symlinks.patch from Fedora + for grub2-probe to detect lvm devices correctly +* Sat Sep 11 2010 jslaby@suse.de +- add gettext "requires" +* Sun Mar 14 2010 aj@suse.de +- Fix build on x86-64. +* Fri Mar 12 2010 aj@suse.de +- Don't build parallel. +- Update to grub 1.98 including: + * Multiboot on EFI support. + * Saved default menu entry support, with new utilities `grub-reboot' and + `grub-set-default'. + * Encrypted password support, with a new utility `grub-mkpasswd-pbkdf2'. + * `grub-mkfloppy' removed; use `grub-mkrescue' to create floppy images. +* Fri Feb 12 2010 aj@suse.de +- Update to grub 1.97.2: + * Fix a few 4 GiB limits. + * Fix license problems with a few BSD headers. + * Lots of misc bugfixes. +* Wed Dec 9 2009 aj@suse.de +- Fix requires. +* Wed Dec 9 2009 aj@suse.de +- Mark /etc/default/grub as config file. +* Wed Dec 9 2009 aj@suse.de +- Mark root partition rw +* Wed Dec 9 2009 aj@suse.de +- New package grub2. diff --git a/grub2.rpmlintrc b/grub2.rpmlintrc new file mode 100644 index 0000000..b0097e0 --- /dev/null +++ b/grub2.rpmlintrc @@ -0,0 +1,14 @@ +addFilter("zero-length /boot/grub2/grub.cfg") +addFilter("non-etc-or-var-file-marked-as-conffile /boot/grub2/grub.cfg") +addFilter("non-conffile-in-etc /etc/bash_completion.d/grub") +addFilter("non-conffile-in-etc /etc/grub.d/README") +addFilter("statically-linked-binary .*/grub2/*/kernel.img") +# We need to supply unstripped files for grub +addFilter("unstripped-binary-or-object .*/grub2/*/.*.mod") +# TODO: s390 Experts: is this sensible?! +addFilter("s390x: W: executable-stack") +# We need to provide compatibility sym-links in noarch package +addFilter("suse-filelist-forbidden-noarch") +addFilter("filelist-forbidden-noarch") +# +addFilter('arch-independent-package-contains-binary-or-object') diff --git a/grub2.spec b/grub2.spec new file mode 100644 index 0000000..5e50d1c --- /dev/null +++ b/grub2.spec @@ -0,0 +1,1523 @@ +# +# spec file for package grub2 +# +# Copyright (c) 2022-2023 ZhuningOS +# +# needssslcertforbuild + + +%define _binaries_in_noarch_package_terminate_build 0 + +Name: grub2 +%ifarch x86_64 ppc64 +BuildRequires: gcc-32bit +BuildRequires: glibc-32bit +BuildRequires: glibc-devel-32bit glibc-32bit +%else +BuildRequires: gcc +BuildRequires: glibc-devel +%endif +BuildRequires: automake +BuildRequires: bison +BuildRequires: device-mapper-devel +BuildRequires: fdupes +BuildRequires: flex +BuildRequires: freetype2-devel +BuildRequires: fuse-devel +%if 0%{?suse_version} >= 1140 +BuildRequires: dejavu-fonts +BuildRequires: gnu-unifont +%endif +BuildRequires: help2man +BuildRequires: xz +%if 0%{?suse_version} >= 1210 +BuildRequires: makeinfo +%else +BuildRequires: texinfo +%endif +%if %{defined pythons} +BuildRequires: %{pythons} +%else +BuildRequires: python +%endif +BuildRequires: xz-devel +%ifarch x86_64 aarch64 ppc ppc64 ppc64le +BuildRequires: openssl >= 0.9.8 +BuildRequires: pesign-obs-integration +%endif +%if 0%{?suse_version} >= 1210 +# Package systemd services files grub2-once.service +BuildRequires: systemd-rpm-macros +%define has_systemd 1 +%endif +%if 0%{?suse_version} > 1320 +BuildRequires: update-bootloader-rpm-macros +%endif + +# Modules code is dynamically loaded and collected from a _fixed_ path. +%define _libdir %{_exec_prefix}/lib + +# Build grub2-emu everywhere (it may be "required" by 'grub2-once') +%define emu 1 + +%ifarch ppc ppc64 ppc64le +%define grubcpu powerpc +%define platform ieee1275 +%define brp_pesign_reservation 65536 +# emu does not build here yet... :-( +%define emu 0 +%endif + +%ifarch %{ix86} x86_64 +%define grubcpu i386 +%define platform pc +%endif + +%ifarch s390x +%define grubcpu s390x +%define platform emu +%endif + +%ifarch %{arm} +%define grubcpu arm +%define platform uboot +%endif + +%ifarch aarch64 +%define grubcpu arm64 +%define platform efi +%define only_efi 1 +%endif + +%ifarch riscv64 +%define grubcpu riscv64 +%define platform efi +%define only_efi 1 +%endif + +%define grubarch %{grubcpu}-%{platform} + +# build efi bootloader on some platforms only: +%if ! 0%{?efi:1} +%global efi %{ix86} x86_64 ia64 aarch64 %{arm} riscv64 +%endif + +%ifarch %{efi} +%ifarch %{ix86} +%define grubefiarch i386-efi +%else +%ifarch aarch64 +%define grubefiarch arm64-efi +%else +%ifarch %{arm} +%define grubefiarch arm-efi +%else +%define grubefiarch %{_target_cpu}-efi +%endif +%endif +%endif +%endif + +%ifarch %{ix86} +%define grubxenarch i386-xen +%endif + +%ifarch x86_64 +%define grubxenarch x86_64-xen +%endif + +%if "%{platform}" == "emu" +# force %%{emu} to 1, e.g. for s390 +%define emu 1 +%endif + +%if 0%{?suse_version} == 1110 +%define only_efi %{nil} +%define only_x86_64 %{nil} +%endif + +Version: 2.06 +Release: 150500.29.8.1 +Summary: Bootloader with support for Linux, Multiboot and more +License: GPL-3.0-or-later +Group: System/Boot +URL: http://www.gnu.org/software/grub/ +Source0: https://ftp.gnu.org/gnu/grub/grub-%{version}.tar.xz +Source1: 90_persistent +Source2: grub.default +Source4: grub2.rpmlintrc +Source6: grub2-once +Source7: 20_memtest86+ +Source8: README.ibm3215 +Source10: openSUSE-UEFI-CA-Certificate.crt +Source11: SLES-UEFI-CA-Certificate.crt +Source12: grub2-snapper-plugin.sh +Source14: 80_suse_btrfs_snapshot +Source15: grub2-once.service +Source16: grub2-xen-pv-firmware.cfg +# required hook for systemd-sleep (bsc#941758) +Source17: grub2-systemd-sleep.sh +Source18: grub2-check-default.sh +Source19: grub2-instdev-fixup.pl +Source1000: PATCH_POLICY +Patch1: rename-grub-info-file-to-grub2.patch +Patch2: grub2-linux.patch +Patch3: use-grub2-as-a-package-name.patch +Patch4: info-dir-entry.patch +Patch5: grub2-simplefb.patch +Patch6: grub2-iterate-and-hook-for-extended-partition.patch +Patch8: grub2-ppc-terminfo.patch +Patch9: grub2-GRUB_CMDLINE_LINUX_RECOVERY-for-recovery-mode.patch +Patch10: grub2-fix-error-terminal-gfxterm-isn-t-found.patch +Patch12: grub2-fix-menu-in-xen-host-server.patch +Patch15: not-display-menu-when-boot-once.patch +Patch17: grub2-pass-corret-root-for-nfsroot.patch +Patch19: grub2-efi-HP-workaround.patch +Patch21: grub2-secureboot-add-linuxefi.patch +Patch23: grub2-secureboot-no-insmod-on-sb.patch +Patch25: grub2-secureboot-chainloader.patch +Patch27: grub2-linuxefi-fix-boot-params.patch +Patch35: grub2-linguas.sh-no-rsync.patch +Patch37: grub2-use-Unifont-for-starfield-theme-terminal.patch +Patch38: grub2-s390x-01-Changes-made-and-files-added-in-order-to-allow-s390x.patch +Patch39: grub2-s390x-02-kexec-module-added-to-emu.patch +Patch40: grub2-s390x-03-output-7-bit-ascii.patch +Patch41: grub2-s390x-04-grub2-install.patch +Patch42: grub2-s390x-05-grub2-mkconfig.patch +Patch43: grub2-use-rpmsort-for-version-sorting.patch +Patch53: grub2-getroot-treat-mdadm-ddf-as-simple-device.patch +Patch56: grub2-setup-try-fs-embed-if-mbr-gap-too-small.patch +Patch58: grub2-xen-linux16.patch +Patch59: grub2-efi-disable-video-cirrus-and-bochus.patch +Patch61: grub2-vbe-blacklist-preferred-1440x900x32.patch +Patch64: grub2-grubenv-in-btrfs-header.patch +Patch65: grub2-mkconfig-aarch64.patch +Patch70: grub2-default-distributor.patch +Patch71: grub2-menu-unrestricted.patch +Patch72: grub2-mkconfig-arm.patch +Patch75: grub2-s390x-06-loadparm.patch +Patch76: grub2-s390x-07-add-image-param-for-zipl-setup.patch +Patch77: grub2-s390x-08-workaround-part-to-disk.patch +Patch78: grub2-commands-introduce-read_file-subcommand.patch +Patch79: grub2-efi-chainload-harder.patch +Patch80: grub2-emu-4-all.patch +Patch81: grub2-lvm-allocate-metadata-buffer-from-raw-contents.patch +Patch82: grub2-diskfilter-support-pv-without-metadatacopies.patch +Patch84: grub2-s390x-09-improve-zipl-setup.patch +Patch85: grub2-getroot-scan-disk-pv.patch +Patch92: grub2-util-30_os-prober-multiple-initrd.patch +Patch93: grub2-getroot-support-nvdimm.patch +Patch94: grub2-install-fix-not-a-directory-error.patch +Patch96: grub-install-force-journal-draining-to-ensure-data-i.patch +Patch97: grub2-s390x-skip-zfcpdump-image.patch +# Btrfs snapshot booting related patches +Patch101: grub2-btrfs-01-add-ability-to-boot-from-subvolumes.patch +Patch102: grub2-btrfs-02-export-subvolume-envvars.patch +Patch103: grub2-btrfs-03-follow_default.patch +Patch104: grub2-btrfs-04-grub2-install.patch +Patch105: grub2-btrfs-05-grub2-mkconfig.patch +Patch106: grub2-btrfs-06-subvol-mount.patch +Patch107: grub2-btrfs-07-subvol-fallback.patch +Patch108: grub2-btrfs-08-workaround-snapshot-menu-default-entry.patch +Patch109: grub2-btrfs-09-get-default-subvolume.patch +Patch110: grub2-btrfs-10-config-directory.patch +# Support EFI xen loader +Patch120: grub2-efi-xen-chainload.patch +Patch121: grub2-efi-chainloader-root.patch +Patch122: grub2-efi-xen-cmdline.patch +Patch123: grub2-efi-xen-cfg-unquote.patch +Patch124: grub2-efi-xen-removable.patch +# Hidden menu entry and hotkey "t" for text console +Patch140: grub2-Add-hidden-menu-entries.patch +Patch141: grub2-SUSE-Add-the-t-hotkey.patch +# Linux root device related patches +Patch163: grub2-zipl-setup-fix-btrfs-multipledev.patch +Patch164: grub2-suse-remove-linux-root-param.patch +# PPC64 LE support +Patch205: grub2-ppc64le-disable-video.patch +Patch207: grub2-ppc64le-memory-map.patch +# PPC +Patch211: grub2-ppc64-cas-reboot-support.patch +Patch212: grub2-install-remove-useless-check-PReP-partition-is-empty.patch +Patch213: grub2-Fix-incorrect-netmask-on-ppc64.patch +Patch215: grub2-ppc64-cas-new-scope.patch +Patch218: grub2-ppc64-cas-fix-double-free.patch +Patch233: 0001-osdep-Introduce-include-grub-osdep-major.h-and-use-i.patch +Patch234: 0002-osdep-linux-hostdisk-Use-stat-instead-of-udevadm-for.patch +Patch236: grub2-efi_gop-avoid-low-resolution.patch +# Support HTTP Boot IPv4 and IPv6 (fate#320129) +Patch281: 0002-net-read-bracketed-ipv6-addrs-and-port-numbers.patch +Patch282: 0003-bootp-New-net_bootp6-command.patch +Patch283: 0004-efinet-UEFI-IPv6-PXE-support.patch +Patch284: 0005-grub.texi-Add-net_bootp6-doument.patch +Patch285: 0006-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch +Patch286: 0007-efinet-Setting-network-from-UEFI-device-path.patch +Patch287: 0008-efinet-Setting-DNS-server-from-UEFI-protocol.patch +# TPM Support (FATE#315831) +Patch411: 0012-tpm-Build-tpm-as-module.patch +# UEFI HTTP and related network protocol support (FATE#320130) +Patch420: 0001-add-support-for-UEFI-network-protocols.patch +Patch421: 0002-AUDIT-0-http-boot-tracker-bug.patch +# check if default entry need to be corrected for updated distributor version +# and/or use fallback entry if default kernel entry removed (bsc#1065349) +Patch430: grub2-mkconfig-default-entry-correction.patch +Patch431: grub2-s390x-10-keep-network-at-kexec.patch +Patch432: grub2-s390x-11-secureboot.patch +# Support for UEFI Secure Boot on AArch64 (FATE#326541) +Patch450: grub2-secureboot-install-signed-grub.patch +Patch501: grub2-btrfs-help-on-snapper-rollback.patch +# Improved hiDPI device support (FATE#326680) +Patch510: grub2-video-limit-the-resolution-for-fixed-bimap-font.patch +# Support long menuentries (FATE#325760) +Patch511: grub2-gfxmenu-support-scrolling-menu-entry-s-text.patch +Patch714: 0001-kern-mm.c-Make-grub_calloc-inline.patch +Patch716: 0002-cmdline-Provide-cmdline-functions-as-module.patch +# bsc#1172745 L3: SLES 12 SP4 - Slow boot of system after updated kernel - +# takes 45 minutes after grub to start loading kernel +Patch717: 0001-ieee1275-powerpc-implements-fibre-channel-discovery-.patch +Patch718: 0002-ieee1275-powerpc-enables-device-mapper-discovery.patch +Patch719: 0001-Unify-the-check-to-enable-btrfs-relative-path.patch +Patch721: 0001-efi-linux-provide-linux-command.patch +# Secure Boot support in GRUB on aarch64 (jsc#SLE-15864) +Patch730: 0001-Add-support-for-Linux-EFI-stub-loading-on-aarch64.patch +Patch731: 0002-arm64-make-sure-fdt-has-address-cells-and-size-cells.patch +Patch732: 0003-Make-grub_error-more-verbose.patch +Patch733: 0004-arm-arm64-loader-Better-memory-allocation-and-error-.patch +Patch735: 0006-efi-Set-image-base-address-before-jumping-to-the-PE-.patch +Patch739: 0001-Fix-build-error-in-binutils-2.36.patch +Patch740: 0001-emu-fix-executable-stack-marking.patch +Patch784: 0044-squash-kern-Add-lockdown-support.patch +Patch786: 0046-squash-verifiers-Move-verifiers-API-to-kernel-image.patch +Patch788: 0001-ieee1275-Avoiding-many-unecessary-open-close.patch +Patch789: 0001-Workaround-volatile-efi-boot-variable.patch +Patch790: 0001-30_uefi-firmware-fix-printf-format-with-null-byte.patch +Patch791: 0001-i386-pc-build-btrfs-zstd-support-into-separate-modul.patch +Patch792: 0001-templates-Follow-the-path-of-usr-merged-kernel-confi.patch +Patch793: 0001-tpm-Pass-unknown-error-as-non-fatal-but-debug-print-.patch +Patch794: 0001-Filter-out-POSIX-locale-for-translation.patch +Patch795: 0001-ieee1275-implement-FCP-methods-for-WWPN-and-LUNs.patch +Patch796: 0001-disk-diskfilter-Use-nodes-in-logical-volume-s-segmen.patch +Patch797: 0001-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch +Patch798: 0001-arm64-Fix-EFI-loader-kernel-image-allocation.patch +Patch799: 0002-Arm-check-for-the-PE-magic-for-the-compiled-arch.patch +Patch800: 0001-fs-btrfs-Make-extent-item-iteration-to-handle-gaps.patch +Patch801: 0001-Factor-out-grub_efi_linux_boot.patch +Patch802: 0002-Fix-race-in-EFI-validation.patch +Patch803: 0003-Handle-multi-arch-64-on-32-boot-in-linuxefi-loader.patch +Patch804: 0004-Try-to-pick-better-locations-for-kernel-and-initrd.patch +Patch805: 0005-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch +Patch806: 0006-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch +Patch807: 0007-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch +Patch808: 0008-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch +Patch809: 0009-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch +Patch810: 0010-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch +Patch811: 0011-Also-define-GRUB_EFI_MAX_ALLOCATION_ADDRESS-for-RISC.patch +Patch812: 0001-grub-mkconfig-restore-umask-for-grub.cfg.patch +Patch813: 0001-ieee1275-Drop-HEAP_MAX_ADDR-and-HEAP_MIN_SIZE-consta.patch +Patch814: 0002-ieee1275-claim-more-memory.patch +Patch815: 0003-ieee1275-request-memory-with-ibm-client-architecture.patch +Patch816: 0004-Add-suport-for-signing-grub-with-an-appended-signatu.patch +Patch817: 0005-docs-grub-Document-signing-grub-under-UEFI.patch +Patch818: 0006-docs-grub-Document-signing-grub-with-an-appended-sig.patch +Patch819: 0007-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch +Patch820: 0008-pgp-factor-out-rsa_pad.patch +Patch821: 0009-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch +Patch822: 0010-posix_wrap-tweaks-in-preparation-for-libtasn1.patch +Patch823: 0011-libtasn1-import-libtasn1-4.18.0.patch +Patch824: 0012-libtasn1-disable-code-not-needed-in-grub.patch +Patch825: 0013-libtasn1-changes-for-grub-compatibility.patch +Patch826: 0014-libtasn1-compile-into-asn1-module.patch +Patch827: 0015-test_asn1-test-module-for-libtasn1.patch +Patch828: 0016-grub-install-support-embedding-x509-certificates.patch +Patch829: 0017-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch +Patch830: 0018-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch +Patch831: 0019-appended-signatures-support-verifying-appended-signa.patch +Patch832: 0020-appended-signatures-verification-tests.patch +Patch833: 0021-appended-signatures-documentation.patch +Patch834: 0022-ieee1275-enter-lockdown-based-on-ibm-secure-boot.patch +Patch835: 0023-x509-allow-Digitial-Signature-plus-other-Key-Usages.patch +Patch836: 0001-grub-install-Add-SUSE-signed-image-support-for-power.patch +Patch837: 0001-Add-grub_envblk_buf-helper-function.patch +Patch838: 0002-Add-grub_disk_write_tail-helper-function.patch +Patch839: 0003-grub-install-support-prep-environment-block.patch +Patch840: 0004-Introduce-prep_load_env-command.patch +Patch841: 0005-export-environment-at-start-up.patch +Patch842: 0001-grub-install-bailout-root-device-probing.patch +Patch843: 0001-RISC-V-Adjust-march-flags-for-binutils-2.38.patch +Patch844: 0001-install-fix-software-raid1-on-esp.patch +Patch845: 0001-powerpc-do-CAS-in-a-more-compatible-way.patch +Patch846: 0001-ofdisk-improve-boot-time-by-lookup-boot-disk-first.patch +Patch847: 0001-video-Remove-trailing-whitespaces.patch +Patch848: 0002-loader-efi-chainloader-Simplify-the-loader-state.patch +Patch849: 0003-commands-boot-Add-API-to-pass-context-to-loader.patch +Patch850: 0004-loader-efi-chainloader-Use-grub_loader_set_ex.patch +Patch851: 0005-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch +Patch852: 0006-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch +Patch853: 0007-video-readers-png-Abort-sooner-if-a-read-operation-f.patch +Patch854: 0008-video-readers-png-Refuse-to-handle-multiple-image-he.patch +Patch855: 0009-video-readers-png-Drop-greyscale-support-to-fix-heap.patch +Patch856: 0010-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch +Patch857: 0011-video-readers-png-Sanity-check-some-huffman-codes.patch +Patch858: 0012-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch +Patch859: 0013-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch +Patch860: 0014-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch +Patch861: 0015-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch +Patch862: 0016-normal-charset-Fix-array-out-of-bounds-formatting-un.patch +Patch863: 0017-net-ip-Do-IP-fragment-maths-safely.patch +Patch864: 0018-net-netbuff-Block-overly-large-netbuff-allocs.patch +Patch865: 0019-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch +Patch866: 0020-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch +Patch867: 0021-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch +Patch868: 0022-net-tftp-Avoid-a-trivial-UAF.patch +Patch869: 0023-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch +Patch870: 0024-net-http-Fix-OOB-write-for-split-http-headers.patch +Patch871: 0025-net-http-Error-out-on-headers-with-LF-without-CR.patch +Patch872: 0026-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch +Patch873: 0027-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch +Patch874: 0028-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch +Patch875: 0029-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch +Patch876: 0030-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch +Patch877: 0031-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch +Patch878: 0032-Use-grub_loader_set_ex-for-secureboot-chainloader.patch +Patch879: 0001-grub-install-set-point-of-no-return-for-powerpc-ieee1275.patch +Patch885: 0001-luks2-Add-debug-message-to-align-with-luks-and-geli-.patch +Patch886: 0002-cryptodisk-Refactor-to-discard-have_it-global.patch +Patch887: 0003-cryptodisk-Return-failure-in-cryptomount-when-no-cry.patch +Patch888: 0004-cryptodisk-Improve-error-messaging-in-cryptomount-in.patch +Patch889: 0005-cryptodisk-Improve-cryptomount-u-error-message.patch +Patch890: 0006-cryptodisk-Add-infrastructure-to-pass-data-from-cryp.patch +Patch891: 0007-cryptodisk-Refactor-password-input-out-of-crypto-dev.patch +Patch892: 0008-cryptodisk-Move-global-variables-into-grub_cryptomou.patch +Patch893: 0009-cryptodisk-Improve-handling-of-partition-name-in-cry.patch +Patch894: 0010-protectors-Add-key-protectors-framework.patch +Patch895: 0011-tpm2-Add-TPM-Software-Stack-TSS.patch +Patch896: 0012-protectors-Add-TPM2-Key-Protector.patch +Patch897: 0013-cryptodisk-Support-key-protectors.patch +Patch898: 0014-util-grub-protect-Add-new-tool.patch +Patch899: fix-tpm2-build.patch +Patch900: 0001-crytodisk-fix-cryptodisk-module-looking-up.patch +# (PED-996) NVMeoFC support on Grub (grub2) +Patch901: 0001-ieee1275-add-support-for-NVMeoFC.patch +Patch902: 0002-ieee1275-ofpath-enable-NVMeoF-logical-device-transla.patch +Patch903: 0003-ieee1275-change-the-logic-of-ieee1275_get_devargs.patch +Patch904: 0004-ofpath-controller-name-update.patch +# (PED-1265) TDX: Enhance grub2 measurement to TD RTMR +Patch905: 0001-commands-efi-tpm-Refine-the-status-of-log-event.patch +Patch906: 0002-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch +Patch907: 0003-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch +# (PED-1990) GRUB2: Measure the kernel on POWER10 and extend TPM PCRs +Patch908: 0001-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch +Patch909: 0002-ieee1275-implement-vec5-for-cas-negotiation.patch +Patch910: 0001-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch +Patch911: 0002-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch +Patch912: 0003-font-Fix-several-integer-overflows-in-grub_font_cons.patch +Patch913: 0004-font-Remove-grub_font_dup_glyph.patch +Patch914: 0005-font-Fix-integer-overflow-in-ensure_comb_space.patch +Patch915: 0006-font-Fix-integer-overflow-in-BMP-index.patch +Patch916: 0007-font-Fix-integer-underflow-in-binary-search-of-char-.patch +Patch917: 0008-fbutil-Fix-integer-overflow.patch +Patch918: 0009-font-Fix-an-integer-underflow-in-blit_comb.patch +Patch919: 0010-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch +Patch920: 0011-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch +Patch921: 0012-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch +Patch922: 0001-devmapper-getroot-Have-devmapper-recognize-LUKS2.patch +Patch923: 0002-devmapper-getroot-Set-up-cheated-LUKS2-cryptodisk-mo.patch +Patch924: 0003-disk-cryptodisk-When-cheatmounting-use-the-sector-in.patch +Patch925: 0001-ieee1275-Increase-initially-allocated-heap-from-1-4-.patch +Patch926: 0001-grub2-Set-multiple-device-path-for-a-nvmf-boot-devic.patch +Patch927: 0001-grub-core-modify-sector-by-sysfs-as-disk-sector.patch +Patch928: 0001-grub2-Can-t-setup-a-default-boot-device-correctly-on.patch +Patch929: 0001-ieee1275-Further-increase-initially-allocated-heap-f.patch +Patch930: 0002-tpm-Disable-tpm-verifier-if-tpm-is-not-present.patch +Patch931: 0001-ieee1275-ofdisk-retry-on-open-and-read-failure.patch +Patch932: 0001-Fix-infinite-boot-loop-on-headless-system-in-qemu.patch +Patch933: 0001-openfw-Ensure-get_devargs-and-get_devname-functions-.patch +Patch934: 0002-prep_loadenv-Fix-regex-for-Open-Firmware-device-spec.patch +Patch935: 0001-kern-ieee1275-init-Convert-plain-numbers-to-constant.patch +Patch936: 0002-kern-ieee1275-init-Extended-support-in-Vec5.patch +Patch937: 0001-fs-ntfs-Fix-an-OOB-write-when-parsing-the-ATTRIBUTE_.patch +Patch938: 0002-fs-ntfs-Fix-an-OOB-read-when-reading-data-from-the-r.patch +Patch939: 0003-fs-ntfs-Fix-an-OOB-read-when-parsing-directory-entri.patch +Patch940: 0004-fs-ntfs-Fix-an-OOB-read-when-parsing-bitmaps-for-ind.patch +Patch941: 0005-fs-ntfs-Fix-an-OOB-read-when-parsing-a-volume-label.patch +Patch942: 0006-fs-ntfs-Make-code-more-readable.patch + +Requires: gettext-runtime +%if 0%{?suse_version} >= 1140 +%ifnarch s390x +Recommends: os-prober +%endif +# xorriso not available using grub2-mkrescue (bnc#812681) +# downgrade to suggest as minimal system can't afford pulling in tcl/tk and half of the x11 stack (bsc#1102515) +Suggests: libburnia-tools +Suggests: mtools +%endif +%if ! 0%{?only_efi:1} +Requires: grub2-%{grubarch} = %{version}-%{release} +%endif +%ifarch s390x +# required utilities by grub2-s390x-04-grub2-install.patch +# use 'showconsole' to determine console device. (bnc#876743) +Requires: kexec-tools +Requires: (/sbin/showconsole or /usr/sbin/showconsole) +# for /sbin/zipl used by grub2-zipl-setup +Requires: s390-tools +%endif +%ifarch ppc64 ppc64le +Requires: powerpc-utils +%endif + +%if 0%{?only_x86_64:1} +ExclusiveArch: x86_64 +%else +ExclusiveArch: %{ix86} x86_64 ppc ppc64 ppc64le s390x aarch64 %{arm} riscv64 +%endif + +%description +This is the second version of the GRUB (Grand Unified Bootloader), a +highly configurable and customizable bootloader with modular +architecture. It support rich scale of kernel formats, file systems, +computer architectures and hardware devices. + +This package includes user space utlities to manage GRUB on your system. + +%package branding-upstream + +Summary: Upstream branding for GRUB2's graphical console +Group: System/Fhs +Requires: %{name} = %{version} + +%description branding-upstream +Upstream branding for GRUB2's graphical console + +%if ! 0%{?only_efi:1} +%package %{grubarch} + +Summary: Bootloader with support for Linux, Multiboot and more +Group: System/Boot +%if "%{platform}" != "emu" +BuildArch: noarch +%endif +Requires: %{name} = %{version} +Requires(post): %{name} = %{version} +%if 0%{?update_bootloader_requires:1} +%update_bootloader_requires +%else +Requires: perl-Bootloader +Requires(post): perl-Bootloader +%endif + +%description %{grubarch} +The GRand Unified Bootloader (GRUB) is a highly configurable and customizable +bootloader with modular architecture. It supports rich variety of kernel formats, +file systems, computer architectures and hardware devices. This subpackage +provides support for %{platform} systems. + +%package %{grubarch}-extras +Summary: Unsupported modules for %{grubarch} +Group: System/Boot +BuildArch: noarch +Requires: %{name}-%{grubarch} = %{version} +Provides: %{name}-%{grubarch}:%{_datadir}/%{name}/%{grubarch}/zfs.mod +Provides: %{name}-%{grubarch}:%{_datadir}/%{name}/%{grubarch}/zfscrypt.mod +Provides: %{name}-%{grubarch}:%{_datadir}/%{name}/%{grubarch}/zfsinfo.mod + +%description %{grubarch}-extras +Unsupported modules for %{name}-%{grubarch} + +%package %{grubarch}-debug +Summary: Debug symbols for %{grubarch} +Group: System/Boot +%if "%{platform}" != "emu" +BuildArch: noarch +%endif +Requires: %{name}-%{grubarch} = %{version} + +%description %{grubarch}-debug +Debug information for %{name}-%{grubarch} + +Information on how to debug grub can be found online: +https://www.cnblogs.com/coryxie/archive/2013/03/12/2956807.html + +%endif + +%ifarch %{efi} + +%package %{grubefiarch} + +Summary: Bootloader with support for Linux, Multiboot and more +Group: System/Boot +BuildArch: noarch +# Require efibootmgr +# Without it grub-install is broken so break the package as well if unavailable +Requires: efibootmgr +Requires(post): efibootmgr +Requires: %{name} = %{version} +Requires(post): %{name} = %{version} +%if 0%{?update_bootloader_requires:1} +%update_bootloader_requires +%else +Requires: perl-Bootloader >= 0.706 +Requires(post): perl-Bootloader >= 0.706 +%endif +Provides: %{name}-efi = %{version}-%{release} +Obsoletes: %{name}-efi < %{version}-%{release} + +%description %{grubefiarch} +The GRand Unified Bootloader (GRUB) is a highly configurable and customizable +bootloader with modular architecture. It supports rich variety of kernel formats, +file systems, computer architectures and hardware devices. This subpackage +provides support for EFI systems. + +%package %{grubefiarch}-extras + +Summary: Unsupported modules for %{grubefiarch} +Group: System/Boot +BuildArch: noarch +Requires: %{name}-%{grubefiarch} = %{version} +Provides: %{name}-%{grubefiarch}:%{_datadir}/%{name}/%{grubefiarch}/zfs.mod +Provides: %{name}-%{grubefiarch}:%{_datadir}/%{name}/%{grubefiarch}/zfscrypt.mod +Provides: %{name}-%{grubefiarch}:%{_datadir}/%{name}/%{grubefiarch}/zfsinfo.mod + +%description %{grubefiarch}-extras +Unsupported modules for %{name}-%{grubefiarch} + +%package %{grubefiarch}-debug +Summary: Debug symbols for %{grubefiarch} +Group: System/Boot +%if "%{platform}" != "emu" +BuildArch: noarch +%endif +Requires: %{name}-%{grubefiarch} = %{version} + +%description %{grubefiarch}-debug +Debug symbols for %{name}-%{grubefiarch} + +Information on how to debug grub can be found online: +https://www.cnblogs.com/coryxie/archive/2013/03/12/2956807.html + +%endif + +%ifarch %{ix86} x86_64 + +%package %{grubxenarch} + +Summary: Bootloader with support for Linux, Multiboot and more +Group: System/Boot +Provides: %{name}-xen = %{version}-%{release} +Obsoletes: %{name}-xen < %{version}-%{release} +BuildArch: noarch + +%description %{grubxenarch} +The GRand Unified Bootloader (GRUB) is a highly configurable and customizable +bootloader with modular architecture. It supports rich variety of kernel formats, +file systems, computer architectures and hardware devices. This subpackage +provides support for XEN systems. + +%package %{grubxenarch}-extras +Summary: Unsupported modules for %{grubxenarch} +Group: System/Boot +BuildArch: noarch +Requires: %{name}-%{grubxenarch} = %{version} +Provides: %{name}-%{grubxenarch}:%{_datadir}/%{name}/%{grubxenarch}/zfs.mod +Provides: %{name}-%{grubxenarch}:%{_datadir}/%{name}/%{grubxenarch}/zfscrypt.mod +Provides: %{name}-%{grubxenarch}:%{_datadir}/%{name}/%{grubxenarch}/zfsinfo.mod + +%description %{grubxenarch}-extras +Unsupported modules for %{name}-%{grubxenarch} + +%endif + +%package snapper-plugin + +Summary: Grub2's snapper plugin +Group: System/Fhs +Requires: %{name} = %{version} +Requires: libxml2-tools +Supplements: packageand(snapper:grub2) +BuildArch: noarch + +%description snapper-plugin +Grub2's snapper plugin for advanced btrfs snapshot boot menu management + +%if 0%{?has_systemd:1} +%package systemd-sleep-plugin + +Summary: Grub2's systemd-sleep plugin +Group: System/Fhs +Requires: grub2 +Requires: util-linux +Supplements: packageand(systemd:grub2) +BuildArch: noarch + +%description systemd-sleep-plugin +Grub2's systemd-sleep plugin for directly booting hibernated kernel image in +swap partition while in resuming +%endif + +%prep +# We create (if we build for efi) two copies of the sources in the Builddir +%autosetup -p1 -n grub-%{version} + +%build +# collect evidence to debug spurious build failure on SLE15 +ulimit -a +# patches above may update the timestamp of grub.texi +# and via build-aux/mdate-sh they end up in grub2.info, breaking build-compare +[ -z "$SOURCE_DATE_EPOCH" ] ||\ + [ `stat -c %Y docs/grub.texi` -lt $SOURCE_DATE_EPOCH ] ||\ + touch -d@$SOURCE_DATE_EPOCH docs/grub.texi + +# This simplifies patch handling without need to use git to create patch +# that renames file +mv docs/grub.texi docs/grub2.texi + +cp %{SOURCE8} . +mkdir build +%ifarch %{efi} +mkdir build-efi +%endif +%ifarch %{ix86} x86_64 +mkdir build-xen +%endif +%if %{emu} +mkdir build-emu +%endif + +export PYTHON=%{_bindir}/python3 +[ -x $PYTHON ] || unset PYTHON # try 'python', if 'python3' is unavailable +# autogen calls autoreconf -vi +./autogen.sh +# Not yet: +%define common_conf_options TARGET_LDFLAGS=-static --program-transform-name=s,grub,%{name}, +# This does NOT work on SLE11: +%define _configure ../configure + +# We don't want to let rpm override *FLAGS with default a.k.a bogus values. +CFLAGS="-fno-strict-aliasing -fno-inline-functions-called-once " +CXXFLAGS=" " +FFLAGS=" " +export CFLAGS CXXFLAGS FFLAGS + +%if %{emu} +cd build-emu +%define arch_specific --enable-device-mapper --disable-grub-mount +TLFLAGS="-fPIC" + +# -static is needed so that autoconf script is able to link +# test that looks for _start symbol on 64 bit platforms +../configure TARGET_LDFLAGS=$TLFLAGS \ + --prefix=%{_prefix} \ + --libdir=%{_datadir} \ + --sysconfdir=%{_sysconfdir} \ + --target=%{_target_platform} \ + --with-platform=emu \ + %{arch_specific} \ + --program-transform-name=s,grub,%{name}, +make %{?_smp_mflags} +cd .. +if [ "%{platform}" = "emu" ]; then + rmdir build + mv build-emu build +fi +%endif + +%ifarch %{ix86} x86_64 +cd build-xen +../configure \ + TARGET_LDFLAGS=-static \ + --prefix=%{_prefix} \ + --libdir=%{_datadir} \ + --sysconfdir=%{_sysconfdir} \ + --target=%{_target_platform} \ + --with-platform=xen \ + --program-transform-name=s,grub,%{name}, +make %{?_smp_mflags} + +./grub-mkstandalone --grub-mkimage=./grub-mkimage -o grub.xen -O %{grubxenarch} -d grub-core/ "/boot/grub/grub.cfg=%{SOURCE16}" + +cd .. +%endif + +FS_MODULES="btrfs ext2 xfs jfs reiserfs" +CD_MODULES="all_video boot cat configfile echo true \ + font gfxmenu gfxterm gzio halt iso9660 \ + jpeg minicmd normal part_apple part_msdos part_gpt \ + password password_pbkdf2 png reboot search search_fs_uuid \ + search_fs_file search_label sleep test video fat loadenv loopback" +PXE_MODULES="tftp http" +CRYPTO_MODULES="luks luks2 gcry_rijndael gcry_sha1 gcry_sha256 gcry_sha512" +%ifarch %{efi} +CD_MODULES="${CD_MODULES} chain efifwsetup efinet" +PXE_MODULES="${PXE_MODULES} efinet" +%else +CD_MODULES="${CD_MODULES} net" +PXE_MODULES="${PXE_MODULES} net" +%endif + +%ifarch x86_64 +CD_MODULES="${CD_MODULES} linuxefi" +%else +CD_MODULES="${CD_MODULES} linux" +%endif + +GRUB_MODULES="${CD_MODULES} ${FS_MODULES} ${PXE_MODULES} ${CRYPTO_MODULES} mdraid09 mdraid1x lvm serial" +%ifarch ppc ppc64 ppc64le +GRUB_MODULES="${GRUB_MODULES} appendedsig memdisk tar regexp prep_loadenv tpm" +%endif + +%ifarch %{efi} +cd build-efi +../configure \ + TARGET_LDFLAGS=-static \ + --prefix=%{_prefix} \ + --libdir=%{_datadir} \ + --sysconfdir=%{_sysconfdir} \ + --target=%{_target_platform} \ + --with-platform=efi \ + --program-transform-name=s,grub,%{name}, +make %{?_smp_mflags} + +# SBAT metadata +%if 0%{?is_opensuse} == 1 +distro_id="opensuse" +distro_name="The openSUSE Project" +%else +distro_id="sle" +distro_name="SUSE Linux Enterprise" +%endif +upstream_sbat=4 +distro_sbat=1 +echo "sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md" > sbat.csv +echo "grub,${upstream_sbat},Free Software Foundation,grub,%{version},https://www.gnu.org/software/grub/" >> sbat.csv +echo "grub.${distro_id},${distro_sbat},${distro_name},%{name},%{version},mailto:security@suse.de" >> sbat.csv + +./grub-mkimage -O %{grubefiarch} -o grub.efi --prefix= --sbat sbat.csv \ + -d grub-core ${GRUB_MODULES} +%ifarch x86_64 +./grub-mkimage -O %{grubefiarch} -o grub-tpm.efi --prefix= --sbat sbat.csv \ + -d grub-core ${GRUB_MODULES} tpm tpm2 +%endif + +%ifarch x86_64 aarch64 +if test -e %{_sourcedir}/_projectcert.crt ; then + prjsubject=$(openssl x509 -in %{_sourcedir}/_projectcert.crt -noout -subject_hash) + prjissuer=$(openssl x509 -in %{_sourcedir}/_projectcert.crt -noout -issuer_hash) + opensusesubject=$(openssl x509 -in %{SOURCE10} -noout -subject_hash) + slessubject=$(openssl x509 -in %{SOURCE11} -noout -subject_hash) + if test "$prjissuer" = "$opensusesubject" ; then + cert=%{SOURCE10} + fi + if test "$prjissuer" = "$slessubject" ; then + cert=%{SOURCE11} + fi + if test "$prjsubject" = "$prjissuer" ; then + cert=%{_sourcedir}/_projectcert.crt + fi +fi +if test -z "$cert" ; then + echo "cannot identify project, assuming openSUSE signing" + cert=%{SOURCE10} +fi + +openssl x509 -in $cert -outform DER -out grub.der +%endif + +cd .. +%endif + +%if ! 0%{?only_efi:1} +cd build + +# 64-bit x86-64 machines use 32-bit boot loader +# (We cannot just redefine _target_cpu, as we'd get i386.rpm packages then) +%ifarch x86_64 +%define _target_platform i386-%{_vendor}-%{_target_os}%{?_gnu} +%endif + +%if "%{platform}" != "emu" +%define arch_specific --enable-device-mapper +TLFLAGS="-static" + +# -static is needed so that autoconf script is able to link +# test that looks for _start symbol on 64 bit platforms +../configure TARGET_LDFLAGS="$TLFLAGS" \ + --prefix=%{_prefix} \ + --libdir=%{_datadir} \ + --sysconfdir=%{_sysconfdir} \ + --target=%{_target_platform} \ + --with-platform=%{platform} \ + %{arch_specific} \ + --program-transform-name=s,grub,%{name}, +make %{?_smp_mflags} + +if [ "%{platform}" = "ieee1275" ]; then + # So far neither OpenFirmware nor grub support CA chain, only certificate pinning + # Use project certificate always in the shipped informational file and + # for kernel verification + projectcert="%{_sourcedir}/_projectcert.crt" + openssl x509 -in "$projectcert" -outform DER -out grub.der + cat > %{platform}-config <<'EOF' +set root=memdisk +set prefix=($root)/ +echo "earlycfg: root=$root prefix=$prefix" +EOF + cat > ./grub.cfg <<'EOF' + +regexp --set 1:bdev --set 2:bpath '\((.*)\)(.*)' "$cmdpath" +regexp --set 1:bdev --set 2:bpart '(.*[^\])(,.*)' "$bdev" + +echo "bdev=$bdev" +echo "bpart=$bpart" +echo "bpath=$bpath" + +if [ -z "$ENV_FS_UUID" ]; then + echo "Reading vars from ($bdev)" + prep_load_env "($bdev)" +fi + +echo "ENV_HINT=$ENV_HINT" +echo "ENV_GRUB_DIR=$ENV_GRUB_DIR" +echo "ENV_FS_UUID=$ENV_FS_UUID" + +if [ "$btrfs_relative_path" = xy ]; then + btrfs_relative_path=1 +fi + +if [ "$bdev" -a "$bpart" -a "$bpath" ]; then + set hints="--hint $bdev$bpart" + set cfg_dir="$bpath" +elif [ "$bdev" -a "$bpart" ]; then + set hints="--hint $bdev$bpart" + set cfg_dir="/boot/grub2 /grub2" + set btrfs_relative_path=1 +elif [ "$bdev" ]; then + if [ "$ENV_HINT" ]; then + set hints="--hint $ENV_HINT" + else + set hints="--hint ${bdev}," + fi + if [ "$ENV_GRUB_DIR" ]; then + set cfg_dir="$ENV_GRUB_DIR" + else + set cfg_dir="/boot/grub2 /grub2" + set btrfs_relative_path=1 + fi +else + set hints="" + set cfg_dir="/boot/grub2 /grub2" + set btrfs_relative_path=1 +fi + +set prefix="" +set root="" +set cfg="grub.cfg" + +if [ "$ENV_CRYPTO_UUID" ]; then + cryptomount -u "$ENV_CRYPTO_UUID" +fi + +if [ "$ENV_FS_UUID" ]; then + echo "searching for $ENV_FS_UUID with $hints" + if search --fs-uuid --set=root "$ENV_FS_UUID" $hints; then + echo "$ENV_FS_UUID is on $root" + fi +fi + +for d in ${cfg_dir}; do + if [ -z "$root" ]; then + echo "searching for ${d}/${cfg}" + if search --file --set=root "${d}/${cfg}" $hints; then + echo "${d}/${cfg} is on $root" + prefix="($root)${d}" + fi + elif [ -f "${d}/${cfg}" ]; then + echo "${d}/${cfg} is on $root" + prefix="($root)${d}" + else + echo "${d}/${cfg} not found in $root" + fi + + if [ "$prefix" -a x"$btrfs_relative_path" = x1 ]; then + btrfs_relative_path=0 + if [ -f /@"${d}"/powerpc-ieee1275/command.lst ]; then + btrfs_relative_path=1 + echo "mounting subvolume @${d}/powerpc-ieee1275 on ${d}/powerpc-ieee1275" + btrfs-mount-subvol ($root) "${d}"/powerpc-ieee1275 @"${d}"/powerpc-ieee1275 + fi + btrfs_relative_path=1 + break + fi +done + +echo "prefix=$prefix root=$root" +if [ -n "$prefix" ]; then + source "${prefix}/${cfg}" +fi +EOF + %{__tar} cvf memdisk.tar ./grub.cfg + ./grub-mkimage -O %{grubarch} -o grub.elf -d grub-core -x grub.der -m memdisk.tar \ + -c %{platform}-config --appended-signature-size %brp_pesign_reservation ${GRUB_MODULES} + ls -l "grub.elf" + truncate -s -%brp_pesign_reservation "grub.elf" +fi +%endif +cd .. +%endif + +%install + +%ifarch %{ix86} x86_64 +cd build-xen +%make_install +install -m 644 grub.xen %{buildroot}/%{_datadir}/%{name}/%{grubxenarch}/. +# provide compatibility sym-link for VM definitions pointing to old location +install -d %{buildroot}%{_libdir}/%{name}/%{grubxenarch} +ln -srf %{buildroot}%{_datadir}/%{name}/%{grubxenarch}/grub.xen %{buildroot}%{_libdir}/%{name}/%{grubxenarch}/grub.xen +cat <<-EoM >%{buildroot}%{_libdir}/%{name}/%{grubxenarch}/DEPRECATED + This directory and its contents was moved to %{_datadir}/%{name}/%{grubxenarch}. + Individual symbolic links are provided for a smooth transition. + Please update your VM definition files to use the new location! +EoM +cd .. +%endif + +%ifarch %{efi} +cd build-efi +%make_install +install -m 644 grub.efi %{buildroot}/%{_datadir}/%{name}/%{grubefiarch}/. +%ifarch x86_64 +install -m 644 grub-tpm.efi %{buildroot}/%{_datadir}/%{name}/%{grubefiarch}/. +%endif + +# Create grub.efi link to system efi directory +# This is for tools like kiwi not fiddling with the path +%define sysefibasedir %{_datadir}/efi +%define sysefidir %{sysefibasedir}/%{_target_cpu} +install -d %{buildroot}/%{sysefidir} +ln -sr %{buildroot}/%{_datadir}/%{name}/%{grubefiarch}/grub.efi %{buildroot}%{sysefidir}/grub.efi +%ifarch x86_64 +# provide compatibility sym-link for previous shim-install and the like +install -d %{buildroot}/usr/lib64/efi +ln -srf %{buildroot}/%{_datadir}/%{name}/%{grubefiarch}/grub.efi %{buildroot}/usr/lib64/efi/grub.efi +cat <<-EoM >%{buildroot}/usr/lib64/efi/DEPRECATED + This directory and its contents was moved to %{_datadir}/efi/x86_64. + Individual symbolic links are provided for a smooth transition and + may vanish at any point in time. Please use the new location! +EoM +%endif + +%ifarch x86_64 aarch64 +export BRP_PESIGN_FILES="%{_datadir}/%{name}/%{grubefiarch}/grub.efi" +%ifarch x86_64 +BRP_PESIGN_FILES="${BRP_PESIGN_FILES} %{_datadir}/%{name}/%{grubefiarch}/grub-tpm.efi" +%endif +install -m 444 grub.der %{buildroot}/%{sysefidir}/ +%endif + +cd .. +%endif + +%if ! 0%{?only_efi:1} +cd build +%make_install +if [ "%{platform}" = "ieee1275" ]; then + export BRP_PESIGN_FILES="%{_datadir}/%{name}/%{grubarch}/grub.elf" + export BRP_PESIGN_GRUB_RESERVATION=%brp_pesign_reservation + install -m 444 grub.der %{buildroot}%{_datadir}/%{name}/%{grubarch}/ + install -m 644 grub.elf %{buildroot}%{_datadir}/%{name}/%{grubarch}/ +fi +cd .. +%endif + +if [ "%{platform}" = "emu" ]; then + # emu-lite is currently broken (and not needed), don't install! + rm -f %{buildroot}/%{_bindir}/%{name}-emu-lite +elif [ -d build-emu/grub-core ]; then + cd build-emu/grub-core + install -m 755 grub-emu %{buildroot}/%{_bindir}/%{name}-emu + if false; then + # this needs to go to '-emu'-package; until that is ready, don't install! + install -m 755 grub-emu-lite %{buildroot}/%{_bindir}/%{name}-emu-lite + else + rm -f %{buildroot}/%{_bindir}/%{name}-emu-lite + fi + install -m 644 grub-emu.1 %{buildroot}/%{_mandir}/man1/%{name}-emu.1 + cd ../.. +fi + +# *.module files are installed with executable bits due to the way grub2 build +# system works. Clear executable bits to not confuse find-debuginfo.sh +find %{buildroot}/%{_datadir}/%{name} \ + \( -name '*.module' -o -name '*.image' -o -name '*.exec' \) -print0 | \ + xargs --no-run-if-empty -0 chmod a-x + +# Script that makes part of grub.cfg persist across updates +install -m 755 %{SOURCE1} %{buildroot}/%{_sysconfdir}/grub.d/ + +# Script to generate memtest86+ menu entry +install -m 755 %{SOURCE7} %{buildroot}/%{_sysconfdir}/grub.d/ + +# Ghost config file +install -d %{buildroot}/boot/%{name} +touch %{buildroot}/boot/%{name}/grub.cfg + +# Remove devel files +rm %{buildroot}/%{_datadir}/%{name}/*/*.h +%if 0%{?suse_version} >= 1140 +rm %{buildroot}/%{_datadir}/%{name}/*.h +%endif + +# Defaults +install -m 644 -D %{SOURCE2} %{buildroot}/%{_sysconfdir}/default/grub +install -m 755 -D %{SOURCE6} %{buildroot}/%{_sbindir}/grub2-once +install -m 755 -D %{SOURCE12} %{buildroot}/%{_libdir}/snapper/plugins/grub +install -m 755 -D %{SOURCE14} %{buildroot}/%{_sysconfdir}/grub.d/80_suse_btrfs_snapshot +%if 0%{?has_systemd:1} +install -m 644 -D %{SOURCE15} %{buildroot}/%{_unitdir}/grub2-once.service +install -m 755 -D %{SOURCE17} %{buildroot}/%{_libdir}/systemd/system-sleep/grub2.sleep +%endif +install -m 755 -D %{SOURCE18} %{buildroot}/%{_sbindir}/grub2-check-default +%ifarch %{ix86} x86_64 +install -m 755 -D %{SOURCE19} %{buildroot}/%{_libexecdir}/grub2-instdev-fixup.pl +%endif + +R="%{buildroot}" +%ifarch %{ix86} x86_64 +%else +rm -f $R%{_sysconfdir}/grub.d/20_memtest86+ +%endif + +%ifarch ppc ppc64 ppc64le +rm -f $R%{_sysconfdir}/grub.d/95_textmode +%else +rm -f $R%{_sysconfdir}/grub.d/20_ppc_terminfo +%endif + +%ifarch s390x +mv $R%{_sysconfdir}/{grub.d,default}/zipl2grub.conf.in +chmod 600 $R%{_sysconfdir}/default/zipl2grub.conf.in + +%define dracutlibdir %{_prefix}/lib/dracut +%define dracutgrubmoddir %{dracutlibdir}/modules.d/99grub2 +install -m 755 -d $R%{dracutgrubmoddir} +for f in module-setup.sh grub2.sh; do + mv $R%{_datadir}/%{name}/%{grubarch}/dracut-$f $R%{dracutgrubmoddir}/$f +done +mv $R%{_datadir}/%{name}/%{grubarch}/dracut-zipl-refresh \ + $R%{_datadir}/%{name}/zipl-refresh +rm -f $R%{_sysconfdir}/grub.d/30_os-prober + +perl -ni -e ' + sub END() { + print "\n# on s390x always:\nGRUB_DISABLE_OS_PROBER=true\n"; + } + if ( s{^#?(GRUB_TERMINAL)=(console|gfxterm)}{$1=console} ) { + $_ .= "GRUB_GFXPAYLOAD_LINUX=text\n"; + } + if ( m{^# The resolution used on graphical} || + m{^# # note that you can use only modes} || + m{^# you can see them in real GRUB} || + m{^#?GRUB_GFXMODE=} ) { + next; + } + s{openSUSE}{SUSE Linux Enterprise Server} if (m{^GRUB_DISTRIBUTOR}); + print; +' %{buildroot}/%{_sysconfdir}/default/grub +%else +%endif + +# bsc#1205554 move the zfs modules into extras packages +# EXTRA_PATTERN='pattern1|pattern2|pattern3|...' +EXTRA_PATTERN="zfs" +%ifarch %{ix86} x86_64 +find %{buildroot}/%{_datadir}/%{name}/%{grubxenarch}/ -type f | sed 's,%{buildroot},,' > %{grubxenarch}-all.lst +grep -v -E ${EXTRA_PATTERN} %{grubxenarch}-all.lst > %{grubxenarch}.lst +grep -E ${EXTRA_PATTERN} %{grubxenarch}-all.lst > %{grubxenarch}-extras.lst +%endif + +%ifarch %{efi} +find %{buildroot}/%{_datadir}/%{name}/%{grubefiarch}/ -name '*.mod' | sed 's,%{buildroot},,' > %{grubefiarch}-mod-all.lst +grep -v -E ${EXTRA_PATTERN} %{grubefiarch}-mod-all.lst > %{grubefiarch}-mod.lst +grep -E ${EXTRA_PATTERN} %{grubefiarch}-mod-all.lst > %{grubefiarch}-mod-extras.lst +%endif + +find %{buildroot}/%{_datadir}/%{name}/%{grubarch}/ -name '*.mod' | sed 's,%{buildroot},,' > %{grubarch}-mod-all.lst +grep -v -E ${EXTRA_PATTERN} %{grubarch}-mod-all.lst > %{grubarch}-mod.lst +grep -E ${EXTRA_PATTERN} %{grubarch}-mod-all.lst > %{grubarch}-mod-extras.lst + +%find_lang %{name} +%fdupes %buildroot%{_bindir} +%fdupes %buildroot%{_libdir} +%fdupes %buildroot%{_datadir} + +%pre +%service_add_pre grub2-once.service + +%post +%service_add_post grub2-once.service + +%if ! 0%{?only_efi:1} + +%post %{grubarch} +%if 0%{?update_bootloader_check_type_reinit_post:1} +%update_bootloader_check_type_reinit_post grub2 +%else +# To check by current loader settings +if [ -f %{_sysconfdir}/sysconfig/bootloader ]; then + . %{_sysconfdir}/sysconfig/bootloader +fi + +# If the grub is the current loader, we'll handle the grub2 testing entry +if [ "x${LOADER_TYPE}" = "xgrub" ]; then + + exec >/dev/null 2>&1 + + # check if entry for grub2's core.img exists in the config + # if yes, we will correct obsoleted path and update grub2 stuff and config to make it work + # if no, do nothing + if [ -f /boot/grub/menu.lst ]; then + + # If grub config contains obsolete core.img path, remove and use the new one + if /usr/bin/grep -l "^\s*kernel\s*.*/boot/%{name}/core.img" /boot/grub/menu.lst; then + /sbin/update-bootloader --remove --image /boot/%{name}/core.img || true + /sbin/update-bootloader --add --image /boot/%{name}/i386-pc/core.img --name "GNU GRUB 2" || true + fi + + # Install grub2 stuff and config to make the grub2 testing entry to work with updated version + if /usr/bin/grep -l "^\s*kernel\s*.*/boot/%{name}/i386-pc/core.img" /boot/grub/menu.lst; then + # Determine the partition with /boot + BOOT_PARTITION=$(df -h /boot | sed -n '2s/[[:blank:]].*//p') + # Generate core.img, but don't let it be installed in boot sector + %{name}-install --no-bootsector $BOOT_PARTITION || true + # Create a working grub2 config, otherwise that entry is un-bootable + /usr/sbin/grub2-mkconfig -o /boot/%{name}/grub.cfg + fi + fi + +elif [ "x${LOADER_TYPE}" = "xgrub2" ]; then + + # It's enought to call update-bootloader to install grub2 and update it's config + # Use new --reinit, if not available use --refresh + # --reinit: install and update bootloader config + # --refresh: update bootloader config + /sbin/update-bootloader --reinit 2>&1 | grep -q 'Unknown option: reinit' && + /sbin/update-bootloader --refresh || true +fi +%endif + +%posttrans %{grubarch} +%{?update_bootloader_posttrans} + +%endif + +%ifarch %{efi} + +%post %{grubefiarch} +%if 0%{?update_bootloader_check_type_reinit_post:1} +%update_bootloader_check_type_reinit_post grub2-efi +%else +# To check by current loader settings +if [ -f %{_sysconfdir}/sysconfig/bootloader ]; then + . %{_sysconfdir}/sysconfig/bootloader +fi + +if [ "x${LOADER_TYPE}" = "xgrub2-efi" ]; then + + if [ -d /boot/%{name}-efi ]; then + # Migrate settings to standard prefix /boot/grub2 + for i in custom.cfg grubenv; do + [ -f /boot/%{name}-efi/$i ] && cp -a /boot/%{name}-efi/$i /boot/%{name} || : + done + + fi + + # It's enough to call update-bootloader to install grub2 and update it's config + # Use new --reinit, if not available use --refresh + # --reinit: install and update bootloader config + # --refresh: update bootloader config + /sbin/update-bootloader --reinit 2>&1 | grep -q 'Unknown option: reinit' && + /sbin/update-bootloader --refresh || true +fi + +if [ -d /boot/%{name}-efi ]; then + mv /boot/%{name}-efi /boot/%{name}-efi.rpmsave +fi + +exit 0 +%endif + +%posttrans %{grubefiarch} +%{?update_bootloader_posttrans} + +%endif + +%preun +%service_del_preun grub2-once.service +# We did not add core.img to grub1 menu.lst in new update-bootloader macro as what +# the old %%post ever did, then the %%preun counterpart which removed the added core.img +# entry from old %%post can be skipped entirely if having new macro in use. +%if ! 0%{?update_bootloader_posttrans:1}%{?only_efi:1} +if [ $1 = 0 ]; then + # To check by current loader settings + if [ -f %{_sysconfdir}/sysconfig/bootloader ]; then + . %{_sysconfdir}/sysconfig/bootloader + fi + + if [ "x${LOADER_TYPE}" = "xgrub" ]; then + + exec >/dev/null 2>&1 + + if [ -f /boot/grub/menu.lst ]; then + + # Remove grub2 testing entry in menu.lst if has any + for i in /boot/%{name}/core.img /boot/%{name}/i386-pc/core.img; do + if /usr/bin/grep -l "^\s*kernel\s*.*$i" /boot/grub/menu.lst; then + /sbin/update-bootloader --remove --image "$i" || true + fi + done + fi + + # Cleanup config, to not confuse some tools determining bootloader in use + rm -f /boot/%{name}/grub.cfg + + # Cleanup installed files + # Unless grub2 provides grub2-uninstall, we don't remove any file because + # we have no idea what's been installed. (And a blind remove is dangerous + # to remove user's or other package's file accidently ..) + fi +fi +%endif + +%postun +%service_del_postun grub2-once.service + +%files -f %{name}.lang +%defattr(-,root,root,-) +%if 0%{?suse_version} < 1500 +%doc COPYING +%else +%license COPYING +%endif +%doc AUTHORS +%doc NEWS README +%doc THANKS TODO ChangeLog +%doc docs/autoiso.cfg docs/osdetect.cfg +%ifarch s390x +%doc README.ibm3215 +%endif +%dir /boot/%{name} +%ghost %attr(600, root, root) /boot/%{name}/grub.cfg +%{_sysconfdir}/bash_completion.d/grub +%config(noreplace) %{_sysconfdir}/default/grub +%dir %{_sysconfdir}/grub.d +%{_sysconfdir}/grub.d/README +%config(noreplace) %{_sysconfdir}/grub.d/00_header +%config(noreplace) %{_sysconfdir}/grub.d/10_linux +%config(noreplace) %{_sysconfdir}/grub.d/20_linux_xen +%config(noreplace) %{_sysconfdir}/grub.d/30_uefi-firmware +%config(noreplace) %{_sysconfdir}/grub.d/40_custom +%config(noreplace) %{_sysconfdir}/grub.d/41_custom +%config(noreplace) %{_sysconfdir}/grub.d/90_persistent +%ifnarch ppc ppc64 ppc64le +%config(noreplace) %{_sysconfdir}/grub.d/95_textmode +%endif +%ifarch %{ix86} x86_64 +%config(noreplace) %{_sysconfdir}/grub.d/20_memtest86+ +%endif +%ifarch ppc ppc64 ppc64le +%config(noreplace) %{_sysconfdir}/grub.d/20_ppc_terminfo +%endif +%ifarch s390x +%config(noreplace) %{_sysconfdir}/default/zipl2grub.conf.in +%{dracutlibdir} +%{_sbindir}/%{name}-zipl-setup +%{_datadir}/%{name}/zipl-refresh +%endif +%{_sbindir}/%{name}-install +%{_sbindir}/%{name}-mkconfig +%{_sbindir}/%{name}-once +%{_sbindir}/%{name}-probe +%{_sbindir}/%{name}-reboot +%{_sbindir}/%{name}-set-default +%{_sbindir}/%{name}-check-default +%{_bindir}/%{name}-editenv +%{_bindir}/%{name}-file +%{_bindir}/%{name}-fstest +%{_bindir}/%{name}-kbdcomp +%{_bindir}/%{name}-menulst2cfg +%{_bindir}/%{name}-mkfont +%{_bindir}/%{name}-mkimage +%{_bindir}/%{name}-mklayout +%{_bindir}/%{name}-mknetdir +%{_bindir}/%{name}-mkpasswd-pbkdf2 +%{_bindir}/%{name}-mkrelpath +%{_bindir}/%{name}-mkrescue +%{_bindir}/%{name}-mkstandalone +%{_bindir}/%{name}-render-label +%{_bindir}/%{name}-script-check +%{_bindir}/%{name}-syslinux2cfg +%{_bindir}/%{name}-protect +%if 0%{?has_systemd:1} +%{_unitdir}/grub2-once.service +%endif +%dir %{_datadir}/%{name} +%dir %{_datadir}/%{name}/themes +%if 0%{?suse_version} >= 1140 +%{_datadir}/%{name}/*.pf2 +%endif +%{_datadir}/%{name}/grub-mkconfig_lib +%{_infodir}/grub-dev.info* +%{_infodir}/%{name}.info* +%{_mandir}/man1/%{name}-editenv.1.* +%{_mandir}/man1/%{name}-file.1.* +%{_mandir}/man1/%{name}-fstest.1.* +%{_mandir}/man1/%{name}-kbdcomp.1.* +%{_mandir}/man1/%{name}-menulst2cfg.1.* +%{_mandir}/man1/%{name}-mkfont.1.* +%{_mandir}/man1/%{name}-mkimage.1.* +%{_mandir}/man1/%{name}-mklayout.1.* +%{_mandir}/man1/%{name}-mknetdir.1.* +%{_mandir}/man1/%{name}-mkpasswd-pbkdf2.1.* +%{_mandir}/man1/%{name}-mkrelpath.1.* +%{_mandir}/man1/%{name}-mkrescue.1.* +%{_mandir}/man1/%{name}-mkstandalone.1.* +%{_mandir}/man1/%{name}-render-label.1.* +%{_mandir}/man1/%{name}-script-check.1.* +%{_mandir}/man1/%{name}-syslinux2cfg.1.* +%{_mandir}/man8/%{name}-install.8.* +%{_mandir}/man8/%{name}-mkconfig.8.* +%{_mandir}/man8/%{name}-probe.8.* +%{_mandir}/man8/%{name}-reboot.8.* +%{_mandir}/man8/%{name}-set-default.8.* +%if %{emu} +%{_bindir}/%{name}-emu +%{_mandir}/man1/%{name}-emu.1.* +%endif +%ifnarch s390x +%config(noreplace) %{_sysconfdir}/grub.d/30_os-prober +%{_bindir}/%{name}-glue-efi +%{_bindir}/%{name}-mount +%{_sbindir}/%{name}-bios-setup +%{_sbindir}/%{name}-macbless +%{_sbindir}/%{name}-ofpathname +%{_sbindir}/%{name}-sparc64-setup +%{_mandir}/man1/%{name}-glue-efi.1.* +%{_mandir}/man1/%{name}-mount.1.* +%{_mandir}/man8/%{name}-bios-setup.8.* +%{_mandir}/man8/%{name}-macbless.8.* +%{_mandir}/man8/%{name}-ofpathname.8.* +%{_mandir}/man8/%{name}-sparc64-setup.8.* +%endif + +%files branding-upstream +%defattr(-,root,root,-) +%{_datadir}/%{name}/themes/starfield + +%if ! 0%{?only_efi:1} + +%files %{grubarch} -f %{grubarch}-mod.lst +%defattr(-,root,root,-) +%dir %{_datadir}/%{name}/%{grubarch} +%ifarch ppc ppc64 ppc64le +# This is intentionally "grub.chrp" and not "%%{name}.chrp" +%{_datadir}/%{name}/%{grubarch}/grub.chrp +%{_datadir}/%{name}/%{grubarch}/grub.elf +%{_datadir}/%{name}/%{grubarch}/grub.der +%{_datadir}/%{name}/%{grubarch}/bootinfo.txt +%endif +%ifnarch ppc ppc64 ppc64le s390x %{arm} +%{_datadir}/%{name}/%{grubarch}/*.image +%endif +%{_datadir}/%{name}/%{grubarch}/*.img +%{_datadir}/%{name}/%{grubarch}/*.lst +%ifarch x86_64 +%{_datadir}/%{name}/%{grubarch}/efiemu*.o +%endif +%{_datadir}/%{name}/%{grubarch}/kernel.exec +%{_datadir}/%{name}/%{grubarch}/modinfo.sh +%ifarch %{ix86} x86_64 +%{_libexecdir}/%{name}-instdev-fixup.pl +%endif + +%files %{grubarch}-extras -f %{grubarch}-mod-extras.lst +%defattr(-,root,root,-) +%dir %{_datadir}/%{name}/%{grubarch} + +%files %{grubarch}-debug +%defattr(-,root,root,-) +%{_datadir}/%{name}/%{grubarch}/gdb_grub +%{_datadir}/%{name}/%{grubarch}/gmodule.pl +%{_datadir}/%{name}/%{grubarch}/*.module + +%endif + +%ifarch %{efi} + +%files %{grubefiarch} -f %{grubefiarch}-mod.lst +%defattr(-,root,root,-) +%dir %{_datadir}/%{name}/%{grubefiarch} +%{_datadir}/%{name}/%{grubefiarch}/grub.efi +%ifarch x86_64 +%{_datadir}/%{name}/%{grubefiarch}/grub-tpm.efi +%endif +%{_datadir}/%{name}/%{grubefiarch}/*.img +%{_datadir}/%{name}/%{grubefiarch}/*.lst +%{_datadir}/%{name}/%{grubefiarch}/kernel.exec +%{_datadir}/%{name}/%{grubefiarch}/modinfo.sh +%dir %{sysefibasedir} +%dir %{sysefidir} +%{sysefidir}/grub.efi +%if 0%{?suse_version} < 1600 +%ifarch x86_64 +# provide compatibility sym-link for previous shim-install and kiwi +%dir /usr/lib64/efi +/usr/lib64/efi/DEPRECATED +/usr/lib64/efi/grub.efi +%endif +%endif + +%ifarch x86_64 aarch64 +%{sysefidir}/grub.der +%endif + +%files %{grubefiarch}-extras -f %{grubefiarch}-mod-extras.lst +%defattr(-,root,root,-) +%dir %{_datadir}/%{name}/%{grubefiarch} + +%files %{grubefiarch}-debug +%defattr(-,root,root,-) +%{_datadir}/%{name}/%{grubefiarch}/gdb_grub +%{_datadir}/%{name}/%{grubefiarch}/gmodule.pl +%{_datadir}/%{name}/%{grubefiarch}/*.module + +%endif + +%files snapper-plugin +%defattr(-,root,root,-) +%dir %{_libdir}/snapper +%dir %{_libdir}/snapper/plugins +%config(noreplace) %{_sysconfdir}/grub.d/80_suse_btrfs_snapshot +%{_libdir}/snapper/plugins/grub + +%ifarch %{ix86} x86_64 +%files %{grubxenarch} -f %{grubxenarch}.lst +%defattr(-,root,root,-) +%dir %{_datadir}/%{name}/%{grubxenarch} +# provide compatibility sym-link for VM definitions pointing to old location +%dir %{_libdir}/%{name} +%{_libdir}/%{name}/%{grubxenarch} + +%files %{grubxenarch}-extras -f %{grubxenarch}-extras.lst +%defattr(-,root,root,-) +%dir %{_datadir}/%{name}/%{grubxenarch} +%endif + +%if 0%{?has_systemd:1} +%files systemd-sleep-plugin +%defattr(-,root,root,-) +%dir %{_libdir}/systemd/system-sleep +%{_libdir}/systemd/system-sleep/grub2.sleep +%endif + +%changelog diff --git a/info-dir-entry.patch b/info-dir-entry.patch new file mode 100644 index 0000000..0d57faa --- /dev/null +++ b/info-dir-entry.patch @@ -0,0 +1,29 @@ +Index: grub-2.02~beta3/docs/grub.texi +=================================================================== +--- grub-2.02~beta3.orig/docs/grub.texi ++++ grub-2.02~beta3/docs/grub.texi +@@ -32,15 +32,15 @@ Invariant Sections. + + @dircategory Kernel + @direntry +-* GRUB: (grub). The GRand Unified Bootloader +-* grub-install: (grub)Invoking grub-install. Install GRUB on your drive +-* grub-mkconfig: (grub)Invoking grub-mkconfig. Generate GRUB configuration +-* grub-mkpasswd-pbkdf2: (grub)Invoking grub-mkpasswd-pbkdf2. +-* grub-mkrelpath: (grub)Invoking grub-mkrelpath. +-* grub-mkrescue: (grub)Invoking grub-mkrescue. Make a GRUB rescue image +-* grub-mount: (grub)Invoking grub-mount. Mount a file system using GRUB +-* grub-probe: (grub)Invoking grub-probe. Probe device information +-* grub-script-check: (grub)Invoking grub-script-check. ++* GRUB2: (grub2). The GRand Unified Bootloader ++* grub2-install: (grub2)Invoking grub-install. Install GRUB on your drive ++* grub2-mkconfig: (grub2)Invoking grub-mkconfig. Generate GRUB configuration ++* grub2-mkpasswd-pbkdf2: (grub2)Invoking grub-mkpasswd-pbkdf2. ++* grub2-mkrelpath: (grub2)Invoking grub-mkrelpath. ++* grub2-mkrescue: (grub2)Invoking grub-mkrescue. Make a GRUB rescue image ++* grub2-mount: (grub2)Invoking grub-mount. Mount a file system using GRUB ++* grub2-probe: (grub2)Invoking grub-probe. Probe device information ++* grub2-script-check: (grub2)Invoking grub-script-check. + @end direntry + + @setchapternewpage odd diff --git a/not-display-menu-when-boot-once.patch b/not-display-menu-when-boot-once.patch new file mode 100644 index 0000000..57aee60 --- /dev/null +++ b/not-display-menu-when-boot-once.patch @@ -0,0 +1,31 @@ +From 78270522e8b8c0674941e0752c245dd8468e5bf8 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Wed, 1 Aug 2012 15:46:34 +0800 +Subject: [PATCH] not display menu when boot once + +References: bnc#771587 +Patch-Mainline: no + +We should prevent the menu from being displayed if boot once is +specified. This is in order to compliant with Grub1's behavior +and is better than current as it's not make any sense to bother +user to make decision when decision has been made. +--- + util/grub.d/00_header.in | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +Index: grub-2.02~beta2/util/grub.d/00_header.in +=================================================================== +--- grub-2.02~beta2.orig/util/grub.d/00_header.in ++++ grub-2.02~beta2/util/grub.d/00_header.in +@@ -304,7 +304,9 @@ make_timeout () + style="menu" + fi + cat << EOF +-if [ x\$feature_timeout_style = xy ] ; then ++if [ x\${boot_once} = xtrue ]; then ++ set timeout=0 ++elif [ x\$feature_timeout_style = xy ] ; then + set timeout_style=${style} + set timeout=${timeout} + EOF diff --git a/openSUSE-UEFI-CA-Certificate.crt b/openSUSE-UEFI-CA-Certificate.crt new file mode 100644 index 0000000..e943169 --- /dev/null +++ b/openSUSE-UEFI-CA-Certificate.crt @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEdDCCA1ygAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgTEgMB4GA1UEAwwXb3Bl +blNVU0UgU2VjdXJlIEJvb3QgQ0ExCzAJBgNVBAYTAkRFMRIwEAYDVQQHDAlOdXJl +bWJlcmcxGTAXBgNVBAoMEG9wZW5TVVNFIFByb2plY3QxITAfBgkqhkiG9w0BCQEW +EmJ1aWxkQG9wZW5zdXNlLm9yZzAeFw0xMzA4MjYxNjEyMDdaFw0zNTA3MjIxNjEy +MDdaMIGBMSAwHgYDVQQDDBdvcGVuU1VTRSBTZWN1cmUgQm9vdCBDQTELMAkGA1UE +BhMCREUxEjAQBgNVBAcMCU51cmVtYmVyZzEZMBcGA1UECgwQb3BlblNVU0UgUHJv +amVjdDEhMB8GCSqGSIb3DQEJARYSYnVpbGRAb3BlbnN1c2Uub3JnMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3t9hknqk/oPRfTtoDrGn8E6Sk/xHPnAt +Tojcmp76M7Sm2w4jwQ2owdVlBIQE/zpIGE85MuTKTvkEnp8PzSBdYaunANil/yt/ +vuhHwy9bAsi73o4a6UbThu//iJmQ6xCJuIs/PqgHxlV6btNf/IM8PRbtJsUTc5Kx +cB4ilcgAbCV2RvGi2dCwmGgPpy2xDWeJypRK6hLFkVV2f2x6LvkYiZ/49CRD1TVq +ywAOLu1L4l0J2BuXcJmeWm+mgaidqVh2fWlxgtO6OpZDm/DaFcZO6cgVuenLx+Rx +zuoQG2vEKnABqVK0F94AUs995P0PTQMYspAo1G/Erla8NmBJRotrCwIDAQABo4H0 +MIHxMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFGhCYA3iLExHfpW+I9/qlRPl +lxdiMIGuBgNVHSMEgaYwgaOAFGhCYA3iLExHfpW+I9/qlRPllxdioYGHpIGEMIGB +MSAwHgYDVQQDDBdvcGVuU1VTRSBTZWN1cmUgQm9vdCBDQTELMAkGA1UEBhMCREUx +EjAQBgNVBAcMCU51cmVtYmVyZzEZMBcGA1UECgwQb3BlblNVU0UgUHJvamVjdDEh +MB8GCSqGSIb3DQEJARYSYnVpbGRAb3BlbnN1c2Uub3JnggEBMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQsFAAOCAQEAiqOJwo7Z+YIL8zPO6RkXF6NlgM0zrgZR +Vim2OId79J38KI6q4FMSDjpgxwbYOmF2O3cI9JSkjHxHOpnYhJsXzCBiLuJ25MY2 +DSbpLlM1Cvs6NZNFw5OCwQvzCOlXH1k3qdBsafto6n87r9P3WSeO1MeWc/QMCvc+ +5K9sjMd6bwl59EEf428R+z5ssaB75JK3yvky9d7DsHN947OCXc3sYdz+DD7Gteds +LV2Sc//tqmqpm2aeXjptcLAxwM7fLyEQaAyH83egMzEKDxX27jKIxZpTcc0NGqEo +idC/9lasSzs2BisBxevl3HKDPZSsKIMT+8FdJ5wT9jJf9h9Ktz5Tig== +-----END CERTIFICATE----- diff --git a/rename-grub-info-file-to-grub2.patch b/rename-grub-info-file-to-grub2.patch new file mode 100644 index 0000000..14b4b59 --- /dev/null +++ b/rename-grub-info-file-to-grub2.patch @@ -0,0 +1,40 @@ +From 031abf80020b2fa75850d6e09f4489b687a5cb19 Mon Sep 17 00:00:00 2001 +From: Jiri Slaby +Date: Sun, 24 Jun 2012 15:40:40 +0200 +Subject: [PATCH] rename grub info file to grub2 + +Signed-off-by: Jiri Slaby + +From: Andrey Borzenkov +Do not rename file here. quilt does not support it and creates the +whole file if patch needs refreshing. It means that to regenerate two +files - Makefile.core.am and Makefile.util.am - it may be necessary to +manually rename it. +--- + +Index: grub-2.02~beta3/docs/Makefile.am +=================================================================== +--- grub-2.02~beta3.orig/docs/Makefile.am 2016-02-28 19:19:14.788874638 +0300 ++++ grub-2.02~beta3/docs/Makefile.am 2016-02-28 19:19:14.780874638 +0300 +@@ -1,7 +1,7 @@ + AUTOMAKE_OPTIONS = subdir-objects + + # AM_MAKEINFOFLAGS = --no-split --no-validate +-info_TEXINFOS = grub.texi grub-dev.texi ++info_TEXINFOS = grub2.texi grub-dev.texi + grub_TEXINFOS = fdl.texi + + EXTRA_DIST = font_char_metrics.png font_char_metrics.txt +Index: grub-2.02~beta3/docs/grub.texi +=================================================================== +--- grub-2.02~beta3.orig/docs/grub.texi 2016-02-28 19:19:14.788874638 +0300 ++++ grub-2.02~beta3/docs/grub.texi 2016-02-28 19:19:14.784874638 +0300 +@@ -1,7 +1,7 @@ + \input texinfo + @c -*-texinfo-*- + @c %**start of header +-@setfilename grub.info ++@setfilename grub2.info + @include version.texi + @settitle GNU GRUB Manual @value{VERSION} + @c Unify all our little indices for now. diff --git a/use-grub2-as-a-package-name.patch b/use-grub2-as-a-package-name.patch new file mode 100644 index 0000000..a65ae41 --- /dev/null +++ b/use-grub2-as-a-package-name.patch @@ -0,0 +1,27 @@ +From 3729b131ef1dcaa043242e8074418249695d381b Mon Sep 17 00:00:00 2001 +From: Jiri Slaby +Date: Sun, 24 Jun 2012 20:51:52 +0200 +Subject: [PATCH] use grub2 as a package name + +This will ease all of the renaming of directories and all the pkgdata +hacks. + +Signed-off-by: Jiri Slaby +--- + configure | 24 ++++++++++++------------ + configure.ac | 2 +- + 2 files changed, 13 insertions(+), 13 deletions(-) + +Index: grub-2.06/configure.ac +=================================================================== +--- grub-2.06.orig/configure.ac ++++ grub-2.06/configure.ac +@@ -34,7 +34,7 @@ dnl "TARGET_" (such as TARGET_CC, TARGET + dnl the target type. See INSTALL for full list of variables and + dnl description of the relationships between them. + +-AC_INIT([GRUB],[2.06],[bug-grub@gnu.org]) ++AC_INIT([GRUB2],[2.06],[bug-grub@gnu.org]) + + AC_CONFIG_AUX_DIR([build-aux]) +