From 3efed6ed765dc67a50a7d2c86f6fa9de3a2d7018 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: May 18 2021 06:38:48 +0000 Subject: import grub2-2.02-99.el8 --- diff --git a/SOURCES/0318-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch b/SOURCES/0318-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch new file mode 100644 index 0000000..047b07b --- /dev/null +++ b/SOURCES/0318-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch @@ -0,0 +1,121 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Renaud=20M=C3=A9trich?= +Date: Thu, 3 Dec 2020 09:13:24 +0100 +Subject: [PATCH] at_keyboard: use set 1 when keyboard is in Translate mode +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When keyboard controller acts in Translate mode (0x40 mask), then use +set 1 since translation is done. +Otherwise use the mode queried from the controller (usually set 2). + +Added "atkeyb" debugging messages in at_keyboard module as well. + +Resolves: rhbz#1897587 + +Tested on: +- Asus N53SN (set 1 used) +- Dell Precision (set 1 used) +- HP Elitebook (set 2 used) +- HP G5430 (set 1 used, keyboard in XT mode!) +- Lenovo P71 & Lenovo T460s (set 2 used) +- QEMU/KVM (set 1 used) + +Signed-off-by: Renaud Métrich +--- + grub-core/term/at_keyboard.c | 29 ++++++++++++++++++++++++----- + include/grub/at_keyboard.h | 4 ++++ + 2 files changed, 28 insertions(+), 5 deletions(-) + +diff --git a/grub-core/term/at_keyboard.c b/grub-core/term/at_keyboard.c +index f0a986eb176..69d99b61df5 100644 +--- a/grub-core/term/at_keyboard.c ++++ b/grub-core/term/at_keyboard.c +@@ -135,20 +135,28 @@ query_mode (void) + int e; + + e = write_mode (0); +- if (!e) ++ if (!e) { ++ grub_dprintf("atkeyb", "query_mode: write_mode(0) failed\n"); + return 0; ++ } + + do { + keyboard_controller_wait_until_ready (); + ret = grub_inb (KEYBOARD_REG_DATA); + } while (ret == GRUB_AT_ACK); + /* QEMU translates the set even in no-translate mode. */ +- if (ret == 0x43 || ret == 1) ++ if (ret == 0x43 || ret == 1) { ++ grub_dprintf("atkeyb", "query_mode: returning 1 (ret=0x%x)\n", ret); + return 1; +- if (ret == 0x41 || ret == 2) ++ } ++ if (ret == 0x41 || ret == 2) { ++ grub_dprintf("atkeyb", "query_mode: returning 2 (ret=0x%x)\n", ret); + return 2; +- if (ret == 0x3f || ret == 3) ++ } ++ if (ret == 0x3f || ret == 3) { ++ grub_dprintf("atkeyb", "query_mode: returning 3 (ret=0x%x)\n", ret); + return 3; ++ } + return 0; + } + +@@ -165,7 +173,13 @@ set_scancodes (void) + } + + #if !USE_SCANCODE_SET +- ps2_state.current_set = 1; ++ if ((grub_keyboard_controller_orig & KEYBOARD_AT_TRANSLATE) == KEYBOARD_AT_TRANSLATE) { ++ grub_dprintf ("atkeyb", "queried set is %d but keyboard in Translate mode, so actually in set 1\n", grub_keyboard_orig_set); ++ ps2_state.current_set = 1; ++ } else { ++ grub_dprintf ("atkeyb", "using queried set %d\n", grub_keyboard_orig_set); ++ ps2_state.current_set = grub_keyboard_orig_set; ++ } + return; + #else + +@@ -266,6 +280,7 @@ grub_keyboard_controller_init (void) + grub_keyboard_orig_set = 2; + #else + grub_keyboard_controller_orig = grub_keyboard_controller_read (); ++ grub_dprintf ("atkeyb", "grub_keyboard_controller_orig = 0x%x\n", grub_keyboard_controller_orig); + grub_keyboard_orig_set = query_mode (); + #endif + set_scancodes (); +@@ -275,11 +290,15 @@ grub_keyboard_controller_init (void) + static grub_err_t + grub_keyboard_controller_fini (struct grub_term_input *term __attribute__ ((unused))) + { ++/* In !USE_SCANCODE_SET mode, we didn't change anything, so nothing to restore */ ++#if USE_SCANCODE_SET + if (ps2_state.current_set == 0) + return GRUB_ERR_NONE; ++ grub_dprintf ("atkeyb", "restoring set %d, controller 0x%x\n", grub_keyboard_orig_set, grub_keyboard_controller_orig); + if (grub_keyboard_orig_set) + write_mode (grub_keyboard_orig_set); + grub_keyboard_controller_write (grub_keyboard_controller_orig); ++#endif + return GRUB_ERR_NONE; + } + +diff --git a/include/grub/at_keyboard.h b/include/grub/at_keyboard.h +index bcb4d9ba78f..9414dc1b996 100644 +--- a/include/grub/at_keyboard.h ++++ b/include/grub/at_keyboard.h +@@ -19,6 +19,10 @@ + #ifndef GRUB_AT_KEYBOARD_HEADER + #define GRUB_AT_KEYBOARD_HEADER 1 + ++/* ++ * Refer to https://wiki.osdev.org/%228042%22_PS/2_Controller for details. ++ */ ++ + /* Used for sending commands to the controller. */ + #define KEYBOARD_COMMAND_ISREADY(x) !((x) & 0x02) + #define KEYBOARD_COMMAND_READ 0x20 diff --git a/SOURCES/0318-kern-Add-lockdown-support.patch b/SOURCES/0318-kern-Add-lockdown-support.patch deleted file mode 100644 index 1fa686b..0000000 --- a/SOURCES/0318-kern-Add-lockdown-support.patch +++ /dev/null @@ -1,441 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Fri, 19 Feb 2021 10:33:54 +0100 -Subject: [PATCH] kern: Add lockdown support - -When the GRUB starts on a secure boot platform, some commands can be -used to subvert the protections provided by the verification mechanism and -could lead to booting untrusted system. - -To prevent that situation, allow GRUB to be locked down. That way the code -may check if GRUB has been locked down and further restrict the commands -that are registered or what subset of their functionality could be used. - -The lockdown support adds the following components: - -* The grub_lockdown() function which can be used to lockdown GRUB if, - e.g., UEFI Secure Boot is enabled. - -* The grub_is_lockdown() function which can be used to check if the GRUB - was locked down. - -* A verifier that flags OS kernels, the GRUB modules, Device Trees and ACPI - tables as GRUB_VERIFY_FLAGS_DEFER_AUTH to defer verification to other - verifiers. These files are only successfully verified if another registered - verifier returns success. Otherwise, the whole verification process fails. - - For example, PE/COFF binaries verification can be done by the shim_lock - verifier which validates the signatures using the shim_lock protocol. - However, the verification is not deferred directly to the shim_lock verifier. - The shim_lock verifier is hooked into the verification process instead. - -* A set of grub_{command,extcmd}_lockdown functions that can be used by - code registering command handlers, to only register unsafe commands if - the GRUB has not been locked down. - -Signed-off-by: Javier Martinez Canillas -Reviewed-by: Daniel Kiper ---- - grub-core/Makefile.core.def | 1 + - grub-core/commands/extcmd.c | 23 +++++++++++ - grub-core/kern/command.c | 24 ++++++++++++ - grub-core/kern/lockdown.c | 93 +++++++++++++++++++++++++++++++++++++++++++++ - include/grub/command.h | 5 +++ - include/grub/extcmd.h | 7 ++++ - include/grub/lockdown.h | 44 +++++++++++++++++++++ - conf/Makefile.common | 2 + - docs/grub-dev.texi | 27 +++++++++++++ - docs/grub.texi | 9 +++++ - grub-core/Makefile.am | 5 ++- - 11 files changed, 239 insertions(+), 1 deletion(-) - create mode 100644 grub-core/kern/lockdown.c - create mode 100644 include/grub/lockdown.h - -diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def -index c8a50b4fcfa..0eb7f312b29 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -197,6 +197,7 @@ kernel = { - efi = term/efi/console.c; - efi = kern/acpi.c; - efi = kern/efi/acpi.c; -+ efi = kern/lockdown.c; - efi = lib/envblk.c; - efi = kern/efi/tpm.c; - i386_coreboot = kern/i386/pc/acpi.c; -diff --git a/grub-core/commands/extcmd.c b/grub-core/commands/extcmd.c -index 69574e2b05b..90a5ca24a64 100644 ---- a/grub-core/commands/extcmd.c -+++ b/grub-core/commands/extcmd.c -@@ -19,6 +19,7 @@ - - #include - #include -+#include - #include - #include - #include -@@ -110,6 +111,28 @@ grub_register_extcmd (const char *name, grub_extcmd_func_t func, - summary, description, parser, 1); - } - -+static grub_err_t -+grub_extcmd_lockdown (grub_extcmd_context_t ctxt __attribute__ ((unused)), -+ int argc __attribute__ ((unused)), -+ char **argv __attribute__ ((unused))) -+{ -+ return grub_error (GRUB_ERR_ACCESS_DENIED, -+ N_("%s: the command is not allowed when lockdown is enforced"), -+ ctxt->extcmd->cmd->name); -+} -+ -+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) -+{ -+ if (grub_is_lockdown () == GRUB_LOCKDOWN_ENABLED) -+ func = grub_extcmd_lockdown; -+ -+ return grub_register_extcmd (name, func, flags, summary, description, parser); -+} -+ - void - grub_unregister_extcmd (grub_extcmd_t ext) - { -diff --git a/grub-core/kern/command.c b/grub-core/kern/command.c -index acd72187992..4aabcd4b5f9 100644 ---- a/grub-core/kern/command.c -+++ b/grub-core/kern/command.c -@@ -17,6 +17,7 @@ - * along with GRUB. If not, see . - */ - -+#include - #include - #include - -@@ -77,6 +78,29 @@ grub_register_command_prio (const char *name, - return cmd; - } - -+static grub_err_t -+grub_cmd_lockdown (grub_command_t cmd __attribute__ ((unused)), -+ int argc __attribute__ ((unused)), -+ char **argv __attribute__ ((unused))) -+ -+{ -+ return grub_error (GRUB_ERR_ACCESS_DENIED, -+ N_("%s: the command is not allowed when lockdown is enforced"), -+ cmd->name); -+} -+ -+grub_command_t -+grub_register_command_lockdown (const char *name, -+ grub_command_func_t func, -+ const char *summary, -+ const char *description) -+{ -+ if (grub_is_lockdown () == GRUB_LOCKDOWN_ENABLED) -+ func = grub_cmd_lockdown; -+ -+ return grub_register_command_prio (name, func, summary, description, 0); -+} -+ - void - grub_unregister_command (grub_command_t cmd) - { -diff --git a/grub-core/kern/lockdown.c b/grub-core/kern/lockdown.c -new file mode 100644 -index 00000000000..f87ddaeb1ee ---- /dev/null -+++ b/grub-core/kern/lockdown.c -@@ -0,0 +1,93 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2020 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 -+ -+/* There is no verifier framework in grub 2.02 */ -+#if 0 -+#include -+#endif -+ -+static int lockdown = GRUB_LOCKDOWN_DISABLED; -+ -+/* There is no verifier framework in grub 2.02 */ -+#if 0 -+static grub_err_t -+lockdown_verifier_init (grub_file_t io __attribute__ ((unused)), -+ enum grub_file_type type, -+ void **context __attribute__ ((unused)), -+ enum grub_verify_flags *flags) -+{ -+ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; -+ -+ switch (type & GRUB_FILE_TYPE_MASK) -+ { -+ case GRUB_FILE_TYPE_GRUB_MODULE: -+ case GRUB_FILE_TYPE_LINUX_KERNEL: -+ case GRUB_FILE_TYPE_MULTIBOOT_KERNEL: -+ case GRUB_FILE_TYPE_XEN_HYPERVISOR: -+ case GRUB_FILE_TYPE_BSD_KERNEL: -+ case GRUB_FILE_TYPE_XNU_KERNEL: -+ case GRUB_FILE_TYPE_PLAN9_KERNEL: -+ case GRUB_FILE_TYPE_NTLDR: -+ case GRUB_FILE_TYPE_TRUECRYPT: -+ case GRUB_FILE_TYPE_FREEDOS: -+ case GRUB_FILE_TYPE_PXECHAINLOADER: -+ case GRUB_FILE_TYPE_PCCHAINLOADER: -+ case GRUB_FILE_TYPE_COREBOOT_CHAINLOADER: -+ case GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE: -+ case GRUB_FILE_TYPE_ACPI_TABLE: -+ case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE: -+ *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH; -+ -+ /* Fall through. */ -+ -+ default: -+ return GRUB_ERR_NONE; -+ } -+} -+ -+struct grub_file_verifier lockdown_verifier = -+ { -+ .name = "lockdown_verifier", -+ .init = lockdown_verifier_init, -+ }; -+#endif -+ -+void -+grub_lockdown (void) -+{ -+ lockdown = GRUB_LOCKDOWN_ENABLED; -+ -+ /* -+ * XXX: The lockdown verifier doesn't make sense until -+ * GRUB has moved to the shim_lock verifier. -+ */ -+#if 0 -+ grub_verifier_register (&lockdown_verifier); -+#endif -+} -+ -+int -+grub_is_lockdown (void) -+{ -+ return lockdown; -+} -diff --git a/include/grub/command.h b/include/grub/command.h -index eee4e847ee4..2a6f7f84697 100644 ---- a/include/grub/command.h -+++ b/include/grub/command.h -@@ -86,6 +86,11 @@ EXPORT_FUNC(grub_register_command_prio) (const char *name, - const char *summary, - const char *description, - int prio); -+grub_command_t -+EXPORT_FUNC(grub_register_command_lockdown) (const char *name, -+ grub_command_func_t func, -+ const char *summary, -+ const char *description); - 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 19fe592669e..fe9248b8bb6 100644 ---- a/include/grub/extcmd.h -+++ b/include/grub/extcmd.h -@@ -62,6 +62,13 @@ grub_extcmd_t EXPORT_FUNC(grub_register_extcmd) (const char *name, - const char *description, - const struct grub_arg_option *parser); - -+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); -+ - grub_extcmd_t EXPORT_FUNC(grub_register_extcmd_prio) (const char *name, - grub_extcmd_func_t func, - grub_command_flags_t flags, -diff --git a/include/grub/lockdown.h b/include/grub/lockdown.h -new file mode 100644 -index 00000000000..40531fa823b ---- /dev/null -+++ b/include/grub/lockdown.h -@@ -0,0 +1,44 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2020 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_LOCKDOWN_H -+#define GRUB_LOCKDOWN_H 1 -+ -+#include -+ -+#define GRUB_LOCKDOWN_DISABLED 0 -+#define GRUB_LOCKDOWN_ENABLED 1 -+ -+#ifdef GRUB_MACHINE_EFI -+extern void -+EXPORT_FUNC (grub_lockdown) (void); -+extern int -+EXPORT_FUNC (grub_is_lockdown) (void); -+#else -+static inline void -+grub_lockdown (void) -+{ -+} -+ -+static inline int -+grub_is_lockdown (void) -+{ -+ return GRUB_LOCKDOWN_DISABLED; -+} -+#endif -+#endif /* ! GRUB_LOCKDOWN_H */ -diff --git a/conf/Makefile.common b/conf/Makefile.common -index b93879804c0..521cdda1f5a 100644 ---- a/conf/Makefile.common -+++ b/conf/Makefile.common -@@ -85,7 +85,9 @@ CPPFLAGS_PARTTOOL_LIST = -Dgrub_parttool_register=PARTTOOL_LIST_MARKER - CPPFLAGS_TERMINAL_LIST = '-Dgrub_term_register_input(...)=INPUT_TERMINAL_LIST_MARKER(__VA_ARGS__)' - CPPFLAGS_TERMINAL_LIST += '-Dgrub_term_register_output(...)=OUTPUT_TERMINAL_LIST_MARKER(__VA_ARGS__)' - CPPFLAGS_COMMAND_LIST = '-Dgrub_register_command(...)=COMMAND_LIST_MARKER(__VA_ARGS__)' -+CPPFLAGS_COMMAND_LIST += '-Dgrub_register_command_lockdown(...)=COMMAND_LOCKDOWN_LIST_MARKER(__VA_ARGS__)' - CPPFLAGS_COMMAND_LIST += '-Dgrub_register_extcmd(...)=EXTCOMMAND_LIST_MARKER(__VA_ARGS__)' -+CPPFLAGS_COMMAND_LIST += '-Dgrub_register_extcmd_lockdown(...)=EXTCOMMAND_LOCKDOWN_LIST_MARKER(__VA_ARGS__)' - CPPFLAGS_COMMAND_LIST += '-Dgrub_register_command_p1(...)=P1COMMAND_LIST_MARKER(__VA_ARGS__)' - CPPFLAGS_FDT_LIST := '-Dgrub_fdtbus_register(...)=FDT_DRIVER_LIST_MARKER(__VA_ARGS__)' - CPPFLAGS_MARKER = $(CPPFLAGS_FS_LIST) $(CPPFLAGS_VIDEO_LIST) \ -diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi -index 3ce827ab726..421dd410e50 100644 ---- a/docs/grub-dev.texi -+++ b/docs/grub-dev.texi -@@ -84,6 +84,7 @@ This edition documents version @value{VERSION}. - * Video Subsystem:: - * PFF2 Font File Format:: - * Graphical Menu Software Design:: -+* Lockdown framework:: - * Copying This Manual:: Copying This Manual - * Index:: - @end menu -@@ -1949,6 +1950,32 @@ the graphics mode that was in use before @code{grub_video_setup()} was called - might fix some of the problems. - - -+@node Lockdown framework -+@chapter Lockdown framework -+ -+The GRUB can be locked down, which is a restricted mode where some operations -+are not allowed. For instance, some commands cannot be used when the GRUB is -+locked down. -+ -+The function -+@code{grub_lockdown()} is used to lockdown GRUB and the function -+@code{grub_is_lockdown()} function can be used to check whether lockdown is -+enabled or not. When enabled, the function returns @samp{GRUB_LOCKDOWN_ENABLED} -+and @samp{GRUB_LOCKDOWN_DISABLED} when is not enabled. -+ -+The following functions can be used to register the commands that can only be -+used when lockdown is disabled: -+ -+@itemize -+ -+@item @code{grub_cmd_lockdown()} registers command which should not run when the -+GRUB is in lockdown mode. -+ -+@item @code{grub_cmd_lockdown()} registers extended command which should not run -+when the GRUB is in lockdown mode. -+ -+@end itemize -+ - @node Copying This Manual - @appendix Copying This Manual - -diff --git a/docs/grub.texi b/docs/grub.texi -index c54bee31679..0a53c28ee88 100644 ---- a/docs/grub.texi -+++ b/docs/grub.texi -@@ -5610,6 +5610,8 @@ environment variables and commands are listed in the same order. - @menu - * Authentication and authorisation:: Users and access control - * Using digital signatures:: Booting digitally signed code -+* Lockdown:: Lockdown when booting on a secure setup -+ - @end menu - - @node Authentication and authorisation -@@ -5772,6 +5774,13 @@ 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 Lockdown -+@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. -+ - @node Platform limitations - @chapter Platform limitations - -diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am -index 4062652506d..a6f1b0dcd06 100644 ---- a/grub-core/Makefile.am -+++ b/grub-core/Makefile.am -@@ -82,6 +82,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fs.h - KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i18n.h - KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/kernel.h - KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/list.h -+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lockdown.h - KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/misc.h - if COND_emu - KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/compiler-rt-emu.h -@@ -350,8 +351,10 @@ command.lst: $(MARKER_FILES) - b=`basename $$pp .marker`; \ - sed -n \ - -e "/EXTCOMMAND_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/*\1: $$b/;p;}" \ -+ -e "/EXTCOMMAND_LOCKDOWN_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/*\1: $$b/;p;}" \ - -e "/P1COMMAND_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/*\1: $$b/;p;}" \ -- -e "/COMMAND_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/\1: $$b/;p;}" $$pp; \ -+ -e "/COMMAND_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/\1: $$b/;p;}" \ -+ -e "/COMMAND_LOCKDOWN_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/\1: $$b/;p;}" $$pp; \ - done) | sort -u > $@ - platform_DATA += command.lst - CLEANFILES += command.lst diff --git a/SOURCES/0319-grub-install-disable-support-for-EFI-platforms.patch b/SOURCES/0319-grub-install-disable-support-for-EFI-platforms.patch new file mode 100644 index 0000000..2591b60 --- /dev/null +++ b/SOURCES/0319-grub-install-disable-support-for-EFI-platforms.patch @@ -0,0 +1,118 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jan Hlavac +Date: Fri, 20 Nov 2020 23:51:47 +0100 +Subject: [PATCH] grub-install: disable support for EFI platforms + +For each platform, GRUB is shipped as a kernel image and a set of +modules. These files are then used by the grub-install utility to +install GRUB on a specific device. However, in order to support UEFI +Secure Boot, the resulting EFI binary must be signed by a recognized +private key. For this reason, for EFI platforms, most distributions also +ship prebuilt EFI binaries signed by a distribution-specific private +key. In this case, however, the grub-install utility should not be used +because it would overwrite the signed EFI binary. + +The current fix is suboptimal because it preserves all EFI-related code. +A better solution could be to modularize the code and provide a +build-time option. + +Resolves: rhbz#1737444 + +Signed-off-by: Jan Hlavac +--- + util/grub-install.c | 35 ++++++++++++++++------------------- + docs/grub.texi | 7 +++++++ + util/grub-install.8 | 4 +++- + 3 files changed, 26 insertions(+), 20 deletions(-) + +diff --git a/util/grub-install.c b/util/grub-install.c +index 3bf0e063a86..65bb2f99ef1 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -888,6 +888,22 @@ main (int argc, char *argv[]) + + platform = grub_install_get_target (grub_install_source_directory); + ++ switch (platform) ++ { ++ case GRUB_INSTALL_PLATFORM_ARM_EFI: ++ case GRUB_INSTALL_PLATFORM_ARM64_EFI: ++ case GRUB_INSTALL_PLATFORM_I386_EFI: ++ case GRUB_INSTALL_PLATFORM_IA64_EFI: ++ case GRUB_INSTALL_PLATFORM_X86_64_EFI: ++ is_efi = 1; ++ grub_util_error (_("this utility cannot be used for EFI platforms" ++ " because it does not support UEFI Secure Boot")); ++ break; ++ default: ++ is_efi = 0; ++ break; ++ } ++ + { + char *platname = grub_install_get_platform_name (platform); + fprintf (stderr, _("Installing for %s platform.\n"), platname); +@@ -994,26 +1010,7 @@ main (int argc, char *argv[]) + grub_hostfs_init (); + grub_host_init (); + +- switch (platform) +- { +- 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_IA64_EFI: +- is_efi = 1; +- break; +- default: +- is_efi = 0; +- break; +- +- /* pacify warning. */ +- case GRUB_INSTALL_PLATFORM_MAX: +- break; +- } +- + /* Find the EFI System Partition. */ +- + if (is_efi) + { + grub_fs_t fs; +diff --git a/docs/grub.texi b/docs/grub.texi +index c54bee31679..fa11cc0aff7 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -6185,6 +6185,13 @@ grub2-install @var{install_device} + The device name @var{install_device} is an OS device name or a GRUB + device name. + ++In order to support UEFI Secure Boot, the resulting GRUB EFI binary must ++be signed by a recognized private key. For this reason, for EFI ++platforms, most distributions also ship prebuilt GRUB EFI binaries ++signed by a distribution-specific private key. In this case, however, ++@command{grub2-install} should not be used because it would overwrite ++the signed EFI binary. ++ + @command{grub2-install} accepts the following options: + + @table @option +diff --git a/util/grub-install.8 b/util/grub-install.8 +index 76272a39d2e..02371930fa1 100644 +--- a/util/grub-install.8 ++++ b/util/grub-install.8 +@@ -1,4 +1,4 @@ +-.TH GRUB-INSTALL 1 "Wed Feb 26 2014" ++.TH GRUB-INSTALL 1 "Fri Nov 20 2020" + .SH NAME + \fBgrub-install\fR \(em Install GRUB on a device. + +@@ -31,6 +31,8 @@ + .SH DESCRIPTION + \fBgrub-install\fR installs GRUB onto a device. This includes copying GRUB images into the target directory (generally \fI/boot/grub\fR), and on some platforms may also include installing GRUB onto a boot sector. + ++In order to support UEFI Secure Boot, the resulting GRUB EFI binary must be signed by a recognized private key. For this reason, for EFI platforms, most distributions also ship prebuilt GRUB EFI binaries signed by a distribution-specific private key. In this case, however, the \fBgrub-install\fR utility should not be used because it would overwrite the signed EFI binary. ++ + .SH OPTIONS + .TP + \fB--modules\fR=\fIMODULES\fR\! diff --git a/SOURCES/0319-kern-lockdown-Set-a-variable-if-the-GRUB-is-locked-d.patch b/SOURCES/0319-kern-lockdown-Set-a-variable-if-the-GRUB-is-locked-d.patch deleted file mode 100644 index 91021f0..0000000 --- a/SOURCES/0319-kern-lockdown-Set-a-variable-if-the-GRUB-is-locked-d.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Tue, 2 Feb 2021 19:59:48 +0100 -Subject: [PATCH] kern/lockdown: Set a variable if the GRUB is locked down - -It may be useful for scripts to determine whether the GRUB is locked -down or not. Add the lockdown variable which is set to "y" when the GRUB -is locked down. - -Suggested-by: Dimitri John Ledkov -Signed-off-by: Javier Martinez Canillas -Reviewed-by: Daniel Kiper ---- - grub-core/kern/lockdown.c | 4 ++++ - docs/grub.texi | 3 +++ - 2 files changed, 7 insertions(+) - -diff --git a/grub-core/kern/lockdown.c b/grub-core/kern/lockdown.c -index f87ddaeb1ee..30cba7f5ea2 100644 ---- a/grub-core/kern/lockdown.c -+++ b/grub-core/kern/lockdown.c -@@ -18,6 +18,7 @@ - */ - - #include -+#include - #include - #include - -@@ -84,6 +85,9 @@ grub_lockdown (void) - #if 0 - grub_verifier_register (&lockdown_verifier); - #endif -+ -+ grub_env_set ("lockdown", "y"); -+ grub_env_export ("lockdown"); - } - - int -diff --git a/docs/grub.texi b/docs/grub.texi -index 0a53c28ee88..6f5efaace32 100644 ---- a/docs/grub.texi -+++ b/docs/grub.texi -@@ -5781,6 +5781,9 @@ The GRUB can be locked down when booted on a secure boot environment, for exampl - if the UEFI 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. -+ - @node Platform limitations - @chapter Platform limitations - diff --git a/SOURCES/0320-New-with-debug-timestamps-configure-flag-to-prepend-.patch b/SOURCES/0320-New-with-debug-timestamps-configure-flag-to-prepend-.patch new file mode 100644 index 0000000..62d61b9 --- /dev/null +++ b/SOURCES/0320-New-with-debug-timestamps-configure-flag-to-prepend-.patch @@ -0,0 +1,112 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Renaud=20M=C3=A9trich?= +Date: Sat, 23 Nov 2019 14:57:41 +0100 +Subject: [PATCH] New --with-debug-timestamps configure flag to prepend debug + traces with absolute and relative timestamp +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Renaud Métrich +--- + configure.ac | 18 ++++++++++++++++++ + grub-core/kern/misc.c | 20 ++++++++++++++++++++ + config.h.in | 1 + + 3 files changed, 39 insertions(+) + +diff --git a/configure.ac b/configure.ac +index 9323c125469..0059b938a3a 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1514,6 +1514,17 @@ else + fi + AC_SUBST([BOOT_TIME_STATS]) + ++AC_ARG_WITH([debug-timestamps], ++ AS_HELP_STRING([--with-debug-timestamps], ++ [prepend debug traces with absolute and relative timestamps])) ++ ++if test x$with_debug_timestamps = xyes; then ++ DEBUG_WITH_TIMESTAMPS=1 ++else ++ DEBUG_WITH_TIMESTAMPS=0 ++fi ++AC_SUBST([DEBUG_WITH_TIMESTAMPS]) ++ + AC_ARG_ENABLE([grub-emu-sdl], + [AS_HELP_STRING([--enable-grub-emu-sdl], + [build and install the `grub-emu' debugging utility with SDL support (default=guessed)])]) +@@ -2092,6 +2103,7 @@ AM_CONDITIONAL([COND_APPLE_LINKER], [test x$TARGET_APPLE_LINKER = x1]) + AM_CONDITIONAL([COND_ENABLE_EFIEMU], [test x$enable_efiemu = xyes]) + AM_CONDITIONAL([COND_ENABLE_CACHE_STATS], [test x$DISK_CACHE_STATS = x1]) + AM_CONDITIONAL([COND_ENABLE_BOOT_TIME_STATS], [test x$BOOT_TIME_STATS = x1]) ++AM_CONDITIONAL([COND_DEBUG_WITH_TIMESTAMPS], [test x$DEBUG_WITH_TIMESTAMPS = x1]) + + AM_CONDITIONAL([COND_HAVE_CXX], [test x$HAVE_CXX = xyes]) + +@@ -2187,6 +2199,12 @@ else + echo With boot time statistics: No + fi + ++if [ x"$with_debug_timestamps" = xyes ]; then ++echo Debug traces with timestamps: Yes ++else ++echo Debug traces with timestamps: No ++fi ++ + if [ x"$efiemu_excuse" = x ]; then + echo efiemu runtime: Yes + else +diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c +index c034f49f97c..11f2974fce5 100644 +--- a/grub-core/kern/misc.c ++++ b/grub-core/kern/misc.c +@@ -25,6 +25,9 @@ + #include + #include + #include ++#if DEBUG_WITH_TIMESTAMPS ++#include ++#endif + + union printf_arg + { +@@ -179,9 +182,26 @@ grub_real_dprintf (const char *file, const int line, const char *condition, + const char *fmt, ...) + { + va_list args; ++#if DEBUG_WITH_TIMESTAMPS ++ static long unsigned int last_time = 0; ++ static int last_had_cr = 1; ++#endif + + if (grub_debug_enabled (condition)) + { ++#if DEBUG_WITH_TIMESTAMPS ++ /* Don't print timestamp if last printed message isn't terminated yet */ ++ if (last_had_cr) { ++ long unsigned int tmabs = (long unsigned int) grub_get_time_ms(); ++ long unsigned int tmrel = tmabs - last_time; ++ last_time = tmabs; ++ grub_printf ("%3lu.%03lus +%2lu.%03lus ", tmabs / 1000, tmabs % 1000, tmrel / 1000, tmrel % 1000); ++ } ++ if (fmt[grub_strlen(fmt)-1] == '\n') ++ last_had_cr = 1; ++ else ++ last_had_cr = 0; ++#endif + grub_printf ("%s:%d: ", file, line); + va_start (args, fmt); + grub_vprintf (fmt, args); +diff --git a/config.h.in b/config.h.in +index 9e8f9911b18..d15480b4163 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -12,6 +12,7 @@ + /* Define to 1 to enable disk cache statistics. */ + #define DISK_CACHE_STATS @DISK_CACHE_STATS@ + #define BOOT_TIME_STATS @BOOT_TIME_STATS@ ++#define DEBUG_WITH_TIMESTAMPS @DEBUG_WITH_TIMESTAMPS@ + + /* We don't need those. */ + #define MINILZO_CFG_SKIP_LZO_PTR 1 diff --git a/SOURCES/0320-efi-Lockdown-the-GRUB-when-the-UEFI-Secure-Boot-is-e.patch b/SOURCES/0320-efi-Lockdown-the-GRUB-when-the-UEFI-Secure-Boot-is-e.patch deleted file mode 100644 index d1fb42c..0000000 --- a/SOURCES/0320-efi-Lockdown-the-GRUB-when-the-UEFI-Secure-Boot-is-e.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Mon, 28 Sep 2020 20:08:29 +0200 -Subject: [PATCH] efi: Lockdown the GRUB when the UEFI Secure Boot is enabled - -If the UEFI Secure Boot is enabled then the GRUB must be locked down -to prevent executing code that can potentially be used to subvert its -verification mechanisms. - -Signed-off-by: Javier Martinez Canillas -Reviewed-by: Daniel Kiper ---- - grub-core/kern/efi/init.c | 19 +++++++++++++++++++ - 1 file changed, 19 insertions(+) - -diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c -index 79243b364a1..97bf36906a4 100644 ---- a/grub-core/kern/efi/init.c -+++ b/grub-core/kern/efi/init.c -@@ -20,6 +20,8 @@ - #include - #include - #include -+#include -+#include - #include - #include - #include -@@ -93,6 +95,23 @@ grub_efi_init (void) - /* Initialize the memory management system. */ - grub_efi_mm_init (); - -+ /* -+ * Lockdown the GRUB and register the shim_lock verifier -+ * if the UEFI Secure Boot is enabled. -+ */ -+ if (grub_efi_secure_boot ()) -+ { -+ grub_lockdown (); -+ -+ /* -+ * TODO: Move GRUB to using the shim_lock verifier and -+ * enable the lockdown verifier. -+ */ -+#if 0 -+ grub_shim_lock_verifier_setup (); -+#endif -+ } -+ - efi_call_4 (grub_efi_system_table->boot_services->set_watchdog_timer, - 0, 0, 0, NULL); - diff --git a/SOURCES/0321-Added-debug-statements-to-grub_disk_open-and-grub_di.patch b/SOURCES/0321-Added-debug-statements-to-grub_disk_open-and-grub_di.patch new file mode 100644 index 0000000..6edbdbd --- /dev/null +++ b/SOURCES/0321-Added-debug-statements-to-grub_disk_open-and-grub_di.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Renaud=20M=C3=A9trich?= +Date: Sat, 23 Nov 2019 15:22:16 +0100 +Subject: [PATCH] Added debug statements to grub_disk_open() and + grub_disk_close() on success +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Renaud Métrich +--- + grub-core/kern/disk.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/grub-core/kern/disk.c b/grub-core/kern/disk.c +index 789f8c05233..7f58c561472 100644 +--- a/grub-core/kern/disk.c ++++ b/grub-core/kern/disk.c +@@ -285,6 +285,8 @@ grub_disk_open (const char *name) + return 0; + } + ++ grub_dprintf ("disk", "Opening `%s' succeeded.\n", name); ++ + return disk; + } + +@@ -292,7 +294,7 @@ void + grub_disk_close (grub_disk_t disk) + { + grub_partition_t part; +- grub_dprintf ("disk", "Closing `%s'.\n", disk->name); ++ grub_dprintf ("disk", "Closing `%s'...\n", disk->name); + + if (disk->dev && disk->dev->close) + (disk->dev->close) (disk); +@@ -306,8 +308,10 @@ grub_disk_close (grub_disk_t disk) + grub_free (disk->partition); + disk->partition = part; + } ++ grub_dprintf ("disk", "Closing `%s' succeeded.\n", disk->name); + grub_free ((void *) disk->name); + grub_free (disk); ++ + } + + /* Small read (less than cache size and not pass across cache unit boundaries). diff --git a/SOURCES/0321-efi-Use-grub_is_lockdown-instead-of-hardcoding-a-dis.patch b/SOURCES/0321-efi-Use-grub_is_lockdown-instead-of-hardcoding-a-dis.patch deleted file mode 100644 index a902271..0000000 --- a/SOURCES/0321-efi-Use-grub_is_lockdown-instead-of-hardcoding-a-dis.patch +++ /dev/null @@ -1,137 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Mon, 28 Sep 2020 20:08:33 +0200 -Subject: [PATCH] efi: Use grub_is_lockdown() instead of hardcoding a disabled - modules list - -Now the GRUB can check if it has been locked down and this can be used to -prevent executing commands that can be utilized to circumvent the UEFI -Secure Boot mechanisms. So, instead of hardcoding a list of modules that -have to be disabled, prevent the usage of commands that can be dangerous. - -This not only allows the commands to be disabled on other platforms, but -also properly separate the concerns. Since the shim_lock verifier logic -should be only about preventing to run untrusted binaries and not about -defining these kind of policies. - -Signed-off-by: Javier Martinez Canillas -Reviewed-by: Daniel Kiper ---- - grub-core/commands/iorw.c | 26 ++++++++++---------------- - grub-core/commands/memrw.c | 26 ++++++++++---------------- - 2 files changed, 20 insertions(+), 32 deletions(-) - -diff --git a/grub-core/commands/iorw.c b/grub-core/commands/iorw.c -index 41a7f3f0466..584baec8f91 100644 ---- a/grub-core/commands/iorw.c -+++ b/grub-core/commands/iorw.c -@@ -23,7 +23,7 @@ - #include - #include - #include --#include -+#include - - GRUB_MOD_LICENSE ("GPLv3+"); - -@@ -119,9 +119,6 @@ grub_cmd_write (grub_command_t cmd, int argc, char **argv) - - GRUB_MOD_INIT(memrw) - { -- if (grub_efi_secure_boot()) -- return; -- - cmd_read_byte = - grub_register_extcmd ("inb", grub_cmd_read, 0, - N_("PORT"), N_("Read 8-bit value from PORT."), -@@ -135,24 +132,21 @@ GRUB_MOD_INIT(memrw) - N_("PORT"), N_("Read 32-bit value from PORT."), - options); - cmd_write_byte = -- grub_register_command ("outb", grub_cmd_write, -- N_("PORT VALUE [MASK]"), -- N_("Write 8-bit VALUE to PORT.")); -+ grub_register_command_lockdown ("outb", grub_cmd_write, -+ N_("PORT VALUE [MASK]"), -+ N_("Write 8-bit VALUE to PORT.")); - cmd_write_word = -- grub_register_command ("outw", grub_cmd_write, -- N_("PORT VALUE [MASK]"), -- N_("Write 16-bit VALUE to PORT.")); -+ grub_register_command_lockdown ("outw", grub_cmd_write, -+ N_("PORT VALUE [MASK]"), -+ N_("Write 16-bit VALUE to PORT.")); - cmd_write_dword = -- grub_register_command ("outl", grub_cmd_write, -- N_("ADDR VALUE [MASK]"), -- N_("Write 32-bit VALUE to PORT.")); -+ grub_register_command_lockdown ("outl", grub_cmd_write, -+ N_("ADDR VALUE [MASK]"), -+ N_("Write 32-bit VALUE to PORT.")); - } - - GRUB_MOD_FINI(memrw) - { -- if (grub_efi_secure_boot()) -- return; -- - grub_unregister_extcmd (cmd_read_byte); - grub_unregister_extcmd (cmd_read_word); - grub_unregister_extcmd (cmd_read_dword); -diff --git a/grub-core/commands/memrw.c b/grub-core/commands/memrw.c -index 088cbe9e2bc..d401a6db0ef 100644 ---- a/grub-core/commands/memrw.c -+++ b/grub-core/commands/memrw.c -@@ -22,7 +22,7 @@ - #include - #include - #include --#include -+#include - - GRUB_MOD_LICENSE ("GPLv3+"); - -@@ -121,9 +121,6 @@ grub_cmd_write (grub_command_t cmd, int argc, char **argv) - - GRUB_MOD_INIT(memrw) - { -- if (grub_efi_secure_boot()) -- return; -- - cmd_read_byte = - grub_register_extcmd ("read_byte", grub_cmd_read, 0, - N_("ADDR"), N_("Read 8-bit value from ADDR."), -@@ -137,24 +134,21 @@ GRUB_MOD_INIT(memrw) - N_("ADDR"), N_("Read 32-bit value from ADDR."), - options); - cmd_write_byte = -- grub_register_command ("write_byte", grub_cmd_write, -- N_("ADDR VALUE [MASK]"), -- N_("Write 8-bit VALUE to ADDR.")); -+ grub_register_command_lockdown ("write_byte", grub_cmd_write, -+ N_("ADDR VALUE [MASK]"), -+ N_("Write 8-bit VALUE to ADDR.")); - cmd_write_word = -- grub_register_command ("write_word", grub_cmd_write, -- N_("ADDR VALUE [MASK]"), -- N_("Write 16-bit VALUE to ADDR.")); -+ grub_register_command_lockdown ("write_word", grub_cmd_write, -+ N_("ADDR VALUE [MASK]"), -+ N_("Write 16-bit VALUE to ADDR.")); - cmd_write_dword = -- grub_register_command ("write_dword", grub_cmd_write, -- N_("ADDR VALUE [MASK]"), -- N_("Write 32-bit VALUE to ADDR.")); -+ grub_register_command_lockdown ("write_dword", grub_cmd_write, -+ N_("ADDR VALUE [MASK]"), -+ N_("Write 32-bit VALUE to ADDR.")); - } - - GRUB_MOD_FINI(memrw) - { -- if (grub_efi_secure_boot()) -- return; -- - grub_unregister_extcmd (cmd_read_byte); - grub_unregister_extcmd (cmd_read_word); - grub_unregister_extcmd (cmd_read_dword); diff --git a/SOURCES/0322-Introduce-function-grub_debug_is_enabled-void-return.patch b/SOURCES/0322-Introduce-function-grub_debug_is_enabled-void-return.patch new file mode 100644 index 0000000..e73e302 --- /dev/null +++ b/SOURCES/0322-Introduce-function-grub_debug_is_enabled-void-return.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Renaud=20M=C3=A9trich?= +Date: Mon, 25 Nov 2019 09:29:53 +0100 +Subject: [PATCH] Introduce function grub_debug_is_enabled(void) returning 1 if + 'debug' is in the environment and not empty +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Renaud Métrich +--- + grub-core/kern/misc.c | 13 +++++++++++++ + include/grub/misc.h | 1 + + 2 files changed, 14 insertions(+) + +diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c +index 11f2974fce5..97378c48b22 100644 +--- a/grub-core/kern/misc.c ++++ b/grub-core/kern/misc.c +@@ -162,6 +162,19 @@ int grub_err_printf (const char *fmt, ...) + __attribute__ ((alias("grub_printf"))); + #endif + ++/* Return 1 if 'debug' is set and not empty */ ++int ++grub_debug_is_enabled (void) ++{ ++ const char *debug; ++ ++ debug = grub_env_get ("debug"); ++ if (!debug || debug[0] == '\0') ++ return 0; ++ ++ return 1; ++} ++ + int + grub_debug_enabled (const char * condition) + { +diff --git a/include/grub/misc.h b/include/grub/misc.h +index 1258ec6bbf3..6ca03c4d692 100644 +--- a/include/grub/misc.h ++++ b/include/grub/misc.h +@@ -367,6 +367,7 @@ grub_puts (const char *s) + } + + int EXPORT_FUNC(grub_puts_) (const char *s); ++int EXPORT_FUNC(grub_debug_is_enabled) (void); + int EXPORT_FUNC(grub_debug_enabled) (const char *condition); + void EXPORT_FUNC(grub_real_dprintf) (const char *file, + const int line, diff --git a/SOURCES/0322-acpi-Don-t-register-the-acpi-command-when-locked-dow.patch b/SOURCES/0322-acpi-Don-t-register-the-acpi-command-when-locked-dow.patch deleted file mode 100644 index f1b2859..0000000 --- a/SOURCES/0322-acpi-Don-t-register-the-acpi-command-when-locked-dow.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Mon, 28 Sep 2020 20:08:41 +0200 -Subject: [PATCH] acpi: Don't register the acpi command when locked down -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The command is not allowed when lockdown is enforced. Otherwise an -attacker can instruct the GRUB to load an SSDT table to overwrite -the kernel lockdown configuration and later load and execute -unsigned code. - -Fixes: CVE-2020-14372 - -Reported-by: Máté Kukri -Signed-off-by: Javier Martinez Canillas -Reviewed-by: Daniel Kiper ---- - grub-core/commands/acpi.c | 15 ++++++++------- - docs/grub.texi | 5 +++++ - 2 files changed, 13 insertions(+), 7 deletions(-) - -diff --git a/grub-core/commands/acpi.c b/grub-core/commands/acpi.c -index 9f02f22019a..a2912989b5c 100644 ---- a/grub-core/commands/acpi.c -+++ b/grub-core/commands/acpi.c -@@ -27,6 +27,7 @@ - #include - #include - #include -+#include - - #ifdef GRUB_MACHINE_EFI - #include -@@ -775,13 +776,13 @@ static grub_extcmd_t cmd; - - GRUB_MOD_INIT(acpi) - { -- cmd = grub_register_extcmd ("acpi", grub_cmd_acpi, 0, -- N_("[-1|-2] [--exclude=TABLE1,TABLE2|" -- "--load-only=TABLE1,TABLE2] FILE1" -- " [FILE2] [...]"), -- N_("Load host ACPI tables and tables " -- "specified by arguments."), -- options); -+ cmd = grub_register_extcmd_lockdown ("acpi", grub_cmd_acpi, 0, -+ N_("[-1|-2] [--exclude=TABLE1,TABLE2|" -+ "--load-only=TABLE1,TABLE2] FILE1" -+ " [FILE2] [...]"), -+ N_("Load host ACPI tables and tables " -+ "specified by arguments."), -+ options); - } - - GRUB_MOD_FINI(acpi) -diff --git a/docs/grub.texi b/docs/grub.texi -index 6f5efaace32..a724d0712ed 100644 ---- a/docs/grub.texi -+++ b/docs/grub.texi -@@ -4033,6 +4033,11 @@ Normally, this command will replace the Root System Description Pointer - (RSDP) in the Extended BIOS Data Area to point to the new tables. If the - @option{--no-ebda} option is used, the new tables will be known only to - GRUB, but may be used by GRUB's EFI emulation. -+ -+Note: The command is not allowed when lockdown is enforced (@pxref{Lockdown}). -+ Otherwise an attacker can instruct the GRUB to load an SSDT table to -+ overwrite the kernel lockdown configuration and later load and execute -+ unsigned code. - @end deffn - - diff --git a/SOURCES/0323-Don-t-clear-screen-when-debugging-is-enabled.patch b/SOURCES/0323-Don-t-clear-screen-when-debugging-is-enabled.patch new file mode 100644 index 0000000..20abbf3 --- /dev/null +++ b/SOURCES/0323-Don-t-clear-screen-when-debugging-is-enabled.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Renaud=20M=C3=A9trich?= +Date: Sat, 23 Nov 2019 16:23:54 +0100 +Subject: [PATCH] Don't clear screen when debugging is enabled +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Renaud Métrich +--- + grub-core/normal/main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c +index 04ae9ed02f6..59fd54eb0f1 100644 +--- a/grub-core/normal/main.c ++++ b/grub-core/normal/main.c +@@ -204,7 +204,8 @@ void + grub_normal_init_page (struct grub_term_output *term, + int y __attribute__((__unused__))) + { +- grub_term_cls (term); ++ if (! grub_debug_is_enabled ()) ++ grub_term_cls (term); + + #if 0 + grub_ssize_t msg_len; diff --git a/SOURCES/0323-mmap-Don-t-register-cutmem-and-badram-commands-when-.patch b/SOURCES/0323-mmap-Don-t-register-cutmem-and-badram-commands-when-.patch deleted file mode 100644 index ee1fddc..0000000 --- a/SOURCES/0323-mmap-Don-t-register-cutmem-and-badram-commands-when-.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Wed, 14 Oct 2020 16:33:42 +0200 -Subject: [PATCH] mmap: Don't register cutmem and badram commands when lockdown - is enforced - -The cutmem and badram commands can be used to remove EFI memory regions -and potentially disable the UEFI Secure Boot. Prevent the commands to be -registered if the GRUB is locked down. - -Fixes: CVE-2020-27779 - -Reported-by: Teddy Reed -Signed-off-by: Javier Martinez Canillas -Reviewed-by: Daniel Kiper ---- - grub-core/mmap/mmap.c | 13 +++++++------ - docs/grub.texi | 4 ++++ - 2 files changed, 11 insertions(+), 6 deletions(-) - -diff --git a/grub-core/mmap/mmap.c b/grub-core/mmap/mmap.c -index 57b4e9a72a9..7ebf32e1e5e 100644 ---- a/grub-core/mmap/mmap.c -+++ b/grub-core/mmap/mmap.c -@@ -20,6 +20,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -534,12 +535,12 @@ static grub_command_t cmd, cmd_cut; - - GRUB_MOD_INIT(mmap) - { -- cmd = grub_register_command ("badram", grub_cmd_badram, -- N_("ADDR1,MASK1[,ADDR2,MASK2[,...]]"), -- N_("Declare memory regions as faulty (badram).")); -- cmd_cut = grub_register_command ("cutmem", grub_cmd_cutmem, -- N_("FROM[K|M|G] TO[K|M|G]"), -- N_("Remove any memory regions in specified range.")); -+ cmd = grub_register_command_lockdown ("badram", grub_cmd_badram, -+ N_("ADDR1,MASK1[,ADDR2,MASK2[,...]]"), -+ N_("Declare memory regions as faulty (badram).")); -+ cmd_cut = grub_register_command_lockdown ("cutmem", grub_cmd_cutmem, -+ N_("FROM[K|M|G] TO[K|M|G]"), -+ N_("Remove any memory regions in specified range.")); - - } - -diff --git a/docs/grub.texi b/docs/grub.texi -index a724d0712ed..a9b02190404 100644 ---- a/docs/grub.texi -+++ b/docs/grub.texi -@@ -4098,6 +4098,10 @@ this page is to be filtered. This syntax makes it easy to represent patterns - that are often result of memory damage, due to physical distribution of memory - cells. - -+Note: The command is not allowed when lockdown is enforced (@pxref{Lockdown}). -+ This prevents removing EFI memory regions to potentially subvert the -+ security mechanisms provided by the UEFI secure boot. -+ - @node blocklist - @subsection blocklist - diff --git a/SOURCES/0324-commands-Restrict-commands-that-can-load-BIOS-or-DT-.patch b/SOURCES/0324-commands-Restrict-commands-that-can-load-BIOS-or-DT-.patch deleted file mode 100644 index 301910c..0000000 --- a/SOURCES/0324-commands-Restrict-commands-that-can-load-BIOS-or-DT-.patch +++ /dev/null @@ -1,108 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Wed, 24 Feb 2021 09:00:05 +0100 -Subject: [PATCH] commands: Restrict commands that can load BIOS or DT blobs - when locked down - -There are some more commands that should be restricted when the GRUB is -locked down. Following is the list of commands and reasons to restrict: - - * fakebios: creates BIOS-like structures for backward compatibility with - existing OSes. This should not be allowed when locked down. - - * loadbios: reads a BIOS dump from storage and loads it. This action - should not be allowed when locked down. - - * devicetree: loads a Device Tree blob and passes it to the OS. It replaces - any Device Tree provided by the firmware. This also should - not be allowed when locked down. - -Signed-off-by: Javier Martinez Canillas -Reviewed-by: Daniel Kiper ---- - grub-core/commands/efi/loadbios.c | 14 +++++++------- - grub-core/loader/arm/linux.c | 6 +++--- - grub-core/loader/efi/fdt.c | 4 ++-- - docs/grub.texi | 6 ++++-- - 4 files changed, 16 insertions(+), 14 deletions(-) - -diff --git a/grub-core/commands/efi/loadbios.c b/grub-core/commands/efi/loadbios.c -index 132cadbc764..3da4c26df7a 100644 ---- a/grub-core/commands/efi/loadbios.c -+++ b/grub-core/commands/efi/loadbios.c -@@ -205,14 +205,14 @@ static grub_command_t cmd_fakebios, cmd_loadbios; - - GRUB_MOD_INIT(loadbios) - { -- cmd_fakebios = grub_register_command ("fakebios", grub_cmd_fakebios, -- 0, N_("Create BIOS-like structures for" -- " backward compatibility with" -- " existing OS.")); -+ cmd_fakebios = grub_register_command_lockdown ("fakebios", grub_cmd_fakebios, -+ 0, N_("Create BIOS-like structures for" -+ " backward compatibility with" -+ " existing OS.")); - -- cmd_loadbios = grub_register_command ("loadbios", grub_cmd_loadbios, -- N_("BIOS_DUMP [INT10_DUMP]"), -- N_("Load BIOS dump.")); -+ cmd_loadbios = grub_register_command_lockdown ("loadbios", grub_cmd_loadbios, -+ N_("BIOS_DUMP [INT10_DUMP]"), -+ N_("Load BIOS dump.")); - } - - GRUB_MOD_FINI(loadbios) -diff --git a/grub-core/loader/arm/linux.c b/grub-core/loader/arm/linux.c -index ea29d7a724a..ff2911baa67 100644 ---- a/grub-core/loader/arm/linux.c -+++ b/grub-core/loader/arm/linux.c -@@ -489,9 +489,9 @@ GRUB_MOD_INIT (linux) - 0, N_("Load Linux.")); - cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, - 0, N_("Load initrd.")); -- cmd_devicetree = grub_register_command ("devicetree", grub_cmd_devicetree, -- /* TRANSLATORS: DTB stands for device tree blob. */ -- 0, N_("Load DTB file.")); -+ cmd_devicetree = grub_register_command_lockdown ("devicetree", grub_cmd_devicetree, -+ /* TRANSLATORS: DTB stands for device tree blob. */ -+ 0, N_("Load DTB file.")); - my_mod = mod; - current_fdt = (const void *) grub_arm_firmware_get_boot_data (); - machine_type = grub_arm_firmware_get_machine_type (); -diff --git a/grub-core/loader/efi/fdt.c b/grub-core/loader/efi/fdt.c -index a9dbcfdfeaf..c0ea050dc8b 100644 ---- a/grub-core/loader/efi/fdt.c -+++ b/grub-core/loader/efi/fdt.c -@@ -167,8 +167,8 @@ static grub_command_t cmd_devicetree; - GRUB_MOD_INIT (fdt) - { - cmd_devicetree = -- grub_register_command ("devicetree", grub_cmd_devicetree, 0, -- N_("Load DTB file.")); -+ grub_register_command_lockdown ("devicetree", grub_cmd_devicetree, 0, -+ N_("Load DTB file.")); - } - - GRUB_MOD_FINI (fdt) -diff --git a/docs/grub.texi b/docs/grub.texi -index a9b02190404..71943b15dd1 100644 ---- a/docs/grub.texi -+++ b/docs/grub.texi -@@ -4276,13 +4276,15 @@ hour, minute, and second unchanged. - - - @node devicetree --@subsection linux -+@subsection devicetree - - @deffn Command devicetree file - Load a device tree blob (.dtb) from a filesystem, for later use by a Linux - kernel. Does not perform merging with any device tree supplied by firmware, - but rather replaces it completely. --@ref{GNU/Linux}. -+ -+Note: The command is not allowed when lockdown is enforced (@pxref{Lockdown}). -+ This is done to prevent subverting various security mechanisms. - @end deffn - - @node distrust diff --git a/SOURCES/0324-grub_file_-instrumentation-new-file-debug-tag.patch b/SOURCES/0324-grub_file_-instrumentation-new-file-debug-tag.patch new file mode 100644 index 0000000..e0f515a --- /dev/null +++ b/SOURCES/0324-grub_file_-instrumentation-new-file-debug-tag.patch @@ -0,0 +1,71 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Renaud=20M=C3=A9trich?= +Date: Fri, 29 Nov 2019 11:02:00 +0100 +Subject: [PATCH] grub_file_* instrumentation (new 'file' debug tag) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Renaud Métrich +--- + grub-core/kern/file.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c +index 668f8930b19..c2d9a550007 100644 +--- a/grub-core/kern/file.c ++++ b/grub-core/kern/file.c +@@ -67,6 +67,8 @@ grub_file_open (const char *name) + const char *file_name; + grub_file_filter_id_t filter; + ++ grub_dprintf ("file", "Opening `%s' ...\n", name); ++ + device_name = grub_file_get_device_name (name); + if (grub_errno) + goto fail; +@@ -127,6 +129,8 @@ grub_file_open (const char *name) + grub_memcpy (grub_file_filters_enabled, grub_file_filters_all, + sizeof (grub_file_filters_enabled)); + ++ grub_dprintf ("file", "Opening `%s' succeeded.\n", name); ++ + return file; + + fail: +@@ -140,6 +144,8 @@ grub_file_open (const char *name) + grub_memcpy (grub_file_filters_enabled, grub_file_filters_all, + sizeof (grub_file_filters_enabled)); + ++ grub_dprintf ("file", "Opening `%s' failed.\n", name); ++ + return 0; + } + +@@ -171,6 +177,7 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len) + + if (len == 0) + return 0; ++ + read_hook = file->read_hook; + read_hook_data = file->read_hook_data; + if (!file->read_hook) +@@ -191,11 +198,18 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len) + grub_err_t + grub_file_close (grub_file_t file) + { ++ grub_dprintf ("file", "Closing `%s' ...\n", file->name); + if (file->fs->close) + (file->fs->close) (file); + + if (file->device) + grub_device_close (file->device); ++ ++ if (grub_errno == GRUB_ERR_NONE) ++ grub_dprintf ("file", "Closing `%s' succeeded.\n", file->name); ++ else ++ grub_dprintf ("file", "Closing `%s' failed with %d.\n", file->name, grub_errno); ++ + grub_free (file->name); + grub_free (file); + return grub_errno; diff --git a/SOURCES/0325-commands-setpci-Restrict-setpci-command-when-locked-.patch b/SOURCES/0325-commands-setpci-Restrict-setpci-command-when-locked-.patch deleted file mode 100644 index 1bb09d4..0000000 --- a/SOURCES/0325-commands-setpci-Restrict-setpci-command-when-locked-.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Wed, 24 Feb 2021 22:59:59 +0100 -Subject: [PATCH] commands/setpci: Restrict setpci command when locked down - -This command can set PCI devices register values, which makes it dangerous -in a locked down configuration. Restrict it so can't be used on this setup. - -Signed-off-by: Javier Martinez Canillas -Reviewed-by: Daniel Kiper ---- - grub-core/commands/setpci.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/grub-core/commands/setpci.c b/grub-core/commands/setpci.c -index d5bc97d60b2..fa2ba7d8919 100644 ---- a/grub-core/commands/setpci.c -+++ b/grub-core/commands/setpci.c -@@ -329,10 +329,10 @@ static grub_extcmd_t cmd; - - GRUB_MOD_INIT(setpci) - { -- cmd = grub_register_extcmd ("setpci", grub_cmd_setpci, 0, -- N_("[-s POSITION] [-d DEVICE] [-v VAR] " -- "REGISTER[=VALUE[:MASK]]"), -- N_("Manipulate PCI devices."), options); -+ cmd = grub_register_extcmd_lockdown ("setpci", grub_cmd_setpci, 0, -+ N_("[-s POSITION] [-d DEVICE] [-v VAR] " -+ "REGISTER[=VALUE[:MASK]]"), -+ N_("Manipulate PCI devices."), options); - } - - GRUB_MOD_FINI(setpci) diff --git a/SOURCES/0325-ieee1275-Avoiding-many-unecessary-open-close.patch b/SOURCES/0325-ieee1275-Avoiding-many-unecessary-open-close.patch new file mode 100644 index 0000000..c92467d --- /dev/null +++ b/SOURCES/0325-ieee1275-Avoiding-many-unecessary-open-close.patch @@ -0,0 +1,136 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Diego Domingos +Date: Mon, 14 Dec 2020 17:42:45 +0100 +Subject: [PATCH] ieee1275: Avoiding many unecessary open/close + +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 d887d4b6eee..f3a6ecd797f 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) diff --git a/SOURCES/0326-commands-hdparm-Restrict-hdparm-command-when-locked-.patch b/SOURCES/0326-commands-hdparm-Restrict-hdparm-command-when-locked-.patch deleted file mode 100644 index 04129ca..0000000 --- a/SOURCES/0326-commands-hdparm-Restrict-hdparm-command-when-locked-.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Wed, 24 Feb 2021 12:59:29 +0100 -Subject: [PATCH] commands/hdparm: Restrict hdparm command when locked down - -The command can be used to get/set ATA disk parameters. Some of these can -be dangerous since change the disk behavior. Restrict it when locked down. - -Signed-off-by: Javier Martinez Canillas -Reviewed-by: Daniel Kiper ---- - grub-core/commands/hdparm.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/grub-core/commands/hdparm.c b/grub-core/commands/hdparm.c -index d3fa9661e5f..2e2319e645a 100644 ---- a/grub-core/commands/hdparm.c -+++ b/grub-core/commands/hdparm.c -@@ -436,9 +436,9 @@ static grub_extcmd_t cmd; - - GRUB_MOD_INIT(hdparm) - { -- cmd = grub_register_extcmd ("hdparm", grub_cmd_hdparm, 0, -- N_("[OPTIONS] DISK"), -- N_("Get/set ATA disk parameters."), options); -+ cmd = grub_register_extcmd_lockdown ("hdparm", grub_cmd_hdparm, 0, -+ N_("[OPTIONS] DISK"), -+ N_("Get/set ATA disk parameters."), options); - } - - GRUB_MOD_FINI(hdparm) diff --git a/SOURCES/0326-ieee1275-powerpc-implements-fibre-channel-discovery-.patch b/SOURCES/0326-ieee1275-powerpc-implements-fibre-channel-discovery-.patch new file mode 100644 index 0000000..9fa02bb --- /dev/null +++ b/SOURCES/0326-ieee1275-powerpc-implements-fibre-channel-discovery-.patch @@ -0,0 +1,90 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Diego Domingos +Date: Mon, 14 Dec 2020 17:45:28 +0100 +Subject: [PATCH] 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. + +Signed-off-by: Diego Domingos +--- + grub-core/osdep/linux/ofpath.c | 49 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 49 insertions(+) + +diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c +index a6153d35954..0f5d54e9f2d 100644 +--- a/grub-core/osdep/linux/ofpath.c ++++ b/grub-core/osdep/linux/ofpath.c +@@ -350,6 +350,38 @@ of_path_of_ide(const char *sys_devname __attribute__((unused)), const char *devi + return ret; + } + ++ ++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); ++} ++ + #ifdef __sparc__ + static char * + of_path_of_nvme(const char *sys_devname __attribute__((unused)), +@@ -577,6 +609,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 +632,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 + { diff --git a/SOURCES/0327-gdb-Restrict-GDB-access-when-locked-down.patch b/SOURCES/0327-gdb-Restrict-GDB-access-when-locked-down.patch deleted file mode 100644 index b392d22..0000000 --- a/SOURCES/0327-gdb-Restrict-GDB-access-when-locked-down.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Wed, 24 Feb 2021 15:03:26 +0100 -Subject: [PATCH] gdb: Restrict GDB access when locked down - -The gdbstub* commands allow to start and control a GDB stub running on -local host that can be used to connect from a remote debugger. Restrict -this functionality when the GRUB is locked down. - -Signed-off-by: Javier Martinez Canillas -Reviewed-by: Daniel Kiper ---- - grub-core/gdb/gdb.c | 32 ++++++++++++++++++-------------- - 1 file changed, 18 insertions(+), 14 deletions(-) - -diff --git a/grub-core/gdb/gdb.c b/grub-core/gdb/gdb.c -index 847a1e1e36f..1818cb6f8eb 100644 ---- a/grub-core/gdb/gdb.c -+++ b/grub-core/gdb/gdb.c -@@ -75,20 +75,24 @@ static grub_command_t cmd, cmd_stop, cmd_break; - GRUB_MOD_INIT (gdb) - { - grub_gdb_idtinit (); -- cmd = grub_register_command ("gdbstub", grub_cmd_gdbstub, -- N_("PORT"), -- /* TRANSLATORS: GDB stub is a small part of -- GDB functionality running on local host -- which allows remote debugger to -- connect to it. */ -- N_("Start GDB stub on given port")); -- cmd_break = grub_register_command ("gdbstub_break", grub_cmd_gdb_break, -- /* TRANSLATORS: this refers to triggering -- a breakpoint so that the user will land -- into GDB. */ -- 0, N_("Break into GDB")); -- cmd_stop = grub_register_command ("gdbstub_stop", grub_cmd_gdbstop, -- 0, N_("Stop GDB stub")); -+ cmd = grub_register_command_lockdown ("gdbstub", grub_cmd_gdbstub, -+ N_("PORT"), -+ /* -+ * TRANSLATORS: GDB stub is a small part of -+ * GDB functionality running on local host -+ * which allows remote debugger to -+ * connect to it. -+ */ -+ N_("Start GDB stub on given port")); -+ cmd_break = grub_register_command_lockdown ("gdbstub_break", grub_cmd_gdb_break, -+ /* -+ * TRANSLATORS: this refers to triggering -+ * a breakpoint so that the user will land -+ * into GDB. -+ */ -+ 0, N_("Break into GDB")); -+ cmd_stop = grub_register_command_lockdown ("gdbstub_stop", grub_cmd_gdbstop, -+ 0, N_("Stop GDB stub")); - } - - GRUB_MOD_FINI (gdb) diff --git a/SOURCES/0327-ieee1275-powerpc-enables-device-mapper-discovery.patch b/SOURCES/0327-ieee1275-powerpc-enables-device-mapper-discovery.patch new file mode 100644 index 0000000..6f1c21b --- /dev/null +++ b/SOURCES/0327-ieee1275-powerpc-enables-device-mapper-discovery.patch @@ -0,0 +1,106 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Diego Domingos +Date: Mon, 14 Dec 2020 17:47:16 +0100 +Subject: [PATCH] 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. + +Signed-off-by: Diego Domingos +--- + 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 0f5d54e9f2d..cc849d9c94c 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 +@@ -755,13 +756,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); diff --git a/SOURCES/0328-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch b/SOURCES/0328-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch new file mode 100644 index 0000000..2f053c8 --- /dev/null +++ b/SOURCES/0328-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch @@ -0,0 +1,239 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Renaud=20M=C3=A9trich?= +Date: Fri, 18 Dec 2020 15:39:26 +0100 +Subject: [PATCH] Add 'at_keyboard_fallback_set' var to force the set manually + +This seems required with HP DL380p Gen 8 systems. +Indeed, with this system, we can see the following sequence: + +1. controller is queried to get current configuration (returns 0x30 which is quite standard) +2. controller is queried to get the current keyboard set in used, using code 0xf0 (first part) +3. controller answers with 0xfa which means "ACK" (== ok) +4. then we send "0" to tell "we want to know which set your are supporting" +5. controller answers with 0xfa ("ACK") +6. controller should then give us 1, 2, 3 or 0x43, 0x41, 0x3f, but here it gives us 0xfe which means "NACK" + +Since there seems no way to determine the current set, and in fact the +controller expects set2 to be used, we need to rely on an environment +variable. +Everything has been tested on this system: using 0xFE (resend command), +making sure we wait for ACK in the 2 steps "write_mode", etc. + +Below is litterature I used to come up with "there is no other +solution": +- https://wiki.osdev.org/%228042%22_PS/2_Controller +- http://www-ug.eecg.toronto.edu/msl/nios_devices/datasheets/PS2%20Keyboard%20Protocol.htm +- http://www.s100computers.com/My%20System%20Pages/MSDOS%20Board/PC%20Keyboard.pdf +--- + grub-core/term/at_keyboard.c | 121 ++++++++++++++++++++++++++++++++++--------- + 1 file changed, 96 insertions(+), 25 deletions(-) + +diff --git a/grub-core/term/at_keyboard.c b/grub-core/term/at_keyboard.c +index 69d99b61df5..c805cccbdde 100644 +--- a/grub-core/term/at_keyboard.c ++++ b/grub-core/term/at_keyboard.c +@@ -31,6 +31,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); + static grub_uint8_t grub_keyboard_controller_orig; + static grub_uint8_t grub_keyboard_orig_set; + struct grub_ps2_state ps2_state; ++static int fallback_set; + + static int ping_sent; + +@@ -76,6 +77,8 @@ at_command (grub_uint8_t data) + break; + return 0; + } ++ if (i == GRUB_AT_TRIES) ++ grub_dprintf ("atkeyb", "at_command() timed out! (stopped after %d tries)\n", i); + return (i != GRUB_AT_TRIES); + } + +@@ -105,6 +108,21 @@ grub_keyboard_controller_read (void) + + #endif + ++static int ++resend_last_result (void) ++{ ++ grub_uint8_t ret; ++ keyboard_controller_wait_until_ready (); ++ grub_dprintf ("atkeyb", "resend_last_result: sending 0xfe\n"); ++ grub_outb (0xfe, KEYBOARD_REG_DATA); ++ ret = wait_ack (); ++ grub_dprintf ("atkeyb", "resend_last_result: wait_ack() returned 0x%x\n", ret); ++ keyboard_controller_wait_until_ready (); ++ ret = grub_inb (KEYBOARD_REG_DATA); ++ grub_dprintf ("atkeyb", "resend_last_result: read 0x%x from controller\n", ret); ++ return ret; ++} ++ + static int + write_mode (int mode) + { +@@ -113,11 +131,14 @@ write_mode (int mode) + { + grub_uint8_t ack; + keyboard_controller_wait_until_ready (); ++ grub_dprintf ("atkeyb", "write_mode: sending 0xf0\n"); + grub_outb (0xf0, KEYBOARD_REG_DATA); + keyboard_controller_wait_until_ready (); ++ grub_dprintf ("atkeyb", "write_mode: sending mode %d\n", mode); + grub_outb (mode, KEYBOARD_REG_DATA); + keyboard_controller_wait_until_ready (); + ack = wait_ack (); ++ grub_dprintf ("atkeyb", "write_mode: wait_ack() returned 0x%x\n", ack); + if (ack == GRUB_AT_NACK) + continue; + if (ack == GRUB_AT_ACK) +@@ -125,6 +146,9 @@ write_mode (int mode) + return 0; + } + ++ if (i == GRUB_AT_TRIES) ++ grub_dprintf ("atkeyb", "write_mode() timed out! (stopped after %d tries)\n", i); ++ + return (i != GRUB_AT_TRIES); + } + +@@ -132,31 +156,66 @@ static int + query_mode (void) + { + grub_uint8_t ret; ++ grub_uint64_t endtime; ++ unsigned i; + int e; ++ char *envvar; + +- e = write_mode (0); +- if (!e) { +- grub_dprintf("atkeyb", "query_mode: write_mode(0) failed\n"); +- return 0; +- } ++ for (i = 0; i < GRUB_AT_TRIES; i++) { ++ grub_dprintf ("atkeyb", "query_mode: sending command to controller\n"); ++ e = write_mode (0); ++ if (!e) { ++ grub_dprintf ("atkeyb", "query_mode: write_mode(0) failed\n"); ++ return 0; ++ } + +- do { +- keyboard_controller_wait_until_ready (); +- ret = grub_inb (KEYBOARD_REG_DATA); +- } while (ret == GRUB_AT_ACK); +- /* QEMU translates the set even in no-translate mode. */ +- if (ret == 0x43 || ret == 1) { +- grub_dprintf("atkeyb", "query_mode: returning 1 (ret=0x%x)\n", ret); +- return 1; +- } +- if (ret == 0x41 || ret == 2) { +- grub_dprintf("atkeyb", "query_mode: returning 2 (ret=0x%x)\n", ret); +- return 2; ++ endtime = grub_get_time_ms () + 20; ++ do { ++ keyboard_controller_wait_until_ready (); ++ ret = grub_inb (KEYBOARD_REG_DATA); ++ grub_dprintf ("atkeyb", "query_mode/loop: read 0x%x from controller\n", ret); ++ } while ((ret == GRUB_AT_ACK || ret == GRUB_AT_NACK) && grub_get_time_ms () < endtime); ++ if (ret == 0xfe) { ++ grub_dprintf ("atkeyb", "query_mode: asking controller to resend last result\n"); ++ ret = resend_last_result(); ++ grub_dprintf ("atkeyb", "query_mode: read 0x%x from controller\n", ret); ++ } ++ /* QEMU translates the set even in no-translate mode. */ ++ if (ret == 0x43 || ret == 1) { ++ grub_dprintf ("atkeyb", "query_mode: controller returned 0x%x, returning 1\n", ret); ++ return 1; ++ } ++ if (ret == 0x41 || ret == 2) { ++ grub_dprintf ("atkeyb", "query_mode: controller returned 0x%x, returning 2\n", ret); ++ return 2; ++ } ++ if (ret == 0x3f || ret == 3) { ++ grub_dprintf ("atkeyb", "query_mode: controller returned 0x%x, returning 3\n", ret); ++ return 3; ++ } ++ grub_dprintf ("atkeyb", "query_mode: controller returned unexpected value 0x%x, retrying\n", ret); + } +- if (ret == 0x3f || ret == 3) { +- grub_dprintf("atkeyb", "query_mode: returning 3 (ret=0x%x)\n", ret); +- return 3; ++ ++ /* ++ * Falling here means we tried querying and the controller returned something ++ * we don't understand, try to use 'at_keyboard_fallback_set' if it exists, ++ * otherwise return 0. ++ */ ++ envvar = grub_env_get ("at_keyboard_fallback_set"); ++ if (envvar) { ++ fallback_set = grub_strtoul (envvar, 0, 10); ++ if ((grub_errno) || (fallback_set < 1) || (fallback_set > 3)) { ++ grub_dprintf ("atkeyb", "WARNING: ignoring unexpected value '%s' for '%s' variable\n", ++ envvar, "at_keyboard_fallback_set"); ++ fallback_set = 0; ++ } else { ++ grub_dprintf ("atkeyb", "query_mode: '%s' specified in environment, returning %d\n", ++ "at_keyboard_fallback_set", fallback_set); ++ } ++ return fallback_set; + } ++ grub_dprintf ("atkeyb", "WARNING: no '%s' specified in environment, returning 0\n", ++ "at_keyboard_fallback_set"); + return 0; + } + +@@ -165,14 +224,25 @@ set_scancodes (void) + { + /* You must have visited computer museum. Keyboard without scancode set + knowledge. Assume XT. */ +- if (!grub_keyboard_orig_set) +- { +- grub_dprintf ("atkeyb", "No sets support assumed\n"); +- ps2_state.current_set = 1; ++ if (!grub_keyboard_orig_set) { ++ if (fallback_set) { ++ grub_dprintf ("atkeyb", "No sets support assumed but set forced to %d\n", fallback_set); ++ ps2_state.current_set = fallback_set; + return; + } ++ grub_dprintf ("atkeyb", "No sets support assumed, forcing to set 1\n"); ++ ps2_state.current_set = 1; ++ return; ++ } + + #if !USE_SCANCODE_SET ++ if (fallback_set) { ++ grub_dprintf ("atkeyb", "queried set is %d but set forced to %d\n", ++ grub_keyboard_orig_set, fallback_set); ++ ps2_state.current_set = fallback_set; ++ return; ++ } ++ + if ((grub_keyboard_controller_orig & KEYBOARD_AT_TRANSLATE) == KEYBOARD_AT_TRANSLATE) { + grub_dprintf ("atkeyb", "queried set is %d but keyboard in Translate mode, so actually in set 1\n", grub_keyboard_orig_set); + ps2_state.current_set = 1; +@@ -261,6 +331,7 @@ grub_at_keyboard_getkey (struct grub_term_input *term __attribute__ ((unused))) + static void + grub_keyboard_controller_init (void) + { ++ grub_dprintf ("atkeyb", "initializing the controller\n"); + ps2_state.at_keyboard_status = 0; + /* Drain input buffer. */ + while (1) +@@ -282,6 +353,7 @@ grub_keyboard_controller_init (void) + grub_keyboard_controller_orig = grub_keyboard_controller_read (); + grub_dprintf ("atkeyb", "grub_keyboard_controller_orig = 0x%x\n", grub_keyboard_controller_orig); + grub_keyboard_orig_set = query_mode (); ++ grub_dprintf ("atkeyb", "grub_keyboard_orig_set = %d\n", grub_keyboard_orig_set); + #endif + set_scancodes (); + keyboard_controller_led (ps2_state.led_status); +@@ -329,7 +401,6 @@ grub_at_restore_hw (void) + return GRUB_ERR_NONE; + } + +- + static struct grub_term_input grub_at_keyboard_term = + { + .name = "at_keyboard", diff --git a/SOURCES/0328-loader-xnu-Don-t-allow-loading-extension-and-package.patch b/SOURCES/0328-loader-xnu-Don-t-allow-loading-extension-and-package.patch deleted file mode 100644 index 8ccc433..0000000 --- a/SOURCES/0328-loader-xnu-Don-t-allow-loading-extension-and-package.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Wed, 24 Feb 2021 14:44:38 +0100 -Subject: [PATCH] loader/xnu: Don't allow loading extension and packages when - locked down - -The shim_lock verifier validates the XNU kernels but no its extensions -and packages. Prevent these to be loaded when the GRUB is locked down. - -Signed-off-by: Javier Martinez Canillas -Reviewed-by: Daniel Kiper ---- - grub-core/loader/xnu.c | 31 +++++++++++++++++-------------- - 1 file changed, 17 insertions(+), 14 deletions(-) - -diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c -index 2bf02489bad..0c4b33250fb 100644 ---- a/grub-core/loader/xnu.c -+++ b/grub-core/loader/xnu.c -@@ -1480,20 +1480,23 @@ GRUB_MOD_INIT(xnu) - N_("Load XNU image.")); - cmd_kernel64 = grub_register_command ("xnu_kernel64", grub_cmd_xnu_kernel64, - 0, N_("Load 64-bit XNU image.")); -- cmd_mkext = grub_register_command ("xnu_mkext", grub_cmd_xnu_mkext, 0, -- N_("Load XNU extension package.")); -- cmd_kext = grub_register_command ("xnu_kext", grub_cmd_xnu_kext, 0, -- N_("Load XNU extension.")); -- cmd_kextdir = grub_register_command ("xnu_kextdir", grub_cmd_xnu_kextdir, -- /* TRANSLATORS: OSBundleRequired is a -- variable name in xnu extensions -- manifests. It behaves mostly like -- GNU/Linux runlevels. -- */ -- N_("DIRECTORY [OSBundleRequired]"), -- /* TRANSLATORS: There are many extensions -- in extension directory. */ -- N_("Load XNU extension directory.")); -+ cmd_mkext = grub_register_command_lockdown ("xnu_mkext", grub_cmd_xnu_mkext, 0, -+ N_("Load XNU extension package.")); -+ cmd_kext = grub_register_command_lockdown ("xnu_kext", grub_cmd_xnu_kext, 0, -+ N_("Load XNU extension.")); -+ cmd_kextdir = grub_register_command_lockdown ("xnu_kextdir", grub_cmd_xnu_kextdir, -+ /* -+ * TRANSLATORS: OSBundleRequired is -+ * a variable name in xnu extensions -+ * manifests. It behaves mostly like -+ * GNU/Linux runlevels. -+ */ -+ N_("DIRECTORY [OSBundleRequired]"), -+ /* -+ * TRANSLATORS: There are many extensions -+ * in extension directory. -+ */ -+ N_("Load XNU extension directory.")); - cmd_ramdisk = grub_register_command ("xnu_ramdisk", grub_cmd_xnu_ramdisk, 0, - /* TRANSLATORS: ramdisk here isn't identifier. It can be translated. */ - N_("Load XNU ramdisk. " diff --git a/SOURCES/0329-bufio-Use-grub_size_t-instead-of-plain-int-for-size.patch b/SOURCES/0329-bufio-Use-grub_size_t-instead-of-plain-int-for-size.patch new file mode 100644 index 0000000..2d35cc8 --- /dev/null +++ b/SOURCES/0329-bufio-Use-grub_size_t-instead-of-plain-int-for-size.patch @@ -0,0 +1,60 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Kiper +Date: Mon, 29 Oct 2018 13:25:25 +0100 +Subject: [PATCH] bufio: Use grub_size_t instead of plain int for size + +Signed-off-by: Vladimir Serbinenko +Signed-off-by: Daniel Kiper +Reviewed-by: Ross Philipson +(cherry picked from commit f3f8347569383e7f483f37ca70d41eb1af9f990f) +Signed-off-by: Daniel Axtens +--- + grub-core/io/bufio.c | 6 +++--- + include/grub/bufio.h | 4 ++-- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/grub-core/io/bufio.c b/grub-core/io/bufio.c +index 6118bade50d..2781afe0515 100644 +--- a/grub-core/io/bufio.c ++++ b/grub-core/io/bufio.c +@@ -43,7 +43,7 @@ typedef struct grub_bufio *grub_bufio_t; + static struct grub_fs grub_bufio_fs; + + grub_file_t +-grub_bufio_open (grub_file_t io, int size) ++grub_bufio_open (grub_file_t io, grub_size_t size) + { + grub_file_t file; + grub_bufio_t bufio = 0; +@@ -57,7 +57,7 @@ grub_bufio_open (grub_file_t io, int size) + else if (size > GRUB_BUFIO_MAX_SIZE) + size = GRUB_BUFIO_MAX_SIZE; + +- if ((size < 0) || ((unsigned) size > io->size)) ++ if (size > io->size) + size = ((io->size > GRUB_BUFIO_MAX_SIZE) ? GRUB_BUFIO_MAX_SIZE : + io->size); + +@@ -88,7 +88,7 @@ grub_bufio_open (grub_file_t io, int size) + } + + grub_file_t +-grub_buffile_open (const char *name, int size) ++grub_buffile_open (const char *name, grub_size_t size) + { + grub_file_t io, file; + +diff --git a/include/grub/bufio.h b/include/grub/bufio.h +index acdd0c882c6..77eb8ee5672 100644 +--- a/include/grub/bufio.h ++++ b/include/grub/bufio.h +@@ -22,7 +22,7 @@ + + #include + +-grub_file_t EXPORT_FUNC (grub_bufio_open) (grub_file_t io, int size); +-grub_file_t EXPORT_FUNC (grub_buffile_open) (const char *name, int size); ++grub_file_t EXPORT_FUNC (grub_bufio_open) (grub_file_t io, grub_size_t size); ++grub_file_t EXPORT_FUNC (grub_buffile_open) (const char *name, grub_size_t size); + + #endif /* ! GRUB_BUFIO_H */ diff --git a/SOURCES/0329-docs-Document-the-cutmem-command.patch b/SOURCES/0329-docs-Document-the-cutmem-command.patch deleted file mode 100644 index d199a34..0000000 --- a/SOURCES/0329-docs-Document-the-cutmem-command.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Sat, 7 Nov 2020 01:03:18 +0100 -Subject: [PATCH] docs: Document the cutmem command - -The command is not present in the docs/grub.texi user documentation. - -Reported-by: Daniel Kiper -Signed-off-by: Javier Martinez Canillas -Signed-off-by: Daniel Kiper -Reviewed-by: Javier Martinez Canillas ---- - docs/grub.texi | 21 +++++++++++++++++++++ - 1 file changed, 21 insertions(+) - -diff --git a/docs/grub.texi b/docs/grub.texi -index 71943b15dd1..067aa294162 100644 ---- a/docs/grub.texi -+++ b/docs/grub.texi -@@ -3941,6 +3941,7 @@ you forget a command, you can run the command @command{help} - * cpuid:: Check for CPU features - * crc:: Compute or check CRC32 checksums - * cryptomount:: Mount a crypto device -+* cutmem:: Remove memory regions - * date:: Display or set current date and time - * devicetree:: Load a device tree blob - * distrust:: Remove a pubkey from trusted keys -@@ -4098,6 +4099,8 @@ this page is to be filtered. This syntax makes it easy to represent patterns - that are often result of memory damage, due to physical distribution of memory - cells. - -+The command is similar to @command{cutmem} command. -+ - Note: The command is not allowed when lockdown is enforced (@pxref{Lockdown}). - This prevents removing EFI memory regions to potentially subvert the - security mechanisms provided by the UEFI secure boot. -@@ -4261,6 +4264,24 @@ GRUB suports devices encrypted using LUKS and geli. Note that necessary modules - be used. - @end deffn - -+@node cutmem -+@subsection cutmem -+ -+@deffn Command cutmem from[K|M|G] to[K|M|G] -+Remove any memory regions in specified range. -+@end deffn -+ -+This command notifies the memory manager that specified regions of RAM ought to -+be filtered out. This remains in effect after a payload kernel has been loaded -+by GRUB, as long as the loaded kernel obtains its memory map from GRUB. Kernels -+that support this include Linux, GNU Mach, the kernel of FreeBSD and Multiboot -+kernels in general. -+ -+The command is similar to @command{badram} command. -+ -+Note: The command is not allowed when lockdown is enforced (@pxref{Lockdown}). -+ This prevents removing EFI memory regions to potentially subvert the -+ security mechanisms provided by the UEFI secure boot. - - @node date - @subsection date diff --git a/SOURCES/0330-dl-Only-allow-unloading-modules-that-are-not-depende.patch b/SOURCES/0330-dl-Only-allow-unloading-modules-that-are-not-depende.patch deleted file mode 100644 index b96552b..0000000 --- a/SOURCES/0330-dl-Only-allow-unloading-modules-that-are-not-depende.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Tue, 29 Sep 2020 14:08:55 +0200 -Subject: [PATCH] dl: Only allow unloading modules that are not dependencies - -When a module is attempted to be removed its reference counter is always -decremented. This means that repeated rmmod invocations will cause the -module to be unloaded even if another module depends on it. - -This may lead to a use-after-free scenario allowing an attacker to execute -arbitrary code and by-pass the UEFI Secure Boot protection. - -While being there, add the extern keyword to some function declarations in -that header file. - -Fixes: CVE-2020-25632 - -Reported-by: Chris Coulson -Signed-off-by: Javier Martinez Canillas -Reviewed-by: Daniel Kiper ---- - grub-core/commands/minicmd.c | 7 +++++-- - grub-core/kern/dl.c | 9 +++++++++ - include/grub/dl.h | 8 +++++--- - 3 files changed, 19 insertions(+), 5 deletions(-) - -diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c -index b25ca4b9f17..4660a020bda 100644 ---- a/grub-core/commands/minicmd.c -+++ b/grub-core/commands/minicmd.c -@@ -137,8 +137,11 @@ grub_mini_cmd_rmmod (struct grub_command *cmd __attribute__ ((unused)), - if (! mod) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such module"); - -- if (grub_dl_unref (mod) <= 0) -- grub_dl_unload (mod); -+ if (grub_dl_ref_count (mod) > 1) -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "cannot unload referenced module"); -+ -+ grub_dl_unref (mod); -+ grub_dl_unload (mod); - - return 0; - } -diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c -index 91105bc4677..333c1329eab 100644 ---- a/grub-core/kern/dl.c -+++ b/grub-core/kern/dl.c -@@ -621,6 +621,15 @@ grub_dl_unref (grub_dl_t mod) - return --mod->ref_count; - } - -+int -+grub_dl_ref_count (grub_dl_t mod) -+{ -+ if (mod == NULL) -+ return 0; -+ -+ return mod->ref_count; -+} -+ - static void - grub_dl_flush_cache (grub_dl_t mod) - { -diff --git a/include/grub/dl.h b/include/grub/dl.h -index 7b5bfb07ce6..a58fbc767c0 100644 ---- a/include/grub/dl.h -+++ b/include/grub/dl.h -@@ -204,9 +204,11 @@ grub_dl_t EXPORT_FUNC(grub_dl_load) (const char *name); - grub_dl_t grub_dl_load_core (void *addr, grub_size_t size); - grub_dl_t EXPORT_FUNC(grub_dl_load_core_noinit) (void *addr, grub_size_t size); - int EXPORT_FUNC(grub_dl_unload) (grub_dl_t mod); --void grub_dl_unload_unneeded (void); --int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod); --int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod); -+extern void grub_dl_unload_unneeded (void); -+extern int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod); -+extern int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod); -+extern int EXPORT_FUNC(grub_dl_ref_count) (grub_dl_t mod); -+ - extern grub_dl_t EXPORT_VAR(grub_dl_head); - - #ifndef GRUB_UTIL diff --git a/SOURCES/0330-verifiers-File-type-for-fine-grained-signature-verif.patch b/SOURCES/0330-verifiers-File-type-for-fine-grained-signature-verif.patch new file mode 100644 index 0000000..12baee2 --- /dev/null +++ b/SOURCES/0330-verifiers-File-type-for-fine-grained-signature-verif.patch @@ -0,0 +1,1738 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Vladimir Serbinenko +Date: Wed, 20 Nov 2013 02:28:29 +0100 +Subject: [PATCH] verifiers: File type for fine-grained signature-verification + controlling + +Let's provide file type info to the I/O layer. This way verifiers +framework and its users will be able to differentiate files and verify +only required ones. + +This is preparatory patch. + +Signed-off-by: Vladimir Serbinenko +Signed-off-by: Daniel Kiper +Reviewed-by: Ross Philipson +(backported from commit ca0a4f689a02c2c5a5e385f874aaaa38e151564e) +Signed-off-by: Daniel Axtens +--- + grub-core/commands/acpi.c | 2 +- + grub-core/commands/blocklist.c | 4 +- + grub-core/commands/cat.c | 2 +- + grub-core/commands/cmp.c | 4 +- + grub-core/commands/efi/loadbios.c | 4 +- + grub-core/commands/file.c | 5 +- + grub-core/commands/hashsum.c | 22 ++-- + grub-core/commands/hexdump.c | 2 +- + grub-core/commands/i386/pc/play.c | 2 +- + grub-core/commands/keylayouts.c | 2 +- + grub-core/commands/legacycfg.c | 2 +- + grub-core/commands/loadenv.c | 24 +++-- + grub-core/commands/ls.c | 8 +- + grub-core/commands/minicmd.c | 2 +- + grub-core/commands/nativedisk.c | 3 +- + grub-core/commands/parttool.c | 2 +- + grub-core/commands/search.c | 4 +- + grub-core/commands/test.c | 4 +- + grub-core/commands/testload.c | 2 +- + grub-core/commands/testspeed.c | 2 +- + grub-core/commands/verify.c | 51 ++++----- + grub-core/disk/loopback.c | 3 +- + grub-core/efiemu/main.c | 2 +- + grub-core/font/font.c | 4 +- + grub-core/fs/zfs/zfscrypt.c | 2 +- + grub-core/gettext/gettext.c | 2 +- + grub-core/gfxmenu/theme_loader.c | 2 +- + grub-core/io/bufio.c | 4 +- + grub-core/io/gzio.c | 5 +- + grub-core/io/lzopio.c | 6 +- + grub-core/io/offset.c | 7 +- + grub-core/io/xzio.c | 6 +- + grub-core/kern/dl.c | 2 +- + grub-core/kern/elf.c | 4 +- + grub-core/kern/file.c | 22 ++-- + grub-core/lib/syslinux_parse.c | 2 +- + grub-core/loader/efi/chainloader.c | 2 +- + grub-core/loader/i386/bsd.c | 16 +-- + grub-core/loader/i386/coreboot/chainloader.c | 2 +- + grub-core/loader/i386/linux.c | 2 +- + grub-core/loader/i386/pc/chainloader.c | 4 +- + grub-core/loader/i386/pc/freedos.c | 2 +- + grub-core/loader/i386/pc/linux.c | 2 +- + grub-core/loader/i386/pc/ntldr.c | 2 +- + grub-core/loader/i386/pc/plan9.c | 2 +- + grub-core/loader/i386/pc/pxechainloader.c | 2 +- + grub-core/loader/i386/pc/truecrypt.c | 2 +- + grub-core/loader/i386/xen.c | 7 +- + grub-core/loader/i386/xen_file.c | 2 +- + grub-core/loader/i386/xnu.c | 2 +- + grub-core/loader/linux.c | 6 +- + grub-core/loader/macho.c | 4 +- + grub-core/loader/mips/linux.c | 2 +- + grub-core/loader/multiboot.c | 8 +- + grub-core/loader/xnu.c | 16 +-- + grub-core/loader/xnu_resume.c | 4 +- + grub-core/normal/autofs.c | 11 +- + grub-core/normal/crypto.c | 2 +- + grub-core/normal/dyncmd.c | 2 +- + grub-core/normal/main.c | 2 +- + grub-core/normal/term.c | 2 +- + grub-core/video/readers/jpeg.c | 2 +- + grub-core/video/readers/png.c | 2 +- + grub-core/video/readers/tga.c | 2 +- + util/grub-fstest.c | 6 +- + util/grub-mount.c | 6 +- + include/grub/bufio.h | 4 +- + include/grub/elfload.h | 2 +- + include/grub/file.h | 152 +++++++++++++++++++-------- + include/grub/machoload.h | 3 +- + 70 files changed, 292 insertions(+), 221 deletions(-) + +diff --git a/grub-core/commands/acpi.c b/grub-core/commands/acpi.c +index 9f02f22019a..5a1499aa0e3 100644 +--- a/grub-core/commands/acpi.c ++++ b/grub-core/commands/acpi.c +@@ -635,7 +635,7 @@ grub_cmd_acpi (struct grub_extcmd_context *ctxt, int argc, char **args) + grub_size_t size; + char *buf; + +- file = grub_file_open (args[i]); ++ file = grub_file_open (args[i], GRUB_FILE_TYPE_ACPI_TABLE); + if (! file) + { + free_tables (); +diff --git a/grub-core/commands/blocklist.c b/grub-core/commands/blocklist.c +index d1a47b504bf..944449b77d4 100644 +--- a/grub-core/commands/blocklist.c ++++ b/grub-core/commands/blocklist.c +@@ -121,8 +121,8 @@ grub_cmd_blocklist (grub_command_t cmd __attribute__ ((unused)), + if (argc < 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + +- grub_file_filter_disable_compression (); +- file = grub_file_open (args[0]); ++ file = grub_file_open (args[0], GRUB_FILE_TYPE_PRINT_BLOCKLIST ++ | GRUB_FILE_TYPE_NO_DECOMPRESS); + if (! file) + return grub_errno; + +diff --git a/grub-core/commands/cat.c b/grub-core/commands/cat.c +index 88d90443602..ba5f0061aa5 100644 +--- a/grub-core/commands/cat.c ++++ b/grub-core/commands/cat.c +@@ -56,7 +56,7 @@ grub_cmd_cat (grub_extcmd_context_t ctxt, int argc, char **args) + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + +- file = grub_file_open (args[0]); ++ file = grub_file_open (args[0], GRUB_FILE_TYPE_CAT); + if (! file) + return grub_errno; + +diff --git a/grub-core/commands/cmp.c b/grub-core/commands/cmp.c +index cc23ee67ea3..e9c3b25d34c 100644 +--- a/grub-core/commands/cmp.c ++++ b/grub-core/commands/cmp.c +@@ -45,8 +45,8 @@ grub_cmd_cmp (grub_command_t cmd __attribute__ ((unused)), + grub_printf_ (N_("Compare file `%s' with `%s':\n"), args[0], + args[1]); + +- file1 = grub_file_open (args[0]); +- file2 = grub_file_open (args[1]); ++ file1 = grub_file_open (args[0], GRUB_FILE_TYPE_CMP); ++ file2 = grub_file_open (args[1], GRUB_FILE_TYPE_CMP); + if (! file1 || ! file2) + goto cleanup; + +diff --git a/grub-core/commands/efi/loadbios.c b/grub-core/commands/efi/loadbios.c +index 132cadbc764..d41d521a4ae 100644 +--- a/grub-core/commands/efi/loadbios.c ++++ b/grub-core/commands/efi/loadbios.c +@@ -169,7 +169,7 @@ grub_cmd_loadbios (grub_command_t cmd __attribute__ ((unused)), + + if (argc > 1) + { +- file = grub_file_open (argv[1]); ++ file = grub_file_open (argv[1], GRUB_FILE_TYPE_VBE_DUMP); + if (! file) + return grub_errno; + +@@ -183,7 +183,7 @@ grub_cmd_loadbios (grub_command_t cmd __attribute__ ((unused)), + return grub_errno; + } + +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_VBE_DUMP); + if (! file) + return grub_errno; + +diff --git a/grub-core/commands/file.c b/grub-core/commands/file.c +index 3ff6d5522d2..4f81aa1f9e1 100644 +--- a/grub-core/commands/file.c ++++ b/grub-core/commands/file.c +@@ -165,7 +165,7 @@ grub_cmd_file (grub_extcmd_context_t ctxt, int argc, char **args) + if (type == -1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no type specified"); + +- file = grub_file_open (args[0]); ++ file = grub_file_open (args[0], GRUB_FILE_TYPE_XNU_KERNEL); + if (!file) + return grub_errno; + switch (type) +@@ -546,7 +546,8 @@ grub_cmd_file (grub_extcmd_context_t ctxt, int argc, char **args) + case IS_XNU64: + case IS_XNU32: + { +- macho = grub_macho_open (args[0], (type == IS_XNU64)); ++ macho = grub_macho_open (args[0], GRUB_FILE_TYPE_XNU_KERNEL, ++ (type == IS_XNU64)); + if (!macho) + break; + /* FIXME: more checks? */ +diff --git a/grub-core/commands/hashsum.c b/grub-core/commands/hashsum.c +index d18687351a5..456ba908b6f 100644 +--- a/grub-core/commands/hashsum.c ++++ b/grub-core/commands/hashsum.c +@@ -113,7 +113,7 @@ check_list (const gcry_md_spec_t *hash, const char *hashfilename, + if (hash->mdlen > GRUB_CRYPTO_MAX_MDLEN) + return grub_error (GRUB_ERR_BUG, "mdlen is too long"); + +- hashlist = grub_file_open (hashfilename); ++ hashlist = grub_file_open (hashfilename, GRUB_FILE_TYPE_HASHLIST); + if (!hashlist) + return grub_errno; + +@@ -141,17 +141,15 @@ check_list (const gcry_md_spec_t *hash, const char *hashfilename, + filename = grub_xasprintf ("%s/%s", prefix, p); + if (!filename) + return grub_errno; +- if (!uncompress) +- grub_file_filter_disable_compression (); +- file = grub_file_open (filename); ++ file = grub_file_open (filename, GRUB_FILE_TYPE_TO_HASH ++ | (!uncompress ? GRUB_FILE_TYPE_NO_DECOMPRESS ++ : GRUB_FILE_TYPE_NONE)); + grub_free (filename); + } + else +- { +- if (!uncompress) +- grub_file_filter_disable_compression (); +- file = grub_file_open (p); +- } ++ file = grub_file_open (p, GRUB_FILE_TYPE_TO_HASH ++ | (!uncompress ? GRUB_FILE_TYPE_NO_DECOMPRESS ++ : GRUB_FILE_TYPE_NONE)); + if (!file) + { + grub_file_close (hashlist); +@@ -242,9 +240,9 @@ grub_cmd_hashsum (struct grub_extcmd_context *ctxt, + grub_file_t file; + grub_err_t err; + unsigned j; +- if (!uncompress) +- grub_file_filter_disable_compression (); +- file = grub_file_open (args[i]); ++ file = grub_file_open (args[i], GRUB_FILE_TYPE_TO_HASH ++ | (!uncompress ? GRUB_FILE_TYPE_NO_DECOMPRESS ++ : GRUB_FILE_TYPE_NONE)); + if (!file) + { + if (!keep) +diff --git a/grub-core/commands/hexdump.c b/grub-core/commands/hexdump.c +index 4c884b3a19a..eaa12465bb3 100644 +--- a/grub-core/commands/hexdump.c ++++ b/grub-core/commands/hexdump.c +@@ -90,7 +90,7 @@ grub_cmd_hexdump (grub_extcmd_context_t ctxt, int argc, char **args) + { + grub_file_t file; + +- file = grub_file_open (args[0]); ++ file = grub_file_open (args[0], GRUB_FILE_TYPE_HEXCAT); + if (! file) + return 0; + +diff --git a/grub-core/commands/i386/pc/play.c b/grub-core/commands/i386/pc/play.c +index 7712e2a36a1..c8181310515 100644 +--- a/grub-core/commands/i386/pc/play.c ++++ b/grub-core/commands/i386/pc/play.c +@@ -93,7 +93,7 @@ grub_cmd_play (grub_command_t cmd __attribute__ ((unused)), + grub_uint32_t tempo; + grub_file_t file; + +- file = grub_file_open (args[0]); ++ file = grub_file_open (args[0], GRUB_FILE_TYPE_AUDIO); + + if (! file) + return grub_errno; +diff --git a/grub-core/commands/keylayouts.c b/grub-core/commands/keylayouts.c +index f35d3a369ba..c05d6128a6d 100644 +--- a/grub-core/commands/keylayouts.c ++++ b/grub-core/commands/keylayouts.c +@@ -220,7 +220,7 @@ grub_cmd_keymap (struct grub_command *cmd __attribute__ ((unused)), + else + filename = argv[0]; + +- file = grub_file_open (filename); ++ file = grub_file_open (filename, GRUB_FILE_TYPE_KEYBOARD_LAYOUT); + if (! file) + goto fail; + +diff --git a/grub-core/commands/legacycfg.c b/grub-core/commands/legacycfg.c +index 0de070eacc4..f5696a51a75 100644 +--- a/grub-core/commands/legacycfg.c ++++ b/grub-core/commands/legacycfg.c +@@ -56,7 +56,7 @@ legacy_file (const char *filename) + if (!suffix) + return grub_errno; + +- file = grub_file_open (filename); ++ file = grub_file_open (filename, GRUB_FILE_TYPE_CONFIG); + if (! file) + { + grub_free (suffix); +diff --git a/grub-core/commands/loadenv.c b/grub-core/commands/loadenv.c +index 91c99456091..163b9a09042 100644 +--- a/grub-core/commands/loadenv.c ++++ b/grub-core/commands/loadenv.c +@@ -46,7 +46,8 @@ static const struct grub_arg_option options[] = + PUBKEY filter (that insists upon properly signed files) as well. PUBKEY + filter is restored before the function returns. */ + static grub_file_t +-open_envblk_file (char *filename, int untrusted) ++open_envblk_file (char *filename, ++ enum grub_file_type type) + { + grub_file_t file; + char *buf = 0; +@@ -74,13 +75,7 @@ open_envblk_file (char *filename, int untrusted) + grub_strcpy (filename + len + 1, GRUB_ENVBLK_DEFCFG); + } + +- /* The filters that are disabled will be re-enabled by the call to +- grub_file_open() after this particular file is opened. */ +- grub_file_filter_disable_compression (); +- if (untrusted) +- grub_file_filter_disable_pubkey (); +- +- file = grub_file_open (filename); ++ file = grub_file_open (filename, type); + + grub_free (buf); + return file; +@@ -98,7 +93,10 @@ grub_cmd_load_env (grub_extcmd_context_t ctxt, int argc, char **args) + whitelist.list = args; + + /* state[0] is the -f flag; state[1] is the --skip-sig flag */ +- file = open_envblk_file ((state[0].set) ? state[0].arg : 0, state[1].set); ++ file = open_envblk_file ((state[0].set) ? state[0].arg : 0, ++ GRUB_FILE_TYPE_LOADENV ++ | (state[1].set ++ ? GRUB_FILE_TYPE_SKIP_SIGNATURE : GRUB_FILE_TYPE_NONE)); + if (! file) + return grub_errno; + +@@ -133,7 +131,10 @@ grub_cmd_list_env (grub_extcmd_context_t ctxt, + grub_file_t file; + grub_envblk_t envblk; + +- file = open_envblk_file ((state[0].set) ? state[0].arg : 0, 0); ++ file = open_envblk_file ((state[0].set) ? state[0].arg : 0, ++ GRUB_FILE_TYPE_LOADENV ++ | (state[1].set ++ ? GRUB_FILE_TYPE_SKIP_SIGNATURE : GRUB_FILE_TYPE_NONE)); + if (! file) + return grub_errno; + +@@ -317,7 +318,8 @@ grub_cmd_save_env (grub_extcmd_context_t ctxt, int argc, char **args) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no variable is specified"); + + file = open_envblk_file ((state[0].set) ? state[0].arg : 0, +- 1 /* allow untrusted */); ++ GRUB_FILE_TYPE_SAVEENV ++ | GRUB_FILE_TYPE_SKIP_SIGNATURE); + if (! file) + return grub_errno; + +diff --git a/grub-core/commands/ls.c b/grub-core/commands/ls.c +index c25161cc4f2..2cdb2acc552 100644 +--- a/grub-core/commands/ls.c ++++ b/grub-core/commands/ls.c +@@ -129,8 +129,8 @@ print_files_long (const char *filename, const struct grub_dirhook_info *info, + + /* XXX: For ext2fs symlinks are detected as files while they + should be reported as directories. */ +- grub_file_filter_disable_compression (); +- file = grub_file_open (pathname); ++ file = grub_file_open (pathname, GRUB_FILE_TYPE_GET_SIZE ++ | GRUB_FILE_TYPE_NO_DECOMPRESS); + if (! file) + { + grub_errno = 0; +@@ -234,8 +234,8 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human) + struct grub_dirhook_info info; + grub_errno = 0; + +- grub_file_filter_disable_compression (); +- file = grub_file_open (dirname); ++ file = grub_file_open (dirname, GRUB_FILE_TYPE_GET_SIZE ++ | GRUB_FILE_TYPE_NO_DECOMPRESS); + if (! file) + goto fail; + +diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c +index b25ca4b9f17..46bf135e8f0 100644 +--- a/grub-core/commands/minicmd.c ++++ b/grub-core/commands/minicmd.c +@@ -43,7 +43,7 @@ grub_mini_cmd_cat (struct grub_command *cmd __attribute__ ((unused)), + if (argc < 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_CAT); + if (! file) + return grub_errno; + +diff --git a/grub-core/commands/nativedisk.c b/grub-core/commands/nativedisk.c +index d69214f6de0..f200a5ce092 100644 +--- a/grub-core/commands/nativedisk.c ++++ b/grub-core/commands/nativedisk.c +@@ -242,7 +242,8 @@ grub_cmd_nativedisk (grub_command_t cmd __attribute__ ((unused)), + if (! filename) + goto fail; + +- file = grub_file_open (filename); ++ file = grub_file_open (filename, ++ GRUB_FILE_TYPE_GRUB_MODULE); + grub_free (filename); + if (! file) + goto fail; +diff --git a/grub-core/commands/parttool.c b/grub-core/commands/parttool.c +index 36dadc0b1db..051e31320e9 100644 +--- a/grub-core/commands/parttool.c ++++ b/grub-core/commands/parttool.c +@@ -199,7 +199,7 @@ grub_cmd_parttool (grub_command_t cmd __attribute__ ((unused)), + { + grub_file_t file; + +- file = grub_file_open (filename); ++ file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE_LIST); + if (file) + { + char *buf = 0; +diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c +index 7dd32e445c9..ddda6e7c590 100644 +--- a/grub-core/commands/search.c ++++ b/grub-core/commands/search.c +@@ -81,8 +81,8 @@ iterate_device (const char *name, void *data) + if (! buf) + return 1; + +- grub_file_filter_disable_compression (); +- file = grub_file_open (buf); ++ file = grub_file_open (buf, GRUB_FILE_TYPE_FS_SEARCH ++ | GRUB_FILE_TYPE_NO_DECOMPRESS); + if (file) + { + found = 1; +diff --git a/grub-core/commands/test.c b/grub-core/commands/test.c +index 5f06642f6c6..13c6ed9534a 100644 +--- a/grub-core/commands/test.c ++++ b/grub-core/commands/test.c +@@ -355,8 +355,8 @@ test_parse (char **args, int *argn, int argc) + if (grub_strcmp (args[*argn], "-s") == 0) + { + grub_file_t file; +- grub_file_filter_disable_compression (); +- file = grub_file_open (args[*argn + 1]); ++ file = grub_file_open (args[*argn + 1], GRUB_FILE_TYPE_GET_SIZE ++ | GRUB_FILE_TYPE_NO_DECOMPRESS); + update_val (file && (grub_file_size (file) != 0), &ctx); + if (file) + grub_file_close (file); +diff --git a/grub-core/commands/testload.c b/grub-core/commands/testload.c +index cfab6763dc3..ff01a0516dd 100644 +--- a/grub-core/commands/testload.c ++++ b/grub-core/commands/testload.c +@@ -57,7 +57,7 @@ grub_cmd_testload (struct grub_command *cmd __attribute__ ((unused)), + if (argc < 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_TESTLOAD); + if (! file) + return grub_errno; + +diff --git a/grub-core/commands/testspeed.c b/grub-core/commands/testspeed.c +index 042645f8d26..c13a9b8d8d2 100644 +--- a/grub-core/commands/testspeed.c ++++ b/grub-core/commands/testspeed.c +@@ -61,7 +61,7 @@ grub_cmd_testspeed (grub_extcmd_context_t ctxt, int argc, char **args) + if (buffer == NULL) + return grub_errno; + +- file = grub_file_open (args[0]); ++ file = grub_file_open (args[0], GRUB_FILE_TYPE_TESTLOAD); + if (file == NULL) + goto quit; + +diff --git a/grub-core/commands/verify.c b/grub-core/commands/verify.c +index 67cb1c78509..f0dfeceebd4 100644 +--- a/grub-core/commands/verify.c ++++ b/grub-core/commands/verify.c +@@ -680,10 +680,12 @@ grub_cmd_trust (grub_extcmd_context_t ctxt, + if (argc < 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); + +- grub_file_filter_disable_compression (); +- if (ctxt->state[OPTION_SKIP_SIG].set) +- grub_file_filter_disable_pubkey (); +- pkf = grub_file_open (args[0]); ++ pkf = grub_file_open (args[0], ++ GRUB_FILE_TYPE_PUBLIC_KEY_TRUST ++ | GRUB_FILE_TYPE_NO_DECOMPRESS ++ | (ctxt->state[OPTION_SKIP_SIG].set ++ ? GRUB_FILE_TYPE_SKIP_SIGNATURE ++ : GRUB_FILE_TYPE_NONE)); + if (!pkf) + return grub_errno; + pk = grub_load_public_key (pkf); +@@ -771,10 +773,12 @@ grub_cmd_verify_signature (grub_extcmd_context_t ctxt, + if (argc > 2) + { + grub_file_t pkf; +- grub_file_filter_disable_compression (); +- if (ctxt->state[OPTION_SKIP_SIG].set) +- grub_file_filter_disable_pubkey (); +- pkf = grub_file_open (args[2]); ++ pkf = grub_file_open (args[2], ++ GRUB_FILE_TYPE_PUBLIC_KEY ++ | GRUB_FILE_TYPE_NO_DECOMPRESS ++ | (ctxt->state[OPTION_SKIP_SIG].set ++ ? GRUB_FILE_TYPE_SKIP_SIGNATURE ++ : GRUB_FILE_TYPE_NONE)); + if (!pkf) + return grub_errno; + pk = grub_load_public_key (pkf); +@@ -786,16 +790,16 @@ grub_cmd_verify_signature (grub_extcmd_context_t ctxt, + grub_file_close (pkf); + } + +- grub_file_filter_disable_all (); +- f = grub_file_open (args[0]); ++ f = grub_file_open (args[0], GRUB_FILE_TYPE_VERIFY_SIGNATURE); + if (!f) + { + err = grub_errno; + goto fail; + } + +- grub_file_filter_disable_all (); +- sig = grub_file_open (args[1]); ++ sig = grub_file_open (args[1], ++ GRUB_FILE_TYPE_SIGNATURE ++ | GRUB_FILE_TYPE_NO_DECOMPRESS); + if (!sig) + { + err = grub_errno; +@@ -858,33 +862,32 @@ struct grub_fs verified_fs = + }; + + static grub_file_t +-grub_pubkey_open (grub_file_t io, const char *filename) ++grub_pubkey_open (grub_file_t io, enum grub_file_type type) + { + grub_file_t sig; + char *fsuf, *ptr; + grub_err_t err; +- grub_file_filter_t curfilt[GRUB_FILE_FILTER_MAX]; + grub_file_t ret; + grub_verified_t verified; + ++ if ((type & GRUB_FILE_TYPE_MASK) == GRUB_FILE_TYPE_SIGNATURE ++ || (type & GRUB_FILE_TYPE_MASK) == GRUB_FILE_TYPE_VERIFY_SIGNATURE ++ || (type & GRUB_FILE_TYPE_SKIP_SIGNATURE)) ++ return io; ++ + if (!sec) + return io; + if (io->device->disk && + (io->device->disk->dev->id == GRUB_DISK_DEVICE_MEMDISK_ID + || io->device->disk->dev->id == GRUB_DISK_DEVICE_PROCFS_ID)) + return io; +- fsuf = grub_malloc (grub_strlen (filename) + sizeof (".sig")); ++ fsuf = grub_malloc (grub_strlen (io->name) + sizeof (".sig")); + if (!fsuf) + return NULL; +- ptr = grub_stpcpy (fsuf, filename); ++ ptr = grub_stpcpy (fsuf, io->name); + grub_memcpy (ptr, ".sig", sizeof (".sig")); + +- grub_memcpy (curfilt, grub_file_filters_enabled, +- sizeof (curfilt)); +- grub_file_filter_disable_all (); +- sig = grub_file_open (fsuf); +- grub_memcpy (grub_file_filters_enabled, curfilt, +- sizeof (curfilt)); ++ sig = grub_file_open (fsuf, GRUB_FILE_TYPE_SIGNATURE); + grub_free (fsuf); + if (!sig) + return NULL; +@@ -918,7 +921,7 @@ grub_pubkey_open (grub_file_t io, const char *filename) + if (!verified->buf) + { + grub_file_close (sig); +- grub_free (verified); ++ verified_free (verified); + grub_free (ret); + return NULL; + } +@@ -926,7 +929,7 @@ grub_pubkey_open (grub_file_t io, const char *filename) + { + if (!grub_errno) + grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), +- filename); ++ io->name); + grub_file_close (sig); + verified_free (verified); + grub_free (ret); +diff --git a/grub-core/disk/loopback.c b/grub-core/disk/loopback.c +index 2d8deaeafbd..9406d931cdd 100644 +--- a/grub-core/disk/loopback.c ++++ b/grub-core/disk/loopback.c +@@ -92,7 +92,8 @@ grub_cmd_loopback (grub_extcmd_context_t ctxt, int argc, char **args) + if (argc < 2) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + +- file = grub_file_open (args[1]); ++ file = grub_file_open (args[1], GRUB_FILE_TYPE_LOOPBACK ++ | GRUB_FILE_TYPE_NO_DECOMPRESS); + if (! file) + return grub_errno; + +diff --git a/grub-core/efiemu/main.c b/grub-core/efiemu/main.c +index f6813b1ed15..a81934725be 100644 +--- a/grub-core/efiemu/main.c ++++ b/grub-core/efiemu/main.c +@@ -187,7 +187,7 @@ grub_efiemu_load_file (const char *filename) + grub_file_t file; + grub_err_t err; + +- file = grub_file_open (filename); ++ file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE); + if (! file) + return grub_errno; + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index b36a099b856..b67507fcc82 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -422,7 +422,7 @@ grub_font_load (const char *filename) + #endif + + if (filename[0] == '(' || filename[0] == '/' || filename[0] == '+') +- file = grub_buffile_open (filename, 1024); ++ file = grub_buffile_open (filename, GRUB_FILE_TYPE_FONT, 1024); + else + { + const char *prefix = grub_env_get ("prefix"); +@@ -442,7 +442,7 @@ grub_font_load (const char *filename) + ptr = grub_stpcpy (ptr, filename); + ptr = grub_stpcpy (ptr, ".pf2"); + *ptr = 0; +- file = grub_buffile_open (fullname, 1024); ++ file = grub_buffile_open (fullname, GRUB_FILE_TYPE_FONT, 1024); + grub_free (fullname); + } + if (!file) +diff --git a/grub-core/fs/zfs/zfscrypt.c b/grub-core/fs/zfs/zfscrypt.c +index f8488c35344..de3b015f582 100644 +--- a/grub-core/fs/zfs/zfscrypt.c ++++ b/grub-core/fs/zfs/zfscrypt.c +@@ -430,7 +430,7 @@ grub_cmd_zfs_key (grub_extcmd_context_t ctxt, int argc, char **args) + if (argc > 0) + { + grub_file_t file; +- file = grub_file_open (args[0]); ++ file = grub_file_open (args[0], GRUB_FILE_TYPE_ZFS_ENCRYPTION_KEY); + if (!file) + return grub_errno; + real_size = grub_file_read (file, buf, 1024); +diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c +index b22e1bcc94b..84d520cd494 100644 +--- a/grub-core/gettext/gettext.c ++++ b/grub-core/gettext/gettext.c +@@ -291,7 +291,7 @@ grub_mofile_open (struct grub_gettext_context *ctx, + /* Using fd_mo and not another variable because + it's needed for grub_gettext_get_info. */ + +- fd = grub_file_open (filename); ++ fd = grub_file_open (filename, GRUB_FILE_TYPE_GETTEXT_CATALOG); + + if (!fd) + return grub_errno; +diff --git a/grub-core/gfxmenu/theme_loader.c b/grub-core/gfxmenu/theme_loader.c +index 02978392ccc..d6829bb5e90 100644 +--- a/grub-core/gfxmenu/theme_loader.c ++++ b/grub-core/gfxmenu/theme_loader.c +@@ -743,7 +743,7 @@ grub_gfxmenu_view_load_theme (grub_gfxmenu_view_t view, const char *theme_path) + p.view = view; + p.theme_dir = grub_get_dirname (theme_path); + +- file = grub_file_open (theme_path); ++ file = grub_file_open (theme_path, GRUB_FILE_TYPE_THEME); + if (! file) + { + grub_free (p.theme_dir); +diff --git a/grub-core/io/bufio.c b/grub-core/io/bufio.c +index 2781afe0515..0dbac1b3a1e 100644 +--- a/grub-core/io/bufio.c ++++ b/grub-core/io/bufio.c +@@ -88,11 +88,11 @@ grub_bufio_open (grub_file_t io, grub_size_t size) + } + + grub_file_t +-grub_buffile_open (const char *name, grub_size_t size) ++grub_buffile_open (const char *name, enum grub_file_type type, grub_size_t size) + { + grub_file_t io, file; + +- io = grub_file_open (name); ++ io = grub_file_open (name, type); + if (! io) + return 0; + +diff --git a/grub-core/io/gzio.c b/grub-core/io/gzio.c +index 7024cda84ea..2ecf076dd5e 100644 +--- a/grub-core/io/gzio.c ++++ b/grub-core/io/gzio.c +@@ -1156,11 +1156,14 @@ initialize_tables (grub_gzio_t gzio) + even if IO does not contain data compressed by gzip, return a valid file + object. Note that this function won't close IO, even if an error occurs. */ + static grub_file_t +-grub_gzio_open (grub_file_t io, const char *name __attribute__ ((unused))) ++grub_gzio_open (grub_file_t io, enum grub_file_type type) + { + grub_file_t file; + grub_gzio_t gzio = 0; + ++ if (type & GRUB_FILE_TYPE_NO_DECOMPRESS) ++ return io; ++ + file = (grub_file_t) grub_zalloc (sizeof (*file)); + if (! file) + return 0; +diff --git a/grub-core/io/lzopio.c b/grub-core/io/lzopio.c +index 7559c6c9cab..84edf6dd2dc 100644 +--- a/grub-core/io/lzopio.c ++++ b/grub-core/io/lzopio.c +@@ -407,12 +407,14 @@ CORRUPTED: + } + + static grub_file_t +-grub_lzopio_open (grub_file_t io, +- const char *name __attribute__ ((unused))) ++grub_lzopio_open (grub_file_t io, enum grub_file_type type) + { + grub_file_t file; + grub_lzopio_t lzopio; + ++ if (type & GRUB_FILE_TYPE_NO_DECOMPRESS) ++ return io; ++ + file = (grub_file_t) grub_zalloc (sizeof (*file)); + if (!file) + return 0; +diff --git a/grub-core/io/offset.c b/grub-core/io/offset.c +index ebed0ebe63e..ec8e2320871 100644 +--- a/grub-core/io/offset.c ++++ b/grub-core/io/offset.c +@@ -69,7 +69,8 @@ grub_file_offset_close (grub_file_t file) + } + + grub_file_t +-grub_file_offset_open (grub_file_t parent, grub_off_t start, grub_off_t size) ++grub_file_offset_open (grub_file_t parent, enum grub_file_type type, ++ grub_off_t start, grub_off_t size) + { + struct grub_offset_file *off_data; + grub_file_t off_file, last_off_file; +@@ -95,10 +96,10 @@ grub_file_offset_open (grub_file_t parent, grub_off_t start, grub_off_t size) + last_off_file = NULL; + for (filter = GRUB_FILE_FILTER_COMPRESSION_FIRST; + off_file && filter <= GRUB_FILE_FILTER_COMPRESSION_LAST; filter++) +- if (grub_file_filters_enabled[filter]) ++ if (grub_file_filters[filter]) + { + last_off_file = off_file; +- off_file = grub_file_filters_enabled[filter] (off_file, parent->name); ++ off_file = grub_file_filters[filter] (off_file, type); + } + + if (!off_file) +diff --git a/grub-core/io/xzio.c b/grub-core/io/xzio.c +index a3536ad73b1..42afeedcd64 100644 +--- a/grub-core/io/xzio.c ++++ b/grub-core/io/xzio.c +@@ -169,12 +169,14 @@ ERROR: + } + + static grub_file_t +-grub_xzio_open (grub_file_t io, +- const char *name __attribute__ ((unused))) ++grub_xzio_open (grub_file_t io, enum grub_file_type type) + { + grub_file_t file; + grub_xzio_t xzio; + ++ if (type & GRUB_FILE_TYPE_NO_DECOMPRESS) ++ return io; ++ + file = (grub_file_t) grub_zalloc (sizeof (*file)); + if (!file) + return 0; +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index 91105bc4677..d7a7c8f97b0 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -806,7 +806,7 @@ grub_dl_load_file (const char *filename) + + grub_boot_time ("Loading module %s", filename); + +- file = grub_file_open (filename); ++ file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE); + if (! file) + return 0; + +diff --git a/grub-core/kern/elf.c b/grub-core/kern/elf.c +index 4f282c9cf43..9d7149b3892 100644 +--- a/grub-core/kern/elf.c ++++ b/grub-core/kern/elf.c +@@ -136,12 +136,12 @@ fail: + } + + grub_elf_t +-grub_elf_open (const char *name) ++grub_elf_open (const char *name, enum grub_file_type type) + { + grub_file_t file; + grub_elf_t elf; + +- file = grub_file_open (name); ++ file = grub_file_open (name, type); + if (! file) + return 0; + +diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c +index c2d9a550007..2efc31da94f 100644 +--- a/grub-core/kern/file.c ++++ b/grub-core/kern/file.c +@@ -28,8 +28,7 @@ + + void (*EXPORT_VAR (grub_grubnet_fini)) (void); + +-grub_file_filter_t grub_file_filters_all[GRUB_FILE_FILTER_MAX]; +-grub_file_filter_t grub_file_filters_enabled[GRUB_FILE_FILTER_MAX]; ++grub_file_filter_t grub_file_filters[GRUB_FILE_FILTER_MAX]; + + /* Get the device part of the filename NAME. It is enclosed by parentheses. */ + char * +@@ -59,7 +58,7 @@ grub_file_get_device_name (const char *name) + } + + grub_file_t +-grub_file_open (const char *name) ++grub_file_open (const char *name, enum grub_file_type type) + { + grub_device_t device = 0; + grub_file_t file = 0, last_file = 0; +@@ -116,18 +115,20 @@ grub_file_open (const char *name) + file->name = grub_strdup (name); + grub_errno = GRUB_ERR_NONE; + +- for (filter = 0; file && filter < ARRAY_SIZE (grub_file_filters_enabled); ++ for (filter = 0; file && filter < ARRAY_SIZE (grub_file_filters); + filter++) +- if (grub_file_filters_enabled[filter]) ++ if (grub_file_filters[filter]) + { + last_file = file; +- file = grub_file_filters_enabled[filter] (file, name); ++ file = grub_file_filters[filter] (file, type); ++ if (file && file != last_file) ++ { ++ file->name = grub_strdup (name); ++ grub_errno = GRUB_ERR_NONE; ++ } + } + if (!file) + grub_file_close (last_file); +- +- grub_memcpy (grub_file_filters_enabled, grub_file_filters_all, +- sizeof (grub_file_filters_enabled)); + + grub_dprintf ("file", "Opening `%s' succeeded.\n", name); + +@@ -141,9 +142,6 @@ grub_file_open (const char *name) + + grub_free (file); + +- grub_memcpy (grub_file_filters_enabled, grub_file_filters_all, +- sizeof (grub_file_filters_enabled)); +- + grub_dprintf ("file", "Opening `%s' failed.\n", name); + + return 0; +diff --git a/grub-core/lib/syslinux_parse.c b/grub-core/lib/syslinux_parse.c +index 21ca040ada7..83e7bdb9161 100644 +--- a/grub-core/lib/syslinux_parse.c ++++ b/grub-core/lib/syslinux_parse.c +@@ -696,7 +696,7 @@ syslinux_parse_real (struct syslinux_menu *menu) + char *buf = NULL; + grub_err_t err = GRUB_ERR_NONE; + +- file = grub_file_open (menu->filename); ++ file = grub_file_open (menu->filename, GRUB_FILE_TYPE_CONFIG); + if (!file) + return grub_errno; + while ((grub_free (buf), buf = grub_file_getline (file))) +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index a93edc975cd..29663f71801 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -941,7 +941,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + *(--p16) = 0; + } + +- file = grub_file_open (filename); ++ file = grub_file_open (filename, GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE); + if (! file) + goto fail; + +diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c +index 0f317632a3b..8306b415abd 100644 +--- a/grub-core/loader/i386/bsd.c ++++ b/grub-core/loader/i386/bsd.c +@@ -1464,7 +1464,7 @@ grub_bsd_load (int argc, char *argv[]) + goto fail; + } + +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_BSD_KERNEL); + if (!file) + goto fail; + +@@ -1541,7 +1541,7 @@ grub_cmd_freebsd (grub_extcmd_context_t ctxt, int argc, char *argv[]) + if (err) + return err; + +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_BSD_KERNEL); + if (! file) + return grub_errno; + +@@ -1700,7 +1700,7 @@ grub_cmd_netbsd (grub_extcmd_context_t ctxt, int argc, char *argv[]) + { + grub_file_t file; + +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_BSD_KERNEL); + if (! file) + return grub_errno; + +@@ -1809,7 +1809,7 @@ grub_cmd_freebsd_loadenv (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_FREEBSD_ENV); + if ((!file) || (!file->size)) + goto fail; + +@@ -1914,7 +1914,7 @@ grub_cmd_freebsd_module (grub_command_t cmd __attribute__ ((unused)), + return 0; + } + +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_FREEBSD_MODULE); + if ((!file) || (!file->size)) + goto fail; + +@@ -1965,7 +1965,7 @@ grub_netbsd_module_load (char *filename, grub_uint32_t type) + void *src; + grub_err_t err; + +- file = grub_file_open (filename); ++ file = grub_file_open (filename, GRUB_FILE_TYPE_NETBSD_MODULE); + if ((!file) || (!file->size)) + goto fail; + +@@ -2055,7 +2055,7 @@ grub_cmd_freebsd_module_elf (grub_command_t cmd __attribute__ ((unused)), + return 0; + } + +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_FREEBSD_MODULE_ELF); + if (!file) + return grub_errno; + if (!file->size) +@@ -2095,7 +2095,7 @@ grub_cmd_openbsd_ramdisk (grub_command_t cmd __attribute__ ((unused)), + if (!openbsd_ramdisk.max_size) + return grub_error (GRUB_ERR_BAD_OS, "your kOpenBSD doesn't support ramdisk"); + +- file = grub_file_open (args[0]); ++ file = grub_file_open (args[0], GRUB_FILE_TYPE_OPENBSD_RAMDISK); + if (! file) + return grub_errno; + +diff --git a/grub-core/loader/i386/coreboot/chainloader.c b/grub-core/loader/i386/coreboot/chainloader.c +index 2cb78eee090..0a19ebb9c3e 100644 +--- a/grub-core/loader/i386/coreboot/chainloader.c ++++ b/grub-core/loader/i386/coreboot/chainloader.c +@@ -439,7 +439,7 @@ grub_cmd_chain (grub_command_t cmd __attribute__ ((unused)), + + grub_loader_unset (); + +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_COREBOOT_CHAINLOADER); + if (!file) + return grub_errno; + +diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c +index 191f1631e88..aa2cbc4e7eb 100644 +--- a/grub-core/loader/i386/linux.c ++++ b/grub-core/loader/i386/linux.c +@@ -709,7 +709,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); + if (! file) + goto fail; + +diff --git a/grub-core/loader/i386/pc/chainloader.c b/grub-core/loader/i386/pc/chainloader.c +index ef3a322b78c..976fea73ab5 100644 +--- a/grub-core/loader/i386/pc/chainloader.c ++++ b/grub-core/loader/i386/pc/chainloader.c +@@ -172,8 +172,8 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags) + + grub_dl_ref (my_mod); + +- grub_file_filter_disable_compression (); +- file = grub_file_open (filename); ++ file = grub_file_open (filename, GRUB_FILE_TYPE_PCCHAINLOADER ++ | GRUB_FILE_TYPE_NO_DECOMPRESS); + if (! file) + goto fail; + +diff --git a/grub-core/loader/i386/pc/freedos.c b/grub-core/loader/i386/pc/freedos.c +index 478f3c5139d..aac6c9715f6 100644 +--- a/grub-core/loader/i386/pc/freedos.c ++++ b/grub-core/loader/i386/pc/freedos.c +@@ -110,7 +110,7 @@ grub_cmd_freedos (grub_command_t cmd __attribute__ ((unused)), + if (!rel) + goto fail; + +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_FREEDOS); + if (! file) + goto fail; + +diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c +index 63736fae950..b5c28c6580e 100644 +--- a/grub-core/loader/i386/pc/linux.c ++++ b/grub-core/loader/i386/pc/linux.c +@@ -142,7 +142,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); + if (! file) + goto fail; + +diff --git a/grub-core/loader/i386/pc/ntldr.c b/grub-core/loader/i386/pc/ntldr.c +index 1b88f40d871..f0d74145b38 100644 +--- a/grub-core/loader/i386/pc/ntldr.c ++++ b/grub-core/loader/i386/pc/ntldr.c +@@ -90,7 +90,7 @@ grub_cmd_ntldr (grub_command_t cmd __attribute__ ((unused)), + if (!rel) + goto fail; + +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_NTLDR); + if (! file) + goto fail; + +diff --git a/grub-core/loader/i386/pc/plan9.c b/grub-core/loader/i386/pc/plan9.c +index 814a49d5071..0351090daf8 100644 +--- a/grub-core/loader/i386/pc/plan9.c ++++ b/grub-core/loader/i386/pc/plan9.c +@@ -413,7 +413,7 @@ grub_cmd_plan9 (grub_extcmd_context_t ctxt, int argc, char *argv[]) + if (!rel) + goto fail; + +- fill_ctx.file = grub_file_open (argv[0]); ++ fill_ctx.file = grub_file_open (argv[0], GRUB_FILE_TYPE_PLAN9_KERNEL); + if (! fill_ctx.file) + goto fail; + +diff --git a/grub-core/loader/i386/pc/pxechainloader.c b/grub-core/loader/i386/pc/pxechainloader.c +index e60c62b1bad..acb061169b9 100644 +--- a/grub-core/loader/i386/pc/pxechainloader.c ++++ b/grub-core/loader/i386/pc/pxechainloader.c +@@ -99,7 +99,7 @@ grub_cmd_pxechain (grub_command_t cmd __attribute__ ((unused)), + if (!rel) + goto fail; + +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_PXECHAINLOADER); + if (! file) + goto fail; + +diff --git a/grub-core/loader/i386/pc/truecrypt.c b/grub-core/loader/i386/pc/truecrypt.c +index 9ea4fde42a5..cbeeec7beae 100644 +--- a/grub-core/loader/i386/pc/truecrypt.c ++++ b/grub-core/loader/i386/pc/truecrypt.c +@@ -99,7 +99,7 @@ grub_cmd_truecrypt (grub_command_t cmd __attribute__ ((unused)), + + grub_dl_ref (my_mod); + +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_TRUECRYPT); + if (! file) + goto fail; + +diff --git a/grub-core/loader/i386/xen.c b/grub-core/loader/i386/xen.c +index 85b93347b25..82350d3a178 100644 +--- a/grub-core/loader/i386/xen.c ++++ b/grub-core/loader/i386/xen.c +@@ -650,7 +650,7 @@ grub_cmd_xen (grub_command_t cmd __attribute__ ((unused)), + (char *) xen_state.next_start.cmd_line, + sizeof (xen_state.next_start.cmd_line) - 1); + +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); + if (!file) + return grub_errno; + +@@ -901,9 +901,8 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)), + + xen_state.max_addr = ALIGN_UP (xen_state.max_addr, PAGE_SIZE); + +- if (nounzip) +- grub_file_filter_disable_compression (); +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_INITRD | ++ (nounzip ? GRUB_FILE_TYPE_NO_DECOMPRESS : GRUB_FILE_TYPE_NONE)); + if (!file) + return grub_errno; + size = grub_file_size (file); +diff --git a/grub-core/loader/i386/xen_file.c b/grub-core/loader/i386/xen_file.c +index 77a93e7b228..9af5d66dfcd 100644 +--- a/grub-core/loader/i386/xen_file.c ++++ b/grub-core/loader/i386/xen_file.c +@@ -78,7 +78,7 @@ grub_xen_file (grub_file_t file) + Trim it. */ + if (grub_memcmp (magic, XZ_MAGIC, sizeof (XZ_MAGIC) - 1) == 0) + payload_length -= 4; +- off_file = grub_file_offset_open (file, payload_offset, ++ off_file = grub_file_offset_open (file, GRUB_FILE_TYPE_LINUX_KERNEL, payload_offset, + payload_length); + if (!off_file) + goto fail; +diff --git a/grub-core/loader/i386/xnu.c b/grub-core/loader/i386/xnu.c +index 44f7ebfa2b6..a7009360732 100644 +--- a/grub-core/loader/i386/xnu.c ++++ b/grub-core/loader/i386/xnu.c +@@ -486,7 +486,7 @@ grub_cmd_devprop_load (grub_command_t cmd __attribute__ ((unused)), + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + +- file = grub_file_open (args[0]); ++ file = grub_file_open (args[0], GRUB_FILE_XNU_DEVPROP); + if (! file) + return grub_errno; + size = grub_file_size (file); +diff --git a/grub-core/loader/linux.c b/grub-core/loader/linux.c +index 0953f6d3266..2b2f798e754 100644 +--- a/grub-core/loader/linux.c ++++ b/grub-core/loader/linux.c +@@ -183,7 +183,6 @@ grub_initrd_init (int argc, char *argv[], + eptr = grub_strchr (ptr, ':'); + if (eptr) + { +- grub_file_filter_disable_compression (); + grub_size_t dir_size, name_len; + + initrd_ctx->components[i].newc_name = grub_strndup (ptr, eptr - ptr); +@@ -215,8 +214,9 @@ grub_initrd_init (int argc, char *argv[], + root = 0; + newc = 0; + } +- grub_file_filter_disable_compression (); +- initrd_ctx->components[i].file = grub_file_open (fname); ++ initrd_ctx->components[i].file = grub_file_open (fname, ++ GRUB_FILE_TYPE_LINUX_INITRD ++ | GRUB_FILE_TYPE_NO_DECOMPRESS); + if (!initrd_ctx->components[i].file) + { + grub_initrd_close (initrd_ctx); +diff --git a/grub-core/loader/macho.c b/grub-core/loader/macho.c +index f61341af515..05710c48e06 100644 +--- a/grub-core/loader/macho.c ++++ b/grub-core/loader/macho.c +@@ -188,12 +188,12 @@ fail: + } + + grub_macho_t +-grub_macho_open (const char *name, int is_64bit) ++grub_macho_open (const char *name, enum grub_file_type type, int is_64bit) + { + grub_file_t file; + grub_macho_t macho; + +- file = grub_file_open (name); ++ file = grub_file_open (name, type); + if (! file) + return 0; + +diff --git a/grub-core/loader/mips/linux.c b/grub-core/loader/mips/linux.c +index 27c1db84a44..10358854458 100644 +--- a/grub-core/loader/mips/linux.c ++++ b/grub-core/loader/mips/linux.c +@@ -237,7 +237,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + +- elf = grub_elf_open (argv[0]); ++ elf = grub_elf_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); + if (! elf) + return grub_errno; + +diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c +index f455e803910..e8963d7cdb3 100644 +--- a/grub-core/loader/multiboot.c ++++ b/grub-core/loader/multiboot.c +@@ -323,7 +323,7 @@ grub_cmd_multiboot (grub_command_t cmd __attribute__ ((unused)), + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_MULTIBOOT_KERNEL); + if (! file) + return grub_errno; + +@@ -389,10 +389,8 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)), + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("you need to load the kernel first")); + +- if (nounzip) +- grub_file_filter_disable_compression (); +- +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_MULTIBOOT_MODULE ++ | (nounzip ? GRUB_FILE_TYPE_NO_DECOMPRESS : GRUB_FILE_TYPE_NONE)); + if (! file) + return grub_errno; + +diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c +index 2bf02489bad..9f78abb05f9 100644 +--- a/grub-core/loader/xnu.c ++++ b/grub-core/loader/xnu.c +@@ -355,7 +355,7 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)), + + grub_xnu_unload (); + +- macho = grub_macho_open (args[0], 0); ++ macho = grub_macho_open (args[0], GRUB_FILE_TYPE_XNU_KERNEL, 0); + if (! macho) + return grub_errno; + +@@ -460,7 +460,7 @@ grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)), + + grub_xnu_unload (); + +- macho = grub_macho_open (args[0], 1); ++ macho = grub_macho_open (args[0], GRUB_FILE_TYPE_XNU_KERNEL, 1); + if (! macho) + return grub_errno; + +@@ -678,7 +678,7 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile, + macho = 0; + + if (infoplistname) +- infoplist = grub_file_open (infoplistname); ++ infoplist = grub_file_open (infoplistname, GRUB_FILE_TYPE_XNU_INFO_PLIST); + else + infoplist = 0; + grub_errno = GRUB_ERR_NONE; +@@ -775,7 +775,7 @@ grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)), + if (! grub_xnu_heap_size) + return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first")); + +- file = grub_file_open (args[0]); ++ file = grub_file_open (args[0], GRUB_FILE_TYPE_XNU_MKEXT); + if (! file) + return grub_errno; + +@@ -889,7 +889,7 @@ grub_cmd_xnu_ramdisk (grub_command_t cmd __attribute__ ((unused)), + if (! grub_xnu_heap_size) + return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first")); + +- file = grub_file_open (args[0]); ++ file = grub_file_open (args[0], GRUB_FILE_TYPE_XNU_RAMDISK); + if (! file) + return grub_errno; + +@@ -929,7 +929,7 @@ grub_xnu_check_os_bundle_required (char *plistname, + if (binname) + *binname = 0; + +- file = grub_file_open (plistname); ++ file = grub_file_open (plistname, GRUB_FILE_TYPE_XNU_INFO_PLIST); + if (! file) + return 0; + +@@ -1214,7 +1214,7 @@ grub_xnu_load_kext_from_dir (char *dirname, const char *osbundlerequired, + grub_strcpy (binname + grub_strlen (binname), "/"); + grub_strcpy (binname + grub_strlen (binname), binsuffix); + grub_dprintf ("xnu", "%s:%s\n", ctx.plistname, binname); +- binfile = grub_file_open (binname); ++ binfile = grub_file_open (binname, GRUB_FILE_TYPE_XNU_KEXT); + if (! binfile) + grub_errno = GRUB_ERR_NONE; + +@@ -1257,7 +1257,7 @@ grub_cmd_xnu_kext (grub_command_t cmd __attribute__ ((unused)), + /* User explicitly specified plist and binary. */ + if (grub_strcmp (args[1], "-") != 0) + { +- binfile = grub_file_open (args[1]); ++ binfile = grub_file_open (args[1], GRUB_FILE_TYPE_XNU_KEXT); + if (! binfile) + return grub_errno; + } +diff --git a/grub-core/loader/xnu_resume.c b/grub-core/loader/xnu_resume.c +index 99119558d21..d648ef0cd3a 100644 +--- a/grub-core/loader/xnu_resume.c ++++ b/grub-core/loader/xnu_resume.c +@@ -53,8 +53,8 @@ grub_xnu_resume (char *imagename) + grub_addr_t target_image; + grub_err_t err; + +- grub_file_filter_disable_compression (); +- file = grub_file_open (imagename); ++ file = grub_file_open (imagename, GRUB_FILE_TYPE_XNU_HIBERNATE_IMAGE ++ | GRUB_FILE_TYPE_NO_DECOMPRESS); + if (! file) + return 0; + +diff --git a/grub-core/normal/autofs.c b/grub-core/normal/autofs.c +index 721b9c3256d..7a7cf2b0f7e 100644 +--- a/grub-core/normal/autofs.c ++++ b/grub-core/normal/autofs.c +@@ -33,12 +33,6 @@ autoload_fs_module (void) + { + grub_named_list_t p; + int ret = 0; +- grub_file_filter_t grub_file_filters_was[GRUB_FILE_FILTER_MAX]; +- +- grub_memcpy (grub_file_filters_was, grub_file_filters_enabled, +- sizeof (grub_file_filters_enabled)); +- grub_memcpy (grub_file_filters_enabled, grub_file_filters_all, +- sizeof (grub_file_filters_enabled)); + + while ((p = fs_module_list) != NULL) + { +@@ -56,9 +50,6 @@ autoload_fs_module (void) + grub_free (p); + } + +- grub_memcpy (grub_file_filters_enabled, grub_file_filters_was, +- sizeof (grub_file_filters_enabled)); +- + return ret; + } + +@@ -82,7 +73,7 @@ read_fs_list (const char *prefix) + tmp_autoload_hook = grub_fs_autoload_hook; + grub_fs_autoload_hook = NULL; + +- file = grub_file_open (filename); ++ file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE_LIST); + if (file) + { + /* Override previous fs.lst. */ +diff --git a/grub-core/normal/crypto.c b/grub-core/normal/crypto.c +index e6d345f3345..d01e6f271e1 100644 +--- a/grub-core/normal/crypto.c ++++ b/grub-core/normal/crypto.c +@@ -94,7 +94,7 @@ read_crypto_list (const char *prefix) + return; + } + +- file = grub_file_open (filename); ++ file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE_LIST); + grub_free (filename); + if (!file) + { +diff --git a/grub-core/normal/dyncmd.c b/grub-core/normal/dyncmd.c +index 169c126f508..719ebf477f2 100644 +--- a/grub-core/normal/dyncmd.c ++++ b/grub-core/normal/dyncmd.c +@@ -106,7 +106,7 @@ read_command_list (const char *prefix) + { + grub_file_t file; + +- file = grub_file_open (filename); ++ file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE_LIST); + if (file) + { + char *buf = NULL; +diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c +index 59fd54eb0f1..cee71a4c2ab 100644 +--- a/grub-core/normal/main.c ++++ b/grub-core/normal/main.c +@@ -127,7 +127,7 @@ read_config_file (const char *config) + } + + /* Try to open the config file. */ +- rawfile = grub_file_open (config); ++ rawfile = grub_file_open (config, GRUB_FILE_TYPE_CONFIG); + if (! rawfile) + return 0; + +diff --git a/grub-core/normal/term.c b/grub-core/normal/term.c +index 93a3a0d912e..cc8c173b6e8 100644 +--- a/grub-core/normal/term.c ++++ b/grub-core/normal/term.c +@@ -331,7 +331,7 @@ read_terminal_list (const char *prefix) + return; + } + +- file = grub_file_open (filename); ++ file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE_LIST); + grub_free (filename); + if (!file) + { +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index 21b0d9ded67..31359a4c9c8 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -772,7 +772,7 @@ grub_video_reader_jpeg (struct grub_video_bitmap **bitmap, + grub_file_t file; + struct grub_jpeg_data *data; + +- file = grub_buffile_open (filename, 0); ++ file = grub_buffile_open (filename, GRUB_FILE_TYPE_PIXMAP, 0); + if (!file) + return grub_errno; + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index 719e647e44f..0157ff7420b 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -1095,7 +1095,7 @@ grub_video_reader_png (struct grub_video_bitmap **bitmap, + grub_file_t file; + struct grub_png_data *data; + +- file = grub_buffile_open (filename, 0); ++ file = grub_buffile_open (filename, GRUB_FILE_TYPE_PIXMAP, 0); + if (!file) + return grub_errno; + +diff --git a/grub-core/video/readers/tga.c b/grub-core/video/readers/tga.c +index c7a16fa9cc4..7cb9d1d2a0c 100644 +--- a/grub-core/video/readers/tga.c ++++ b/grub-core/video/readers/tga.c +@@ -297,7 +297,7 @@ grub_video_reader_tga (struct grub_video_bitmap **bitmap, + + grub_memset (&data, 0, sizeof (data)); + +- data.file = grub_buffile_open (filename, 0); ++ data.file = grub_buffile_open (filename, GRUB_FILE_TYPE_PIXMAP, 0); + if (! data.file) + return grub_errno; + +diff --git a/util/grub-fstest.c b/util/grub-fstest.c +index 793aefa02b1..fe5982220d0 100644 +--- a/util/grub-fstest.c ++++ b/util/grub-fstest.c +@@ -120,9 +120,9 @@ read_file (char *pathname, int (*hook) (grub_off_t ofs, char *buf, int len, void + return; + } + +- if (uncompress == 0) +- grub_file_filter_disable_compression (); +- file = grub_file_open (pathname); ++ file = grub_file_open (pathname, ((uncompress == 0) ++ ? GRUB_FILE_TYPE_NO_DECOMPRESS : GRUB_FILE_TYPE_NONE) ++ | GRUB_FILE_TYPE_FSTEST); + if (!file) + { + grub_util_error (_("cannot open `%s': %s"), pathname, +diff --git a/util/grub-mount.c b/util/grub-mount.c +index a25db8a7181..e32b502e7e4 100644 +--- a/util/grub-mount.c ++++ b/util/grub-mount.c +@@ -208,7 +208,7 @@ fuse_getattr (const char *path, struct stat *st) + if (!ctx.file_info.dir) + { + grub_file_t file; +- file = grub_file_open (path); ++ file = grub_file_open (path, GRUB_FILE_TYPE_GET_SIZE); + if (! file && grub_errno == GRUB_ERR_BAD_FILE_TYPE) + { + grub_errno = GRUB_ERR_NONE; +@@ -244,7 +244,7 @@ static int + fuse_open (const char *path, struct fuse_file_info *fi __attribute__ ((unused))) + { + grub_file_t file; +- file = grub_file_open (path); ++ file = grub_file_open (path, GRUB_FILE_TYPE_MOUNT); + if (! file) + return translate_error (); + files[first_fd++] = file; +@@ -308,7 +308,7 @@ fuse_readdir_call_fill (const char *filename, + grub_file_t file; + char *tmp; + tmp = xasprintf ("%s/%s", ctx->path, filename); +- file = grub_file_open (tmp); ++ file = grub_file_open (tmp, GRUB_FILE_TYPE_GET_SIZE); + free (tmp); + /* Symlink to directory. */ + if (! file && grub_errno == GRUB_ERR_BAD_FILE_TYPE) +diff --git a/include/grub/bufio.h b/include/grub/bufio.h +index 77eb8ee5672..0ff72d1033c 100644 +--- a/include/grub/bufio.h ++++ b/include/grub/bufio.h +@@ -23,6 +23,8 @@ + #include + + grub_file_t EXPORT_FUNC (grub_bufio_open) (grub_file_t io, grub_size_t size); +-grub_file_t EXPORT_FUNC (grub_buffile_open) (const char *name, grub_size_t size); ++grub_file_t EXPORT_FUNC (grub_buffile_open) (const char *name, ++ enum grub_file_type type, ++ grub_size_t size); + + #endif /* ! GRUB_BUFIO_H */ +diff --git a/include/grub/elfload.h b/include/grub/elfload.h +index 9a7ae4ebb30..dbb609c9b20 100644 +--- a/include/grub/elfload.h ++++ b/include/grub/elfload.h +@@ -42,7 +42,7 @@ typedef int (*grub_elf32_phdr_iterate_hook_t) + typedef int (*grub_elf64_phdr_iterate_hook_t) + (grub_elf_t elf, Elf64_Phdr *phdr, void *arg); + +-grub_elf_t grub_elf_open (const char *); ++grub_elf_t grub_elf_open (const char *, enum grub_file_type type); + grub_elf_t grub_elf_file (grub_file_t file, const char *filename); + grub_err_t grub_elf_close (grub_elf_t); + +diff --git a/include/grub/file.h b/include/grub/file.h +index 739488cbe59..5b47c5f91f9 100644 +--- a/include/grub/file.h ++++ b/include/grub/file.h +@@ -25,6 +25,109 @@ + #include + #include + ++enum grub_file_type ++ { ++ GRUB_FILE_TYPE_NONE = 0, ++ /* GRUB module to be loaded. */ ++ GRUB_FILE_TYPE_GRUB_MODULE, ++ /* Loopback file to be represented as disk. */ ++ GRUB_FILE_TYPE_LOOPBACK, ++ /* Linux kernel to be loaded. */ ++ GRUB_FILE_TYPE_LINUX_KERNEL, ++ /* Linux initrd. */ ++ GRUB_FILE_TYPE_LINUX_INITRD, ++ ++ /* Multiboot kernel. */ ++ GRUB_FILE_TYPE_MULTIBOOT_KERNEL, ++ /* Multiboot module. */ ++ GRUB_FILE_TYPE_MULTIBOOT_MODULE, ++ ++ GRUB_FILE_TYPE_BSD_KERNEL, ++ GRUB_FILE_TYPE_FREEBSD_ENV, ++ GRUB_FILE_TYPE_FREEBSD_MODULE, ++ GRUB_FILE_TYPE_FREEBSD_MODULE_ELF, ++ GRUB_FILE_TYPE_NETBSD_MODULE, ++ GRUB_FILE_TYPE_OPENBSD_RAMDISK, ++ ++ GRUB_FILE_TYPE_XNU_INFO_PLIST, ++ GRUB_FILE_TYPE_XNU_MKEXT, ++ GRUB_FILE_TYPE_XNU_KEXT, ++ GRUB_FILE_TYPE_XNU_KERNEL, ++ GRUB_FILE_TYPE_XNU_RAMDISK, ++ GRUB_FILE_TYPE_XNU_HIBERNATE_IMAGE, ++ GRUB_FILE_XNU_DEVPROP, ++ ++ GRUB_FILE_TYPE_PLAN9_KERNEL, ++ ++ GRUB_FILE_TYPE_NTLDR, ++ GRUB_FILE_TYPE_TRUECRYPT, ++ GRUB_FILE_TYPE_FREEDOS, ++ GRUB_FILE_TYPE_PXECHAINLOADER, ++ GRUB_FILE_TYPE_PCCHAINLOADER, ++ ++ GRUB_FILE_TYPE_COREBOOT_CHAINLOADER, ++ ++ GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE, ++ ++ /* File holding signature. */ ++ GRUB_FILE_TYPE_SIGNATURE, ++ /* File holding public key to verify signature once. */ ++ GRUB_FILE_TYPE_PUBLIC_KEY, ++ /* File holding public key to add to trused keys. */ ++ GRUB_FILE_TYPE_PUBLIC_KEY_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. */ ++ GRUB_FILE_TYPE_TESTLOAD, ++ /* File we open only to get its size. E.g. in ls output. */ ++ GRUB_FILE_TYPE_GET_SIZE, ++ /* Font file. */ ++ GRUB_FILE_TYPE_FONT, ++ /* File holding encryption key for encrypted ZFS. */ ++ GRUB_FILE_TYPE_ZFS_ENCRYPTION_KEY, ++ /* File we open n grub-fstest. */ ++ GRUB_FILE_TYPE_FSTEST, ++ /* File we open n grub-mount. */ ++ GRUB_FILE_TYPE_MOUNT, ++ /* File which we attempt to identify the type of. */ ++ GRUB_FILE_TYPE_FILE_ID, ++ /* File holding ACPI table. */ ++ GRUB_FILE_TYPE_ACPI_TABLE, ++ /* File we intend show to user. */ ++ GRUB_FILE_TYPE_CAT, ++ GRUB_FILE_TYPE_HEXCAT, ++ /* One of pair of files we intend to compare. */ ++ GRUB_FILE_TYPE_CMP, ++ /* List of hashes for hashsum. */ ++ GRUB_FILE_TYPE_HASHLIST, ++ /* File hashed by hashsum. */ ++ GRUB_FILE_TYPE_TO_HASH, ++ /* Keyboard layout. */ ++ GRUB_FILE_TYPE_KEYBOARD_LAYOUT, ++ /* Picture file. */ ++ GRUB_FILE_TYPE_PIXMAP, ++ /* *.lst shipped by GRUB. */ ++ GRUB_FILE_TYPE_GRUB_MODULE_LIST, ++ /* config file. */ ++ GRUB_FILE_TYPE_CONFIG, ++ GRUB_FILE_TYPE_THEME, ++ GRUB_FILE_TYPE_GETTEXT_CATALOG, ++ GRUB_FILE_TYPE_FS_SEARCH, ++ GRUB_FILE_TYPE_AUDIO, ++ GRUB_FILE_TYPE_VBE_DUMP, ++ ++ GRUB_FILE_TYPE_LOADENV, ++ GRUB_FILE_TYPE_SAVEENV, ++ ++ GRUB_FILE_TYPE_VERIFY_SIGNATURE, ++ ++ GRUB_FILE_TYPE_MASK = 0xffff, ++ ++ /* --skip-sig is specified. */ ++ GRUB_FILE_TYPE_SKIP_SIGNATURE = 0x10000, ++ GRUB_FILE_TYPE_NO_DECOMPRESS = 0x20000 ++ }; ++ + /* File description. */ + struct grub_file + { +@@ -77,61 +180,26 @@ typedef enum grub_file_filter_id + GRUB_FILE_FILTER_COMPRESSION_LAST = GRUB_FILE_FILTER_LZOPIO, + } grub_file_filter_id_t; + +-typedef grub_file_t (*grub_file_filter_t) (grub_file_t in, const char *filename); ++typedef grub_file_t (*grub_file_filter_t) (grub_file_t in, enum grub_file_type type); + +-extern grub_file_filter_t EXPORT_VAR(grub_file_filters_all)[GRUB_FILE_FILTER_MAX]; +-extern grub_file_filter_t EXPORT_VAR(grub_file_filters_enabled)[GRUB_FILE_FILTER_MAX]; ++extern grub_file_filter_t EXPORT_VAR(grub_file_filters)[GRUB_FILE_FILTER_MAX]; + + static inline void + grub_file_filter_register (grub_file_filter_id_t id, grub_file_filter_t filter) + { +- grub_file_filters_all[id] = filter; +- grub_file_filters_enabled[id] = filter; ++ grub_file_filters[id] = filter; + } + + static inline void + grub_file_filter_unregister (grub_file_filter_id_t id) + { +- grub_file_filters_all[id] = 0; +- grub_file_filters_enabled[id] = 0; +-} +- +-static inline void +-grub_file_filter_disable (grub_file_filter_id_t id) +-{ +- grub_file_filters_enabled[id] = 0; +-} +- +-static inline void +-grub_file_filter_disable_compression (void) +-{ +- grub_file_filter_id_t id; +- +- for (id = GRUB_FILE_FILTER_COMPRESSION_FIRST; +- id <= GRUB_FILE_FILTER_COMPRESSION_LAST; id++) +- grub_file_filters_enabled[id] = 0; +-} +- +-static inline void +-grub_file_filter_disable_all (void) +-{ +- grub_file_filter_id_t id; +- +- for (id = 0; +- id < GRUB_FILE_FILTER_MAX; id++) +- grub_file_filters_enabled[id] = 0; +-} +- +-static inline void +-grub_file_filter_disable_pubkey (void) +-{ +- grub_file_filters_enabled[GRUB_FILE_FILTER_PUBKEY] = 0; ++ grub_file_filters[id] = 0; + } + + /* Get a device name from NAME. */ + char *EXPORT_FUNC(grub_file_get_device_name) (const char *name); + +-grub_file_t EXPORT_FUNC(grub_file_open) (const char *name); ++grub_file_t EXPORT_FUNC(grub_file_open) (const char *name, enum grub_file_type type); + grub_ssize_t EXPORT_FUNC(grub_file_read) (grub_file_t file, void *buf, + grub_size_t len); + grub_off_t EXPORT_FUNC(grub_file_seek) (grub_file_t file, grub_off_t offset); +@@ -159,8 +227,8 @@ grub_file_seekable (const grub_file_t file) + } + + grub_file_t +-grub_file_offset_open (grub_file_t parent, grub_off_t start, +- grub_off_t size); ++grub_file_offset_open (grub_file_t parent, enum grub_file_type type, ++ grub_off_t start, grub_off_t size); + void + grub_file_offset_close (grub_file_t file); + +diff --git a/include/grub/machoload.h b/include/grub/machoload.h +index 1eec118f15f..f1157f4105b 100644 +--- a/include/grub/machoload.h ++++ b/include/grub/machoload.h +@@ -49,7 +49,8 @@ struct grub_macho_file + }; + typedef struct grub_macho_file *grub_macho_t; + +-grub_macho_t grub_macho_open (const char *, int is_64bit); ++grub_macho_t grub_macho_open (const char *, enum grub_file_type type, ++ int is_64bit); + grub_macho_t grub_macho_file (grub_file_t file, const char *filename, + int is_64bit); + grub_err_t grub_macho_close (grub_macho_t); diff --git a/SOURCES/0331-usb-Avoid-possible-out-of-bound-accesses-caused-by-m.patch b/SOURCES/0331-usb-Avoid-possible-out-of-bound-accesses-caused-by-m.patch deleted file mode 100644 index 1b04633..0000000 --- a/SOURCES/0331-usb-Avoid-possible-out-of-bound-accesses-caused-by-m.patch +++ /dev/null @@ -1,112 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Fri, 11 Dec 2020 19:19:21 +0100 -Subject: [PATCH] usb: Avoid possible out-of-bound accesses caused by malicious - devices - -The maximum number of configurations and interfaces are fixed but there is -no out-of-bound checking to prevent a malicious USB device to report large -values for these and cause accesses outside the arrays' memory. - -Fixes: CVE-2020-25647 - -Reported-by: Joseph Tartaro (IOActive) -Reported-by: Ilja Van Sprundel -Signed-off-by: Javier Martinez Canillas -Reviewed-by: Daniel Kiper ---- - grub-core/bus/usb/usb.c | 15 ++++++++++++--- - include/grub/usb.h | 10 +++++++--- - 2 files changed, 19 insertions(+), 6 deletions(-) - -diff --git a/grub-core/bus/usb/usb.c b/grub-core/bus/usb/usb.c -index 8da5e4c7491..7cb3cc230b2 100644 ---- a/grub-core/bus/usb/usb.c -+++ b/grub-core/bus/usb/usb.c -@@ -75,6 +75,9 @@ grub_usb_controller_iterate (grub_usb_controller_iterate_hook_t hook, - grub_usb_err_t - grub_usb_clear_halt (grub_usb_device_t dev, int endpoint) - { -+ if (endpoint >= GRUB_USB_MAX_TOGGLE) -+ return GRUB_USB_ERR_BADDEVICE; -+ - dev->toggle[endpoint] = 0; - return grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT - | GRUB_USB_REQTYPE_STANDARD -@@ -134,10 +137,10 @@ grub_usb_device_initialize (grub_usb_device_t dev) - return err; - descdev = &dev->descdev; - -- for (i = 0; i < 8; i++) -+ for (i = 0; i < GRUB_USB_MAX_CONF; i++) - dev->config[i].descconf = NULL; - -- if (descdev->configcnt == 0) -+ if (descdev->configcnt == 0 || descdev->configcnt > GRUB_USB_MAX_CONF) - { - err = GRUB_USB_ERR_BADDEVICE; - goto fail; -@@ -172,6 +175,12 @@ grub_usb_device_initialize (grub_usb_device_t dev) - /* Skip the configuration descriptor. */ - pos = dev->config[i].descconf->length; - -+ if (dev->config[i].descconf->numif > GRUB_USB_MAX_IF) -+ { -+ err = GRUB_USB_ERR_BADDEVICE; -+ goto fail; -+ } -+ - /* Read all interfaces. */ - for (currif = 0; currif < dev->config[i].descconf->numif; currif++) - { -@@ -217,7 +226,7 @@ grub_usb_device_initialize (grub_usb_device_t dev) - - fail: - -- for (i = 0; i < 8; i++) -+ for (i = 0; i < GRUB_USB_MAX_CONF; i++) - grub_free (dev->config[i].descconf); - - return err; -diff --git a/include/grub/usb.h b/include/grub/usb.h -index 512ae1dd0e6..6475c552fc6 100644 ---- a/include/grub/usb.h -+++ b/include/grub/usb.h -@@ -23,6 +23,10 @@ - #include - #include - -+#define GRUB_USB_MAX_CONF 8 -+#define GRUB_USB_MAX_IF 32 -+#define GRUB_USB_MAX_TOGGLE 256 -+ - typedef struct grub_usb_device *grub_usb_device_t; - typedef struct grub_usb_controller *grub_usb_controller_t; - typedef struct grub_usb_controller_dev *grub_usb_controller_dev_t; -@@ -167,7 +171,7 @@ struct grub_usb_configuration - struct grub_usb_desc_config *descconf; - - /* Interfaces associated to this configuration. */ -- struct grub_usb_interface interf[32]; -+ struct grub_usb_interface interf[GRUB_USB_MAX_IF]; - }; - - struct grub_usb_hub_port -@@ -191,7 +195,7 @@ struct grub_usb_device - struct grub_usb_controller controller; - - /* Device configurations (after opening the device). */ -- struct grub_usb_configuration config[8]; -+ struct grub_usb_configuration config[GRUB_USB_MAX_CONF]; - - /* Device address. */ - int addr; -@@ -203,7 +207,7 @@ struct grub_usb_device - int initialized; - - /* Data toggle values (used for bulk transfers only). */ -- int toggle[256]; -+ int toggle[GRUB_USB_MAX_TOGGLE]; - - /* Used by libusb wrapper. Schedulded for removal. */ - void *data; diff --git a/SOURCES/0331-verifiers-Framework-core.patch b/SOURCES/0331-verifiers-Framework-core.patch new file mode 100644 index 0000000..b830048 --- /dev/null +++ b/SOURCES/0331-verifiers-Framework-core.patch @@ -0,0 +1,1026 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Vladimir Serbinenko +Date: Sun, 5 Feb 2017 14:25:47 +0100 +Subject: [PATCH] verifiers: Framework core + +Verifiers framework provides core file verification functionality which +can be used by various security mechanisms, e.g., UEFI secure boot, TPM, +PGP signature verification, etc. + +The patch contains PGP code changes and probably they should be extracted +to separate patch for the sake of clarity. + +Signed-off-by: Vladimir Serbinenko +Signed-off-by: Daniel Kiper +Reviewed-by: Ross Philipson +(cherry picked from commit 75a919e334f8514b6adbc024743cfcd9b88fa394) +Signed-off-by: Daniel Axtens +--- + grub-core/Makefile.core.def | 5 + + grub-core/commands/verifiers.c | 197 ++++++++++++++ + grub-core/commands/verify.c | 566 ++++++++++++++++++++--------------------- + include/grub/file.h | 2 +- + include/grub/list.h | 1 + + include/grub/verify.h | 65 +++++ + 6 files changed, 539 insertions(+), 297 deletions(-) + create mode 100644 grub-core/commands/verifiers.c + create mode 100644 include/grub/verify.h + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index c8a50b4fcfa..29c3bf6cd66 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -921,6 +921,11 @@ module = { + cppflags = '-I$(srcdir)/lib/posix_wrap'; + }; + ++module = { ++ name = verifiers; ++ common = commands/verifiers.c; ++}; ++ + module = { + name = hdparm; + common = commands/hdparm.c; +diff --git a/grub-core/commands/verifiers.c b/grub-core/commands/verifiers.c +new file mode 100644 +index 00000000000..fde88318d4c +--- /dev/null ++++ b/grub-core/commands/verifiers.c +@@ -0,0 +1,197 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2017 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 . ++ * ++ * Verifiers helper. ++ */ ++ ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++struct grub_file_verifier *grub_file_verifiers; ++ ++struct grub_verified ++{ ++ grub_file_t file; ++ void *buf; ++}; ++typedef struct grub_verified *grub_verified_t; ++ ++static void ++verified_free (grub_verified_t verified) ++{ ++ if (verified) ++ { ++ grub_free (verified->buf); ++ grub_free (verified); ++ } ++} ++ ++static grub_ssize_t ++verified_read (struct grub_file *file, char *buf, grub_size_t len) ++{ ++ grub_verified_t verified = file->data; ++ ++ grub_memcpy (buf, (char *) verified->buf + file->offset, len); ++ return len; ++} ++ ++static grub_err_t ++verified_close (struct grub_file *file) ++{ ++ grub_verified_t verified = file->data; ++ ++ grub_file_close (verified->file); ++ verified_free (verified); ++ file->data = 0; ++ ++ /* Device and name are freed by parent. */ ++ file->device = 0; ++ file->name = 0; ++ ++ return grub_errno; ++} ++ ++struct grub_fs verified_fs = ++{ ++ .name = "verified_read", ++ .read = verified_read, ++ .close = verified_close ++}; ++ ++static grub_file_t ++grub_verifiers_open (grub_file_t io, enum grub_file_type type) ++{ ++ grub_verified_t verified = NULL; ++ struct grub_file_verifier *ver; ++ void *context; ++ grub_file_t ret = 0; ++ grub_err_t err; ++ ++ grub_dprintf ("verify", "file: %s type: %d\n", io->name, type); ++ ++ if ((type & GRUB_FILE_TYPE_MASK) == GRUB_FILE_TYPE_SIGNATURE ++ || (type & GRUB_FILE_TYPE_MASK) == GRUB_FILE_TYPE_VERIFY_SIGNATURE ++ || (type & GRUB_FILE_TYPE_SKIP_SIGNATURE)) ++ return io; ++ ++ if (io->device->disk && ++ (io->device->disk->dev->id == GRUB_DISK_DEVICE_MEMDISK_ID ++ || io->device->disk->dev->id == GRUB_DISK_DEVICE_PROCFS_ID)) ++ return io; ++ ++ FOR_LIST_ELEMENTS(ver, grub_file_verifiers) ++ { ++ enum grub_verify_flags flags = 0; ++ err = ver->init (io, type, &context, &flags); ++ if (err) ++ goto fail_noclose; ++ if (!(flags & GRUB_VERIFY_FLAGS_SKIP_VERIFICATION)) ++ break; ++ } ++ ++ if (!ver) ++ /* No verifiers wanted to verify. Just return underlying file. */ ++ return io; ++ ++ ret = grub_malloc (sizeof (*ret)); ++ if (!ret) ++ { ++ goto fail; ++ } ++ *ret = *io; ++ ++ ret->fs = &verified_fs; ++ ret->not_easily_seekable = 0; ++ if (ret->size >> (sizeof (grub_size_t) * GRUB_CHAR_BIT - 1)) ++ { ++ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ N_("big file signature isn't implemented yet")); ++ goto fail; ++ } ++ verified = grub_malloc (sizeof (*verified)); ++ if (!verified) ++ { ++ goto fail; ++ } ++ verified->buf = grub_malloc (ret->size); ++ if (!verified->buf) ++ { ++ goto fail; ++ } ++ if (grub_file_read (io, verified->buf, ret->size) != (grub_ssize_t) ret->size) ++ { ++ if (!grub_errno) ++ grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), ++ io->name); ++ goto fail; ++ } ++ ++ err = ver->write (context, verified->buf, ret->size); ++ if (err) ++ goto fail; ++ ++ err = ver->fini ? ver->fini (context) : GRUB_ERR_NONE; ++ if (err) ++ goto fail; ++ ++ if (ver->close) ++ ver->close (context); ++ ++ FOR_LIST_ELEMENTS_NEXT(ver, grub_file_verifiers) ++ { ++ enum grub_verify_flags flags = 0; ++ err = ver->init (io, type, &context, &flags); ++ if (err) ++ goto fail_noclose; ++ if (flags & GRUB_VERIFY_FLAGS_SKIP_VERIFICATION) ++ continue; ++ err = ver->write (context, verified->buf, ret->size); ++ if (err) ++ goto fail; ++ ++ err = ver->fini ? ver->fini (context) : GRUB_ERR_NONE; ++ if (err) ++ goto fail; ++ ++ if (ver->close) ++ ver->close (context); ++ } ++ ++ verified->file = io; ++ ret->data = verified; ++ return ret; ++ ++ fail: ++ ver->close (context); ++ fail_noclose: ++ verified_free (verified); ++ grub_free (ret); ++ return NULL; ++} ++ ++GRUB_MOD_INIT(verifiers) ++{ ++ grub_file_filter_register (GRUB_FILE_FILTER_VERIFY, grub_verifiers_open); ++} ++ ++GRUB_MOD_FINI(verifiers) ++{ ++ grub_file_filter_unregister (GRUB_FILE_FILTER_VERIFY); ++} +diff --git a/grub-core/commands/verify.c b/grub-core/commands/verify.c +index f0dfeceebd4..29e74a64004 100644 +--- a/grub-core/commands/verify.c ++++ b/grub-core/commands/verify.c +@@ -30,16 +30,10 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +-struct grub_verified +-{ +- grub_file_t file; +- void *buf; +-}; +-typedef struct grub_verified *grub_verified_t; +- + enum + { + OPTION_SKIP_SIG = 0 +@@ -445,23 +439,27 @@ rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval, + return ret; + } + +-static grub_err_t +-grub_verify_signature_real (char *buf, grub_size_t size, +- grub_file_t f, grub_file_t sig, +- struct grub_public_key *pkey) ++struct grub_pubkey_context + { +- grub_size_t len; ++ grub_file_t sig; ++ struct signature_v4_header v4; + grub_uint8_t v; ++ const gcry_md_spec_t *hash; ++ void *hash_context; ++}; ++ ++static grub_err_t ++grub_verify_signature_init (struct grub_pubkey_context *ctxt, grub_file_t sig) ++{ ++ grub_size_t len; + grub_uint8_t h; + grub_uint8_t t; + grub_uint8_t pk; +- const gcry_md_spec_t *hash; +- struct signature_v4_header v4; + grub_err_t err; +- grub_size_t i; +- gcry_mpi_t mpis[10]; + grub_uint8_t type = 0; + ++ grub_memset (ctxt, 0, sizeof (*ctxt)); ++ + err = read_packet_header (sig, &type, &len); + if (err) + return err; +@@ -469,18 +467,18 @@ grub_verify_signature_real (char *buf, grub_size_t size, + if (type != 0x2) + return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature")); + +- if (grub_file_read (sig, &v, sizeof (v)) != sizeof (v)) ++ if (grub_file_read (sig, &ctxt->v, sizeof (ctxt->v)) != sizeof (ctxt->v)) + return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature")); + +- if (v != 4) ++ if (ctxt->v != 4) + return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature")); + +- if (grub_file_read (sig, &v4, sizeof (v4)) != sizeof (v4)) ++ if (grub_file_read (sig, &ctxt->v4, sizeof (ctxt->v4)) != sizeof (ctxt->v4)) + return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature")); + +- h = v4.hash; +- t = v4.type; +- pk = v4.pkeyalgo; ++ h = ctxt->v4.hash; ++ t = ctxt->v4.type; ++ pk = ctxt->v4.pkeyalgo; + + if (t != 0) + return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature")); +@@ -491,183 +489,233 @@ grub_verify_signature_real (char *buf, grub_size_t size, + if (pk >= ARRAY_SIZE (pkalgos) || pkalgos[pk].name == NULL) + return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature")); + +- hash = grub_crypto_lookup_md_by_name (hashes[h]); +- if (!hash) ++ ctxt->hash = grub_crypto_lookup_md_by_name (hashes[h]); ++ if (!ctxt->hash) + return grub_error (GRUB_ERR_BAD_SIGNATURE, "hash `%s' not loaded", hashes[h]); + + grub_dprintf ("crypt", "alive\n"); + +- { +- void *context = NULL; +- unsigned char *hval; +- grub_ssize_t rem = grub_be_to_cpu16 (v4.hashed_sub); +- grub_uint32_t headlen = grub_cpu_to_be32 (rem + 6); +- grub_uint8_t s; +- grub_uint16_t unhashed_sub; +- grub_ssize_t r; +- grub_uint8_t hash_start[2]; +- gcry_mpi_t hmpi; +- grub_uint64_t keyid = 0; +- struct grub_public_subkey *sk; +- grub_uint8_t *readbuf = NULL; ++ ctxt->sig = sig; + +- context = grub_zalloc (hash->contextsize); +- readbuf = grub_zalloc (READBUF_SIZE); +- if (!context || !readbuf) +- goto fail; +- +- hash->init (context); +- if (buf) +- hash->write (context, buf, size); +- else +- while (1) +- { +- r = grub_file_read (f, readbuf, READBUF_SIZE); +- if (r < 0) +- goto fail; +- if (r == 0) +- break; +- hash->write (context, readbuf, r); +- } +- +- hash->write (context, &v, sizeof (v)); +- hash->write (context, &v4, sizeof (v4)); +- while (rem) +- { +- r = grub_file_read (sig, readbuf, +- rem < READBUF_SIZE ? rem : READBUF_SIZE); +- if (r < 0) +- goto fail; +- if (r == 0) +- break; +- hash->write (context, readbuf, r); +- rem -= r; +- } +- hash->write (context, &v, sizeof (v)); +- s = 0xff; +- hash->write (context, &s, sizeof (s)); +- hash->write (context, &headlen, sizeof (headlen)); +- r = grub_file_read (sig, &unhashed_sub, sizeof (unhashed_sub)); +- if (r != sizeof (unhashed_sub)) +- goto fail; +- { +- grub_uint8_t *ptr; +- grub_uint32_t l; +- rem = grub_be_to_cpu16 (unhashed_sub); +- if (rem > READBUF_SIZE) +- goto fail; +- r = grub_file_read (sig, readbuf, rem); +- if (r != rem) +- goto fail; +- for (ptr = readbuf; ptr < readbuf + rem; ptr += l) +- { +- if (*ptr < 192) +- l = *ptr++; +- else if (*ptr < 255) +- { +- if (ptr + 1 >= readbuf + rem) +- break; +- l = (((ptr[0] & ~192) << GRUB_CHAR_BIT) | ptr[1]) + 192; +- ptr += 2; +- } +- else +- { +- if (ptr + 5 >= readbuf + rem) +- break; +- l = grub_be_to_cpu32 (grub_get_unaligned32 (ptr + 1)); +- ptr += 5; +- } +- if (*ptr == 0x10 && l >= 8) +- keyid = grub_get_unaligned64 (ptr + 1); +- } +- } +- +- hash->final (context); +- +- grub_dprintf ("crypt", "alive\n"); +- +- hval = hash->read (context); +- +- if (grub_file_read (sig, hash_start, sizeof (hash_start)) != sizeof (hash_start)) +- goto fail; +- if (grub_memcmp (hval, hash_start, sizeof (hash_start)) != 0) +- goto fail; +- +- grub_dprintf ("crypt", "@ %x\n", (int)grub_file_tell (sig)); +- +- for (i = 0; i < pkalgos[pk].nmpisig; i++) +- { +- grub_uint16_t l; +- grub_size_t lb; +- grub_dprintf ("crypt", "alive\n"); +- if (grub_file_read (sig, &l, sizeof (l)) != sizeof (l)) +- goto fail; +- grub_dprintf ("crypt", "alive\n"); +- lb = (grub_be_to_cpu16 (l) + 7) / 8; +- grub_dprintf ("crypt", "l = 0x%04x\n", grub_be_to_cpu16 (l)); +- if (lb > READBUF_SIZE - sizeof (grub_uint16_t)) +- goto fail; +- grub_dprintf ("crypt", "alive\n"); +- if (grub_file_read (sig, readbuf + sizeof (grub_uint16_t), lb) != (grub_ssize_t) lb) +- goto fail; +- grub_dprintf ("crypt", "alive\n"); +- grub_memcpy (readbuf, &l, sizeof (l)); +- grub_dprintf ("crypt", "alive\n"); +- +- if (gcry_mpi_scan (&mpis[i], GCRYMPI_FMT_PGP, +- readbuf, lb + sizeof (grub_uint16_t), 0)) +- goto fail; +- grub_dprintf ("crypt", "alive\n"); +- } +- +- if (pkey) +- sk = grub_crypto_pk_locate_subkey (keyid, pkey); +- else +- sk = grub_crypto_pk_locate_subkey_in_trustdb (keyid); +- if (!sk) +- { +- /* TRANSLATORS: %08x is 32-bit key id. */ +- grub_error (GRUB_ERR_BAD_SIGNATURE, N_("public key %08x not found"), +- keyid); +- goto fail; +- } +- +- if (pkalgos[pk].pad (&hmpi, hval, hash, sk)) +- goto fail; +- if (!*pkalgos[pk].algo) +- { +- grub_dl_load (pkalgos[pk].module); +- grub_errno = GRUB_ERR_NONE; +- } +- +- if (!*pkalgos[pk].algo) +- { +- grub_error (GRUB_ERR_BAD_SIGNATURE, N_("module `%s' isn't loaded"), +- pkalgos[pk].module); +- goto fail; +- } +- if ((*pkalgos[pk].algo)->verify (0, hmpi, mpis, sk->mpis, 0, 0)) +- goto fail; +- +- grub_free (context); +- grub_free (readbuf); +- +- return GRUB_ERR_NONE; +- +- fail: +- grub_free (context); +- grub_free (readbuf); +- if (!grub_errno) +- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature")); ++ ctxt->hash_context = grub_zalloc (ctxt->hash->contextsize); ++ if (!ctxt->hash_context) + return grub_errno; ++ ++ ctxt->hash->init (ctxt->hash_context); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_pubkey_write (void *ctxt_, void *buf, grub_size_t size) ++{ ++ struct grub_pubkey_context *ctxt = ctxt_; ++ ctxt->hash->write (ctxt->hash_context, buf, size); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_verify_signature_real (struct grub_pubkey_context *ctxt, ++ struct grub_public_key *pkey) ++{ ++ gcry_mpi_t mpis[10]; ++ grub_uint8_t pk = ctxt->v4.pkeyalgo; ++ grub_size_t i; ++ grub_uint8_t *readbuf = NULL; ++ unsigned char *hval; ++ grub_ssize_t rem = grub_be_to_cpu16 (ctxt->v4.hashed_sub); ++ grub_uint32_t headlen = grub_cpu_to_be32 (rem + 6); ++ grub_uint8_t s; ++ grub_uint16_t unhashed_sub; ++ grub_ssize_t r; ++ grub_uint8_t hash_start[2]; ++ gcry_mpi_t hmpi; ++ grub_uint64_t keyid = 0; ++ struct grub_public_subkey *sk; ++ ++ readbuf = grub_malloc (READBUF_SIZE); ++ if (!readbuf) ++ goto fail; ++ ++ ctxt->hash->write (ctxt->hash_context, &ctxt->v, sizeof (ctxt->v)); ++ ctxt->hash->write (ctxt->hash_context, &ctxt->v4, sizeof (ctxt->v4)); ++ while (rem) ++ { ++ r = grub_file_read (ctxt->sig, readbuf, ++ rem < READBUF_SIZE ? rem : READBUF_SIZE); ++ if (r < 0) ++ goto fail; ++ if (r == 0) ++ break; ++ ctxt->hash->write (ctxt->hash_context, readbuf, r); ++ rem -= r; ++ } ++ ctxt->hash->write (ctxt->hash_context, &ctxt->v, sizeof (ctxt->v)); ++ s = 0xff; ++ ctxt->hash->write (ctxt->hash_context, &s, sizeof (s)); ++ ctxt->hash->write (ctxt->hash_context, &headlen, sizeof (headlen)); ++ r = grub_file_read (ctxt->sig, &unhashed_sub, sizeof (unhashed_sub)); ++ if (r != sizeof (unhashed_sub)) ++ goto fail; ++ { ++ grub_uint8_t *ptr; ++ grub_uint32_t l; ++ rem = grub_be_to_cpu16 (unhashed_sub); ++ if (rem > READBUF_SIZE) ++ goto fail; ++ r = grub_file_read (ctxt->sig, readbuf, rem); ++ if (r != rem) ++ goto fail; ++ for (ptr = readbuf; ptr < readbuf + rem; ptr += l) ++ { ++ if (*ptr < 192) ++ l = *ptr++; ++ else if (*ptr < 255) ++ { ++ if (ptr + 1 >= readbuf + rem) ++ break; ++ l = (((ptr[0] & ~192) << GRUB_CHAR_BIT) | ptr[1]) + 192; ++ ptr += 2; ++ } ++ else ++ { ++ if (ptr + 5 >= readbuf + rem) ++ break; ++ l = grub_be_to_cpu32 (grub_get_unaligned32 (ptr + 1)); ++ ptr += 5; ++ } ++ if (*ptr == 0x10 && l >= 8) ++ keyid = grub_get_unaligned64 (ptr + 1); ++ } + } ++ ++ ctxt->hash->final (ctxt->hash_context); ++ ++ grub_dprintf ("crypt", "alive\n"); ++ ++ hval = ctxt->hash->read (ctxt->hash_context); ++ ++ if (grub_file_read (ctxt->sig, hash_start, sizeof (hash_start)) != sizeof (hash_start)) ++ goto fail; ++ if (grub_memcmp (hval, hash_start, sizeof (hash_start)) != 0) ++ goto fail; ++ ++ grub_dprintf ("crypt", "@ %x\n", (int)grub_file_tell (ctxt->sig)); ++ ++ for (i = 0; i < pkalgos[pk].nmpisig; i++) ++ { ++ grub_uint16_t l; ++ grub_size_t lb; ++ grub_dprintf ("crypt", "alive\n"); ++ if (grub_file_read (ctxt->sig, &l, sizeof (l)) != sizeof (l)) ++ goto fail; ++ grub_dprintf ("crypt", "alive\n"); ++ lb = (grub_be_to_cpu16 (l) + 7) / 8; ++ grub_dprintf ("crypt", "l = 0x%04x\n", grub_be_to_cpu16 (l)); ++ if (lb > READBUF_SIZE - sizeof (grub_uint16_t)) ++ goto fail; ++ grub_dprintf ("crypt", "alive\n"); ++ if (grub_file_read (ctxt->sig, readbuf + sizeof (grub_uint16_t), lb) != (grub_ssize_t) lb) ++ goto fail; ++ grub_dprintf ("crypt", "alive\n"); ++ grub_memcpy (readbuf, &l, sizeof (l)); ++ grub_dprintf ("crypt", "alive\n"); ++ ++ if (gcry_mpi_scan (&mpis[i], GCRYMPI_FMT_PGP, ++ readbuf, lb + sizeof (grub_uint16_t), 0)) ++ goto fail; ++ grub_dprintf ("crypt", "alive\n"); ++ } ++ ++ if (pkey) ++ sk = grub_crypto_pk_locate_subkey (keyid, pkey); ++ else ++ sk = grub_crypto_pk_locate_subkey_in_trustdb (keyid); ++ if (!sk) ++ { ++ /* TRANSLATORS: %08x is 32-bit key id. */ ++ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("public key %08x not found"), ++ keyid); ++ goto fail; ++ } ++ ++ if (pkalgos[pk].pad (&hmpi, hval, ctxt->hash, sk)) ++ goto fail; ++ if (!*pkalgos[pk].algo) ++ { ++ grub_dl_load (pkalgos[pk].module); ++ grub_errno = GRUB_ERR_NONE; ++ } ++ ++ if (!*pkalgos[pk].algo) ++ { ++ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("module `%s' isn't loaded"), ++ pkalgos[pk].module); ++ goto fail; ++ } ++ if ((*pkalgos[pk].algo)->verify (0, hmpi, mpis, sk->mpis, 0, 0)) ++ goto fail; ++ ++ grub_free (readbuf); ++ ++ return GRUB_ERR_NONE; ++ ++ fail: ++ grub_free (readbuf); ++ if (!grub_errno) ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature")); ++ return grub_errno; ++} ++ ++static void ++grub_pubkey_close_real (struct grub_pubkey_context *ctxt) ++{ ++ if (ctxt->sig) ++ grub_file_close (ctxt->sig); ++ if (ctxt->hash_context) ++ grub_free (ctxt->hash_context); ++} ++ ++static void ++grub_pubkey_close (void *ctxt) ++{ ++ grub_pubkey_close_real (ctxt); ++ grub_free (ctxt); + } + + grub_err_t + grub_verify_signature (grub_file_t f, grub_file_t sig, + struct grub_public_key *pkey) + { +- return grub_verify_signature_real (0, 0, f, sig, pkey); ++ grub_err_t err; ++ struct grub_pubkey_context ctxt; ++ grub_uint8_t *readbuf = NULL; ++ ++ err = grub_verify_signature_init (&ctxt, sig); ++ if (err) ++ return err; ++ ++ readbuf = grub_zalloc (READBUF_SIZE); ++ if (!readbuf) ++ goto fail; ++ ++ while (1) ++ { ++ grub_ssize_t r; ++ r = grub_file_read (f, readbuf, READBUF_SIZE); ++ if (r < 0) ++ goto fail; ++ if (r == 0) ++ break; ++ err = grub_pubkey_write (&ctxt, readbuf, r); ++ if (err) ++ return err; ++ } ++ ++ grub_verify_signature_real (&ctxt, pkey); ++ fail: ++ grub_pubkey_close_real (&ctxt); ++ return grub_errno; + } + + static grub_err_t +@@ -819,134 +867,52 @@ grub_cmd_verify_signature (grub_extcmd_context_t ctxt, + + static int sec = 0; + +-static void +-verified_free (grub_verified_t verified) +-{ +- if (verified) +- { +- grub_free (verified->buf); +- grub_free (verified); +- } +-} +- +-static grub_ssize_t +-verified_read (struct grub_file *file, char *buf, grub_size_t len) +-{ +- grub_verified_t verified = file->data; +- +- grub_memcpy (buf, (char *) verified->buf + file->offset, len); +- return len; +-} +- + static grub_err_t +-verified_close (struct grub_file *file) +-{ +- grub_verified_t verified = file->data; +- +- grub_file_close (verified->file); +- verified_free (verified); +- file->data = 0; +- +- /* device and name are freed by parent */ +- file->device = 0; +- file->name = 0; +- +- return grub_errno; +-} +- +-struct grub_fs verified_fs = +-{ +- .name = "verified_read", +- .read = verified_read, +- .close = verified_close +-}; +- +-static grub_file_t +-grub_pubkey_open (grub_file_t io, enum grub_file_type type) ++grub_pubkey_init (grub_file_t io, enum grub_file_type type __attribute__ ((unused)), ++ void **context, enum grub_verify_flags *flags) + { + grub_file_t sig; + char *fsuf, *ptr; + grub_err_t err; +- grub_file_t ret; +- grub_verified_t verified; +- +- if ((type & GRUB_FILE_TYPE_MASK) == GRUB_FILE_TYPE_SIGNATURE +- || (type & GRUB_FILE_TYPE_MASK) == GRUB_FILE_TYPE_VERIFY_SIGNATURE +- || (type & GRUB_FILE_TYPE_SKIP_SIGNATURE)) +- return io; ++ struct grub_pubkey_context *ctxt; + + if (!sec) +- return io; +- if (io->device->disk && +- (io->device->disk->dev->id == GRUB_DISK_DEVICE_MEMDISK_ID +- || io->device->disk->dev->id == GRUB_DISK_DEVICE_PROCFS_ID)) +- return io; ++ { ++ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; ++ return GRUB_ERR_NONE; ++ } ++ + fsuf = grub_malloc (grub_strlen (io->name) + sizeof (".sig")); + if (!fsuf) +- return NULL; ++ return grub_errno; + ptr = grub_stpcpy (fsuf, io->name); + grub_memcpy (ptr, ".sig", sizeof (".sig")); + + sig = grub_file_open (fsuf, GRUB_FILE_TYPE_SIGNATURE); + grub_free (fsuf); + if (!sig) +- return NULL; ++ return grub_errno; + +- ret = grub_malloc (sizeof (*ret)); +- if (!ret) ++ ctxt = grub_malloc (sizeof (*ctxt)); ++ if (!ctxt) + { + grub_file_close (sig); +- return NULL; ++ return grub_errno; + } +- *ret = *io; +- +- ret->fs = &verified_fs; +- ret->not_easily_seekable = 0; +- if (ret->size >> (sizeof (grub_size_t) * GRUB_CHAR_BIT - 1)) +- { +- grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, +- "big file signature isn't implemented yet"); +- grub_file_close (sig); +- grub_free (ret); +- return NULL; +- } +- verified = grub_malloc (sizeof (*verified)); +- if (!verified) +- { +- grub_file_close (sig); +- grub_free (ret); +- return NULL; +- } +- verified->buf = grub_malloc (ret->size); +- if (!verified->buf) +- { +- grub_file_close (sig); +- verified_free (verified); +- grub_free (ret); +- return NULL; +- } +- if (grub_file_read (io, verified->buf, ret->size) != (grub_ssize_t) ret->size) +- { +- if (!grub_errno) +- grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), +- io->name); +- grub_file_close (sig); +- verified_free (verified); +- grub_free (ret); +- return NULL; +- } +- +- err = grub_verify_signature_real (verified->buf, ret->size, 0, sig, NULL); +- grub_file_close (sig); ++ err = grub_verify_signature_init (ctxt, sig); + if (err) + { +- verified_free (verified); +- grub_free (ret); +- return NULL; ++ grub_pubkey_close (ctxt); ++ return err; + } +- verified->file = io; +- ret->data = verified; +- return ret; ++ *context = ctxt; ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_pubkey_fini (void *ctxt) ++{ ++ return grub_verify_signature_real (ctxt, NULL); + } + + static char * +@@ -970,8 +936,16 @@ struct grub_fs pseudo_fs = + { + .name = "pseudo", + .read = pseudo_read +-}; ++ }; + ++struct grub_file_verifier grub_pubkey_verifier = ++ { ++ .name = "pgp", ++ .init = grub_pubkey_init, ++ .fini = grub_pubkey_fini, ++ .write = grub_pubkey_write, ++ .close = grub_pubkey_close, ++ }; + + static grub_extcmd_t cmd, cmd_trust; + static grub_command_t cmd_distrust, cmd_list; +@@ -986,8 +960,6 @@ GRUB_MOD_INIT(verify) + sec = 1; + else + sec = 0; +- +- grub_file_filter_register (GRUB_FILE_FILTER_PUBKEY, grub_pubkey_open); + + grub_register_variable_hook ("check_signatures", 0, grub_env_write_sec); + grub_env_export ("check_signatures"); +@@ -1033,11 +1005,13 @@ GRUB_MOD_INIT(verify) + cmd_distrust = grub_register_command ("distrust", grub_cmd_distrust, + N_("PUBKEY_ID"), + N_("Remove PUBKEY_ID from trusted keys.")); ++ ++ grub_verifier_register (&grub_pubkey_verifier); + } + + GRUB_MOD_FINI(verify) + { +- grub_file_filter_unregister (GRUB_FILE_FILTER_PUBKEY); ++ grub_verifier_unregister (&grub_pubkey_verifier); + grub_unregister_extcmd (cmd); + grub_unregister_extcmd (cmd_trust); + grub_unregister_command (cmd_list); +diff --git a/include/grub/file.h b/include/grub/file.h +index 5b47c5f91f9..19dda67f68b 100644 +--- a/include/grub/file.h ++++ b/include/grub/file.h +@@ -171,7 +171,7 @@ extern grub_disk_read_hook_t EXPORT_VAR(grub_file_progress_hook); + /* Filters with lower ID are executed first. */ + typedef enum grub_file_filter_id + { +- GRUB_FILE_FILTER_PUBKEY, ++ GRUB_FILE_FILTER_VERIFY, + GRUB_FILE_FILTER_GZIO, + GRUB_FILE_FILTER_XZIO, + GRUB_FILE_FILTER_LZOPIO, +diff --git a/include/grub/list.h b/include/grub/list.h +index d170ff6da02..b13acb96243 100644 +--- a/include/grub/list.h ++++ b/include/grub/list.h +@@ -35,6 +35,7 @@ void EXPORT_FUNC(grub_list_push) (grub_list_t *head, grub_list_t item); + void EXPORT_FUNC(grub_list_remove) (grub_list_t item); + + #define FOR_LIST_ELEMENTS(var, list) for ((var) = (list); (var); (var) = (var)->next) ++#define FOR_LIST_ELEMENTS_NEXT(var, list) for ((var) = (var)->next; (var); (var) = (var)->next) + #define FOR_LIST_ELEMENTS_SAFE(var, nxt, list) for ((var) = (list), (nxt) = ((var) ? (var)->next : 0); (var); (var) = (nxt), ((nxt) = (var) ? (var)->next : 0)) + + static inline void * +diff --git a/include/grub/verify.h b/include/grub/verify.h +new file mode 100644 +index 00000000000..298120f5776 +--- /dev/null ++++ b/include/grub/verify.h +@@ -0,0 +1,65 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2017 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 ++ ++enum grub_verify_flags ++ { ++ GRUB_VERIFY_FLAGS_SKIP_VERIFICATION = 1, ++ GRUB_VERIFY_FLAGS_SINGLE_CHUNK = 2 ++ }; ++ ++struct grub_file_verifier ++{ ++ struct grub_file_verifier *next; ++ struct grub_file_verifier **prev; ++ ++ const char *name; ++ ++ /* ++ * Check if file needs to be verified and set up context. ++ * init/read/fini is structured in the same way as hash interface. ++ */ ++ grub_err_t (*init) (grub_file_t io, enum grub_file_type type, ++ void **context, enum grub_verify_flags *flags); ++ ++ /* ++ * Right now we pass the whole file in one call but it may ++ * change in the future. If you insist on single buffer you ++ * need to set GRUB_VERIFY_FLAGS_SINGLE_CHUNK in verify_flags. ++ */ ++ grub_err_t (*write) (void *context, void *buf, grub_size_t size); ++ ++ grub_err_t (*fini) (void *context); ++ void (*close) (void *context); ++}; ++ ++extern struct grub_file_verifier *grub_file_verifiers; ++ ++static inline void ++grub_verifier_register (struct grub_file_verifier *ver) ++{ ++ grub_list_push (GRUB_AS_LIST_P (&grub_file_verifiers), GRUB_AS_LIST (ver)); ++} ++ ++static inline void ++grub_verifier_unregister (struct grub_file_verifier *ver) ++{ ++ grub_list_remove (GRUB_AS_LIST (ver)); ++} diff --git a/SOURCES/0332-mmap-Fix-memory-leak-when-iterating-over-mapped-memo.patch b/SOURCES/0332-mmap-Fix-memory-leak-when-iterating-over-mapped-memo.patch deleted file mode 100644 index 66e3744..0000000 --- a/SOURCES/0332-mmap-Fix-memory-leak-when-iterating-over-mapped-memo.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Thu, 3 Dec 2020 14:39:45 +0000 -Subject: [PATCH] mmap: Fix memory leak when iterating over mapped memory - -When returning from grub_mmap_iterate() the memory allocated to present -is not being released causing it to leak. - -Fixes: CID 96655 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/mmap/mmap.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/grub-core/mmap/mmap.c b/grub-core/mmap/mmap.c -index 7ebf32e1e5e..8bf235f3400 100644 ---- a/grub-core/mmap/mmap.c -+++ b/grub-core/mmap/mmap.c -@@ -270,6 +270,7 @@ grub_mmap_iterate (grub_memory_hook_t hook, void *hook_data) - hook_data)) - { - grub_free (ctx.scanline_events); -+ grub_free (present); - return GRUB_ERR_NONE; - } - -@@ -282,6 +283,7 @@ grub_mmap_iterate (grub_memory_hook_t hook, void *hook_data) - } - - grub_free (ctx.scanline_events); -+ grub_free (present); - return GRUB_ERR_NONE; - } - diff --git a/SOURCES/0332-verifiers-Add-possibility-to-verify-kernel-and-modul.patch b/SOURCES/0332-verifiers-Add-possibility-to-verify-kernel-and-modul.patch new file mode 100644 index 0000000..b6265b2 --- /dev/null +++ b/SOURCES/0332-verifiers-Add-possibility-to-verify-kernel-and-modul.patch @@ -0,0 +1,520 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Vladimir Serbinenko +Date: Tue, 7 Feb 2017 02:10:14 +0100 +Subject: [PATCH] verifiers: Add possibility to verify kernel and modules + command lines + +Signed-off-by: Vladimir Serbinenko +Signed-off-by: Daniel Kiper +Reviewed-by: Ross Philipson +(backported from 4d4a8c96e3593d76fe7b025665ccdecc70a53c1f) +Signed-off-by: Daniel Axtens +--- + grub-core/commands/verifiers.c | 14 ++++++++++++++ + grub-core/lib/cmdline.c | 7 ++++--- + grub-core/loader/arm/linux.c | 8 ++++++-- + grub-core/loader/arm64/linux.c | 10 +++++++--- + grub-core/loader/i386/bsd.c | 6 ++++++ + grub-core/loader/i386/linux.c | 16 +++++++++++----- + grub-core/loader/i386/multiboot_mbi.c | 16 ++++++++++------ + grub-core/loader/i386/pc/linux.c | 13 ++++++++----- + grub-core/loader/i386/pc/plan9.c | 11 +++++++++++ + grub-core/loader/i386/xen.c | 7 +++++++ + grub-core/loader/ia64/efi/linux.c | 7 +++++++ + grub-core/loader/mips/linux.c | 8 ++++++++ + grub-core/loader/multiboot_mbi2.c | 8 +++----- + grub-core/loader/powerpc/ieee1275/linux.c | 5 +++-- + grub-core/loader/sparc64/ieee1275/linux.c | 5 +++-- + grub-core/loader/xnu.c | 9 +++++++++ + include/grub/lib/cmdline.h | 5 +++-- + include/grub/verify.h | 11 +++++++++++ + 18 files changed, 131 insertions(+), 35 deletions(-) + +diff --git a/grub-core/commands/verifiers.c b/grub-core/commands/verifiers.c +index fde88318d4c..59ea418a2d9 100644 +--- a/grub-core/commands/verifiers.c ++++ b/grub-core/commands/verifiers.c +@@ -186,6 +186,20 @@ grub_verifiers_open (grub_file_t io, enum grub_file_type type) + return NULL; + } + ++grub_err_t ++grub_verify_string (char *str, enum grub_verify_string_type type) ++{ ++ struct grub_file_verifier *ver; ++ FOR_LIST_ELEMENTS(ver, grub_file_verifiers) ++ { ++ grub_err_t err; ++ err = ver->verify_string ? ver->verify_string (str, type) : GRUB_ERR_NONE; ++ if (err) ++ return err; ++ } ++ return GRUB_ERR_NONE; ++} ++ + GRUB_MOD_INIT(verifiers) + { + grub_file_filter_register (GRUB_FILE_FILTER_VERIFY, grub_verifiers_open); +diff --git a/grub-core/lib/cmdline.c b/grub-core/lib/cmdline.c +index d5c12957cad..463c3c65c79 100644 +--- a/grub-core/lib/cmdline.c ++++ b/grub-core/lib/cmdline.c +@@ -75,8 +75,9 @@ unsigned int grub_loader_cmdline_size (int argc, char *argv[]) + return size; + } + +-int grub_create_loader_cmdline (int argc, char *argv[], char *buf, +- grub_size_t size) ++grub_err_t ++grub_create_loader_cmdline (int argc, char *argv[], char *buf, ++ grub_size_t size, enum grub_verify_string_type type) + { + int i, space; + unsigned int arg_size; +@@ -130,5 +131,5 @@ int grub_create_loader_cmdline (int argc, char *argv[], char *buf, + "grub_kernel_cmdline", orig); + grub_print_error(); + +- return i; ++ return grub_verify_string (orig, type); + } +diff --git a/grub-core/loader/arm/linux.c b/grub-core/loader/arm/linux.c +index ea29d7a724a..beceda52030 100644 +--- a/grub-core/loader/arm/linux.c ++++ b/grub-core/loader/arm/linux.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -383,8 +384,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + /* Create kernel command line. */ + grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE)); +- grub_create_loader_cmdline (argc, argv, +- linux_args + sizeof (LINUX_IMAGE) - 1, size); ++ err = grub_create_loader_cmdline (argc, argv, ++ linux_args + sizeof (LINUX_IMAGE) - 1, size, ++ GRUB_VERIFY_KERNEL_CMDLINE); ++ if (err) ++ goto fail; + + return GRUB_ERR_NONE; + +diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c +index 7a076c13171..48ea66596ad 100644 +--- a/grub-core/loader/arm64/linux.c ++++ b/grub-core/loader/arm64/linux.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -403,9 +404,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE)); +- grub_create_loader_cmdline (argc, argv, +- linux_args + sizeof (LINUX_IMAGE) - 1, +- cmdline_size); ++ 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) + { +diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c +index 8306b415abd..45a71509956 100644 +--- a/grub-core/loader/i386/bsd.c ++++ b/grub-core/loader/i386/bsd.c +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + #ifdef GRUB_MACHINE_PCBIOS + #include + #endif +@@ -418,6 +419,8 @@ grub_freebsd_add_meta_module (const char *filename, const char *type, + grub_addr_t addr, grub_uint32_t size) + { + const char *name; ++ grub_err_t err; ++ + name = grub_strrchr (filename, '/'); + if (name) + name++; +@@ -471,6 +474,9 @@ grub_freebsd_add_meta_module (const char *filename, const char *type, + *(p++) = ' '; + } + *p = 0; ++ err = grub_verify_string (cmdline, GRUB_VERIFY_MODULE_CMDLINE); ++ if (err) ++ return err; + } + } + +diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c +index aa2cbc4e7eb..ef8fcb9e1b6 100644 +--- a/grub-core/loader/i386/linux.c ++++ b/grub-core/loader/i386/linux.c +@@ -1039,11 +1039,17 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + if (!linux_cmdline) + goto fail; + grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); +- grub_create_loader_cmdline (argc, argv, +- linux_cmdline +- + sizeof (LINUX_IMAGE) - 1, +- maximal_cmdline_size +- - (sizeof (LINUX_IMAGE) - 1)); ++ { ++ grub_err_t err; ++ err = grub_create_loader_cmdline (argc, argv, ++ linux_cmdline ++ + sizeof (LINUX_IMAGE) - 1, ++ maximal_cmdline_size ++ - (sizeof (LINUX_IMAGE) - 1), ++ GRUB_VERIFY_KERNEL_CMDLINE); ++ if (err) ++ goto fail; ++ } + + len = prot_file_size; + grub_memcpy (prot_mode_mem, kernel + kernel_offset, len); +diff --git a/grub-core/loader/i386/multiboot_mbi.c b/grub-core/loader/i386/multiboot_mbi.c +index 9d3466d6ace..525446b5687 100644 +--- a/grub-core/loader/i386/multiboot_mbi.c ++++ b/grub-core/loader/i386/multiboot_mbi.c +@@ -676,10 +676,8 @@ grub_multiboot_init_mbi (int argc, char *argv[]) + return grub_errno; + cmdline_size = len; + +- grub_create_loader_cmdline (argc, argv, cmdline, +- cmdline_size); +- +- return GRUB_ERR_NONE; ++ return grub_create_loader_cmdline (argc, argv, cmdline, ++ cmdline_size, GRUB_VERIFY_KERNEL_CMDLINE); + } + + grub_err_t +@@ -688,6 +686,7 @@ grub_multiboot_add_module (grub_addr_t start, grub_size_t size, + { + struct module *newmod; + grub_size_t len = 0; ++ grub_err_t err; + + newmod = grub_malloc (sizeof (*newmod)); + if (!newmod) +@@ -707,8 +706,13 @@ grub_multiboot_add_module (grub_addr_t start, grub_size_t size, + newmod->cmdline_size = len; + total_modcmd += ALIGN_UP (len, 4); + +- grub_create_loader_cmdline (argc, argv, newmod->cmdline, +- newmod->cmdline_size); ++ err = grub_create_loader_cmdline (argc, argv, newmod->cmdline, ++ newmod->cmdline_size, GRUB_VERIFY_MODULE_CMDLINE); ++ if (err) ++ { ++ grub_free (newmod); ++ return grub_errno; ++ } + + if (modules_last) + modules_last->next = newmod; +diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c +index b5c28c6580e..f631225f59b 100644 +--- a/grub-core/loader/i386/pc/linux.c ++++ b/grub-core/loader/i386/pc/linux.c +@@ -348,11 +348,14 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + /* Create kernel command line. */ + grub_memcpy ((char *)grub_linux_real_chunk + GRUB_LINUX_CL_OFFSET, + LINUX_IMAGE, sizeof (LINUX_IMAGE)); +- grub_create_loader_cmdline (argc, argv, +- (char *)grub_linux_real_chunk +- + GRUB_LINUX_CL_OFFSET + sizeof (LINUX_IMAGE) - 1, +- maximal_cmdline_size +- - (sizeof (LINUX_IMAGE) - 1)); ++ err = grub_create_loader_cmdline (argc, argv, ++ (char *)grub_linux_real_chunk ++ + GRUB_LINUX_CL_OFFSET + sizeof (LINUX_IMAGE) - 1, ++ maximal_cmdline_size ++ - (sizeof (LINUX_IMAGE) - 1), ++ GRUB_VERIFY_KERNEL_CMDLINE); ++ if (err) ++ goto fail; + + if (grub_linux_is_bzimage) + grub_linux_prot_target = GRUB_LINUX_BZIMAGE_ADDR; +diff --git a/grub-core/loader/i386/pc/plan9.c b/grub-core/loader/i386/pc/plan9.c +index 0351090daf8..37550155df7 100644 +--- a/grub-core/loader/i386/pc/plan9.c ++++ b/grub-core/loader/i386/pc/plan9.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -505,6 +506,7 @@ grub_cmd_plan9 (grub_extcmd_context_t ctxt, int argc, char *argv[]) + configptr = grub_stpcpy (configptr, "bootfile="); + configptr = grub_stpcpy (configptr, bootpath); + *configptr++ = '\n'; ++ char *cmdline = configptr; + { + int i; + for (i = 1; i < argc; i++) +@@ -513,6 +515,15 @@ grub_cmd_plan9 (grub_extcmd_context_t ctxt, int argc, char *argv[]) + *configptr++ = '\n'; + } + } ++ ++ { ++ grub_err_t err; ++ *configptr = '\0'; ++ err = grub_verify_string (cmdline, GRUB_VERIFY_KERNEL_CMDLINE); ++ if (err) ++ goto fail; ++ } ++ + configptr = grub_stpcpy (configptr, fill_ctx.pmap); + + { +diff --git a/grub-core/loader/i386/xen.c b/grub-core/loader/i386/xen.c +index 82350d3a178..07a4837c532 100644 +--- a/grub-core/loader/i386/xen.c ++++ b/grub-core/loader/i386/xen.c +@@ -41,6 +41,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -649,6 +650,9 @@ grub_cmd_xen (grub_command_t cmd __attribute__ ((unused)), + grub_create_loader_cmdline (argc - 1, argv + 1, + (char *) xen_state.next_start.cmd_line, + sizeof (xen_state.next_start.cmd_line) - 1); ++ err = grub_verify_string (xen_state.next_start.cmd_line, GRUB_VERIFY_MODULE_CMDLINE); ++ if (err) ++ return err; + + file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); + if (!file) +@@ -916,6 +920,9 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)), + + grub_create_loader_cmdline (argc - 1, argv + 1, + get_virtual_current_address (ch), cmdline_len); ++ err = grub_verify_string (get_virtual_current_address (ch), GRUB_VERIFY_MODULE_CMDLINE); ++ if (err) ++ goto fail; + + xen_state.module_info_page[xen_state.n_modules].cmdline = + xen_state.max_addr - xen_state.modules_target_start; +diff --git a/grub-core/loader/ia64/efi/linux.c b/grub-core/loader/ia64/efi/linux.c +index 750330d4572..e325fe0ee83 100644 +--- a/grub-core/loader/ia64/efi/linux.c ++++ b/grub-core/loader/ia64/efi/linux.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -543,6 +544,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + p = grub_stpcpy (p, argv[i]); + } + cmdline[10] = '='; ++ ++ *p = '\0'; ++ ++ err = grub_verify_string (cmdline, GRUB_VERIFY_KERNEL_CMDLINE); ++ if (err) ++ goto fail; + + boot_param->command_line = (grub_uint64_t) cmdline; + boot_param->efi_systab = (grub_uint64_t) grub_efi_system_table; +diff --git a/grub-core/loader/mips/linux.c b/grub-core/loader/mips/linux.c +index 10358854458..20135ce253d 100644 +--- a/grub-core/loader/mips/linux.c ++++ b/grub-core/loader/mips/linux.c +@@ -327,6 +327,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + linux_argv++; + linux_args += ALIGN_UP (sizeof ("a0"), 4); + ++ char *params = linux_args; ++ + #ifdef GRUB_MACHINE_MIPS_LOONGSON + { + unsigned mtype = grub_arch_machine; +@@ -352,6 +354,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + linux_args += ALIGN_UP (grub_strlen (argv[i]) + 1, 4); + } + ++ *linux_args = '\0'; ++ ++ err = grub_verify_string (params, GRUB_VERIFY_KERNEL_CMDLINE); ++ if (err) ++ return err; ++ + /* Reserve space for rd arguments. */ + rd_addr_arg_off = (grub_uint8_t *) linux_args - (grub_uint8_t *) playground; + linux_args += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4); +diff --git a/grub-core/loader/multiboot_mbi2.c b/grub-core/loader/multiboot_mbi2.c +index 3cfb47650a0..f64a857e394 100644 +--- a/grub-core/loader/multiboot_mbi2.c ++++ b/grub-core/loader/multiboot_mbi2.c +@@ -1077,10 +1077,8 @@ grub_multiboot2_init_mbi (int argc, char *argv[]) + return grub_errno; + cmdline_size = len; + +- grub_create_loader_cmdline (argc, argv, cmdline, +- cmdline_size); +- +- return GRUB_ERR_NONE; ++ return grub_create_loader_cmdline (argc, argv, cmdline, cmdline_size, ++ GRUB_VERIFY_KERNEL_CMDLINE); + } + + grub_err_t +@@ -1109,7 +1107,7 @@ grub_multiboot2_add_module (grub_addr_t start, grub_size_t size, + total_modcmd += ALIGN_UP (len, MULTIBOOT_TAG_ALIGN); + + err = grub_create_loader_cmdline (argc, argv, newmod->cmdline, +- newmod->cmdline_size); ++ newmod->cmdline_size, GRUB_VERIFY_MODULE_CMDLINE); + if (err) + { + grub_free (newmod->cmdline); +diff --git a/grub-core/loader/powerpc/ieee1275/linux.c b/grub-core/loader/powerpc/ieee1275/linux.c +index 6e814649f31..c114e7df4fb 100644 +--- a/grub-core/loader/powerpc/ieee1275/linux.c ++++ b/grub-core/loader/powerpc/ieee1275/linux.c +@@ -302,8 +302,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + /* Create kernel command line. */ + grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE)); +- grub_create_loader_cmdline (argc, argv, linux_args + sizeof (LINUX_IMAGE) - 1, +- size); ++ if (grub_create_loader_cmdline (argc, argv, linux_args + sizeof (LINUX_IMAGE) - 1, ++ size)) ++ goto out; + + out: + +diff --git a/grub-core/loader/sparc64/ieee1275/linux.c b/grub-core/loader/sparc64/ieee1275/linux.c +index 67ef0488324..abe46faa012 100644 +--- a/grub-core/loader/sparc64/ieee1275/linux.c ++++ b/grub-core/loader/sparc64/ieee1275/linux.c +@@ -340,8 +340,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + /* Create kernel command line. */ + grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE)); +- grub_create_loader_cmdline (argc, argv, linux_args + sizeof (LINUX_IMAGE) - 1, +- size); ++ if (grub_create_loader_cmdline (argc, argv, linux_args + sizeof (LINUX_IMAGE) - 1, ++ size, GRUB_VERIFY_KERNEL_CMDLINE)) ++ goto out; + + out: + if (elf) +diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c +index 9f78abb05f9..5944dc5eafc 100644 +--- a/grub-core/loader/xnu.c ++++ b/grub-core/loader/xnu.c +@@ -35,6 +35,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -429,6 +430,10 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)), + if (ptr != grub_xnu_cmdline) + *(ptr - 1) = 0; + ++ err = grub_verify_string (grub_xnu_cmdline, GRUB_VERIFY_KERNEL_CMDLINE); ++ if (err) ++ return err; ++ + #if defined (__i386) && !defined (GRUB_MACHINE_EFI) + err = grub_efiemu_autocore (); + if (err) +@@ -538,6 +543,10 @@ grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)), + if (ptr != grub_xnu_cmdline) + *(ptr - 1) = 0; + ++ err = grub_verify_string (grub_xnu_cmdline, GRUB_VERIFY_KERNEL_CMDLINE); ++ if (err) ++ return err; ++ + #if defined (__i386) && !defined (GRUB_MACHINE_EFI) + err = grub_efiemu_autocore (); + if (err) +diff --git a/include/grub/lib/cmdline.h b/include/grub/lib/cmdline.h +index 1fe8d017971..cdca09b7a16 100644 +--- a/include/grub/lib/cmdline.h ++++ b/include/grub/lib/cmdline.h +@@ -21,11 +21,12 @@ + #define GRUB_CMDLINE_HEADER 1 + + #include ++#include + + #define LINUX_IMAGE "BOOT_IMAGE=" + + unsigned int grub_loader_cmdline_size (int argc, char *argv[]); +-int grub_create_loader_cmdline (int argc, char *argv[], char *buf, +- grub_size_t size); ++grub_err_t grub_create_loader_cmdline (int argc, char *argv[], char *buf, ++ grub_size_t size, enum grub_verify_string_type type); + + #endif /* ! GRUB_CMDLINE_HEADER */ +diff --git a/include/grub/verify.h b/include/grub/verify.h +index 298120f5776..9f892d8fedb 100644 +--- a/include/grub/verify.h ++++ b/include/grub/verify.h +@@ -25,6 +25,12 @@ enum grub_verify_flags + GRUB_VERIFY_FLAGS_SINGLE_CHUNK = 2 + }; + ++enum grub_verify_string_type ++ { ++ GRUB_VERIFY_KERNEL_CMDLINE, ++ GRUB_VERIFY_MODULE_CMDLINE, ++ }; ++ + struct grub_file_verifier + { + struct grub_file_verifier *next; +@@ -48,6 +54,8 @@ struct grub_file_verifier + + grub_err_t (*fini) (void *context); + void (*close) (void *context); ++ ++ grub_err_t (*verify_string) (char *str, enum grub_verify_string_type type); + }; + + extern struct grub_file_verifier *grub_file_verifiers; +@@ -63,3 +71,6 @@ grub_verifier_unregister (struct grub_file_verifier *ver) + { + grub_list_remove (GRUB_AS_LIST (ver)); + } ++ ++grub_err_t ++grub_verify_string (char *str, enum grub_verify_string_type type); diff --git a/SOURCES/0333-net-net-Fix-possible-dereference-to-of-a-NULL-pointe.patch b/SOURCES/0333-net-net-Fix-possible-dereference-to-of-a-NULL-pointe.patch deleted file mode 100644 index b70fd47..0000000 --- a/SOURCES/0333-net-net-Fix-possible-dereference-to-of-a-NULL-pointe.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Fri, 27 Nov 2020 15:10:26 +0000 -Subject: [PATCH] net/net: Fix possible dereference to of a NULL pointer - -It is always possible that grub_zalloc() could fail, so we should check for -a NULL return. Otherwise we run the risk of dereferencing a NULL pointer. - -Fixes: CID 296221 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/net/net.c | 9 +++++++-- - 1 file changed, 7 insertions(+), 2 deletions(-) - -diff --git a/grub-core/net/net.c b/grub-core/net/net.c -index 0e72bbb9b39..50d0609038c 100644 ---- a/grub-core/net/net.c -+++ b/grub-core/net/net.c -@@ -89,8 +89,13 @@ grub_net_link_layer_add_address (struct grub_net_card *card, - - /* Add sender to cache table. */ - if (card->link_layer_table == NULL) -- card->link_layer_table = grub_zalloc (LINK_LAYER_CACHE_SIZE -- * sizeof (card->link_layer_table[0])); -+ { -+ card->link_layer_table = grub_zalloc (LINK_LAYER_CACHE_SIZE -+ * sizeof (card->link_layer_table[0])); -+ if (card->link_layer_table == NULL) -+ return; -+ } -+ - entry = &(card->link_layer_table[card->new_ll_entry]); - entry->avail = 1; - grub_memcpy (&entry->ll_address, ll, sizeof (entry->ll_address)); diff --git a/SOURCES/0333-verifiers-Add-possibility-to-defer-verification-to-o.patch b/SOURCES/0333-verifiers-Add-possibility-to-defer-verification-to-o.patch new file mode 100644 index 0000000..bddb30e --- /dev/null +++ b/SOURCES/0333-verifiers-Add-possibility-to-defer-verification-to-o.patch @@ -0,0 +1,91 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Kiper +Date: Wed, 26 Sep 2018 13:17:52 +0200 +Subject: [PATCH] verifiers: Add possibility to defer verification to other + verifiers + +This way if a verifier requires verification of a given file it can defer task +to another verifier (another authority) if it is not able to do it itself. E.g. +shim_lock verifier, posted as a subsequent patch, is able to verify only PE +files. This means that it is not able to verify any of GRUB2 modules which have +to be trusted on UEFI systems with secure boot enabled. So, it can defer +verification to other verifier, e.g. PGP one. + +I silently assume that other verifiers are trusted and will do good job for us. +Or at least they will not do any harm. + +Signed-off-by: Daniel Kiper +Reviewed-by: Ross Philipson +--- + grub-core/commands/verifiers.c | 23 ++++++++++++++++++++--- + include/grub/verify.h | 4 +++- + 2 files changed, 23 insertions(+), 4 deletions(-) + +diff --git a/grub-core/commands/verifiers.c b/grub-core/commands/verifiers.c +index 59ea418a2d9..c638d5f43e0 100644 +--- a/grub-core/commands/verifiers.c ++++ b/grub-core/commands/verifiers.c +@@ -83,6 +83,7 @@ grub_verifiers_open (grub_file_t io, enum grub_file_type type) + void *context; + grub_file_t ret = 0; + grub_err_t err; ++ int defer = 0; + + grub_dprintf ("verify", "file: %s type: %d\n", io->name, type); + +@@ -102,13 +103,27 @@ grub_verifiers_open (grub_file_t io, enum grub_file_type type) + err = ver->init (io, type, &context, &flags); + if (err) + goto fail_noclose; ++ if (flags & GRUB_VERIFY_FLAGS_DEFER_AUTH) ++ { ++ defer = 1; ++ continue; ++ } + if (!(flags & GRUB_VERIFY_FLAGS_SKIP_VERIFICATION)) + break; + } + + if (!ver) +- /* No verifiers wanted to verify. Just return underlying file. */ +- return io; ++ { ++ if (defer) ++ { ++ grub_error (GRUB_ERR_ACCESS_DENIED, ++ N_("verification requested but nobody cares: %s"), io->name); ++ goto fail_noclose; ++ } ++ ++ /* No verifiers wanted to verify. Just return underlying file. */ ++ return io; ++ } + + ret = grub_malloc (sizeof (*ret)); + if (!ret) +@@ -160,7 +175,9 @@ grub_verifiers_open (grub_file_t io, enum grub_file_type type) + err = ver->init (io, type, &context, &flags); + if (err) + goto fail_noclose; +- if (flags & GRUB_VERIFY_FLAGS_SKIP_VERIFICATION) ++ if (flags & GRUB_VERIFY_FLAGS_SKIP_VERIFICATION || ++ /* Verification done earlier. So, we are happy here. */ ++ flags & GRUB_VERIFY_FLAGS_DEFER_AUTH) + continue; + err = ver->write (context, verified->buf, ret->size); + if (err) +diff --git a/include/grub/verify.h b/include/grub/verify.h +index 9f892d8fedb..79022b42258 100644 +--- a/include/grub/verify.h ++++ b/include/grub/verify.h +@@ -22,7 +22,9 @@ + enum grub_verify_flags + { + GRUB_VERIFY_FLAGS_SKIP_VERIFICATION = 1, +- GRUB_VERIFY_FLAGS_SINGLE_CHUNK = 2 ++ GRUB_VERIFY_FLAGS_SINGLE_CHUNK = 2, ++ /* Defer verification to another authority. */ ++ GRUB_VERIFY_FLAGS_DEFER_AUTH = 4 + }; + + enum grub_verify_string_type diff --git a/SOURCES/0334-net-tftp-Fix-dangling-memory-pointer.patch b/SOURCES/0334-net-tftp-Fix-dangling-memory-pointer.patch deleted file mode 100644 index 193d893..0000000 --- a/SOURCES/0334-net-tftp-Fix-dangling-memory-pointer.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Fri, 19 Feb 2021 17:12:23 +0000 -Subject: [PATCH] net/tftp: Fix dangling memory pointer - -The static code analysis tool, Parfait, reported that the valid of -file->data was left referencing memory that was freed by the call to -grub_free(data) where data was initialized from file->data. - -To ensure that there is no unintentional access to this memory -referenced by file->data we should set the pointer to NULL. - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/net/tftp.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c -index b9a4b607a3d..aa0424dcee3 100644 ---- a/grub-core/net/tftp.c -+++ b/grub-core/net/tftp.c -@@ -444,6 +444,7 @@ tftp_close (struct grub_file *file) - grub_net_udp_close (data->sock); - } - grub_free (data); -+ file->data = NULL; - return GRUB_ERR_NONE; - } - diff --git a/SOURCES/0334-verifiers-Rename-verify-module-to-pgp-module.patch b/SOURCES/0334-verifiers-Rename-verify-module-to-pgp-module.patch new file mode 100644 index 0000000..40363f2 --- /dev/null +++ b/SOURCES/0334-verifiers-Rename-verify-module-to-pgp-module.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Kiper +Date: Tue, 2 Oct 2018 22:36:43 +0200 +Subject: [PATCH] verifiers: Rename verify module to pgp module + +Just for clarity. No functional change. + +Signed-off-by: Daniel Kiper +Reviewed-by: Ross Philipson +(cherry picked from commit b07feb8746c3bb845e3f0d33d37c0bded704d14d) +Signed-off-by: Daniel Axtens +--- + grub-core/Makefile.core.def | 4 ++-- + grub-core/commands/{verify.c => pgp.c} | 0 + 2 files changed, 2 insertions(+), 2 deletions(-) + rename grub-core/commands/{verify.c => pgp.c} (100%) + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 29c3bf6cd66..809f11feaef 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -915,8 +915,8 @@ module = { + }; + + module = { +- name = verify; +- common = commands/verify.c; ++ name = pgp; ++ common = commands/pgp.c; + cflags = '$(CFLAGS_POSIX)'; + cppflags = '-I$(srcdir)/lib/posix_wrap'; + }; +diff --git a/grub-core/commands/verify.c b/grub-core/commands/pgp.c +similarity index 100% +rename from grub-core/commands/verify.c +rename to grub-core/commands/pgp.c diff --git a/SOURCES/0335-kern-parser-Fix-resource-leak-if-argc-0.patch b/SOURCES/0335-kern-parser-Fix-resource-leak-if-argc-0.patch deleted file mode 100644 index 87d3140..0000000 --- a/SOURCES/0335-kern-parser-Fix-resource-leak-if-argc-0.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Fri, 22 Jan 2021 12:32:41 +0000 -Subject: [PATCH] kern/parser: Fix resource leak if argc == 0 - -After processing the command-line yet arriving at the point where we are -setting argv, we are allocating memory, even if argc == 0, which makes -no sense since we never put anything into the allocated argv. - -The solution is to simply return that we've successfully processed the -arguments but that argc == 0, and also ensure that argv is NULL when -we're not allocating anything in it. - -There are only 2 callers of this function, and both are handling a zero -value in argc assuming nothing is allocated in argv. - -Fixes: CID 96680 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/kern/parser.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/grub-core/kern/parser.c b/grub-core/kern/parser.c -index 619db3122a0..d1cf061ad68 100644 ---- a/grub-core/kern/parser.c -+++ b/grub-core/kern/parser.c -@@ -146,6 +146,7 @@ grub_parser_split_cmdline (const char *cmdline, - int i; - - *argc = 0; -+ *argv = NULL; - do - { - if (!rd || !*rd) -@@ -207,6 +208,10 @@ grub_parser_split_cmdline (const char *cmdline, - (*argc)++; - } - -+ /* If there are no args, then we're done. */ -+ if (!*argc) -+ return 0; -+ - /* Reserve memory for the return values. */ - args = grub_malloc (bp - buffer); - if (!args) diff --git a/SOURCES/0335-pgp-Fix-emu-build-and-tests-after-pgp-module-renamin.patch b/SOURCES/0335-pgp-Fix-emu-build-and-tests-after-pgp-module-renamin.patch new file mode 100644 index 0000000..5813141 --- /dev/null +++ b/SOURCES/0335-pgp-Fix-emu-build-and-tests-after-pgp-module-renamin.patch @@ -0,0 +1,55 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Colin Watson +Date: Wed, 9 Jan 2019 14:54:39 +0000 +Subject: [PATCH] pgp: Fix emu build and tests after pgp module renaming + +Commit b07feb8746c3bb845e3f0d33d37c0bded704d14d (verifiers: Rename +verify module to pgp module) renamed the "verify" module to "pgp", but +the GRUB_MOD_INIT and GRUB_MOD_FINI macros were left as "verify", which +broke the emu target build; and file_filter_test still referred to the +now non-existent "verify" module. Fix both of these. + +Signed-off-by: Colin Watson +Reviewed-by: Daniel Kiper +(cherry picked from commit ed087f0460516737e174222f01e2bf6ccbd45674) +Signed-off-by: Daniel Axtens +--- + grub-core/commands/pgp.c | 4 ++-- + tests/file_filter_test.in | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c +index 29e74a64004..5c913c2e2fe 100644 +--- a/grub-core/commands/pgp.c ++++ b/grub-core/commands/pgp.c +@@ -950,7 +950,7 @@ struct grub_file_verifier grub_pubkey_verifier = + static grub_extcmd_t cmd, cmd_trust; + static grub_command_t cmd_distrust, cmd_list; + +-GRUB_MOD_INIT(verify) ++GRUB_MOD_INIT(pgp) + { + const char *val; + struct grub_module_header *header; +@@ -1009,7 +1009,7 @@ GRUB_MOD_INIT(verify) + grub_verifier_register (&grub_pubkey_verifier); + } + +-GRUB_MOD_FINI(verify) ++GRUB_MOD_FINI(pgp) + { + grub_verifier_unregister (&grub_pubkey_verifier); + grub_unregister_extcmd (cmd); +diff --git a/tests/file_filter_test.in b/tests/file_filter_test.in +index bfb6382274e..ed6abcb5af4 100644 +--- a/tests/file_filter_test.in ++++ b/tests/file_filter_test.in +@@ -19,7 +19,7 @@ grubshell=@builddir@/grub-shell + + . "@builddir@/grub-core/modinfo.sh" + +-filters="gzio xzio lzopio verify" ++filters="gzio xzio lzopio pgp" + modules="cat mpi" + + for mod in $(cut -d ' ' -f 2 "@builddir@/grub-core/crypto.lst" | sort -u); do diff --git a/SOURCES/0336-include-grub-file.h-Add-device-tree-file-type.patch b/SOURCES/0336-include-grub-file.h-Add-device-tree-file-type.patch new file mode 100644 index 0000000..04e16fc --- /dev/null +++ b/SOURCES/0336-include-grub-file.h-Add-device-tree-file-type.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Leif Lindholm +Date: Wed, 14 Nov 2018 19:29:16 +0000 +Subject: [PATCH] include/grub/file.h: Add device tree file type + +The API change of grub_file_open() for adding verifiers did not include +a type for device tree blobs. Add GRUB_FILE_TYPE_DEVICE_TREE_IMAGE to +the grub_file_type enum. + +Signed-off-by: Leif Lindholm +Reviewed-by: Daniel Kiper +(cherry picked from commit 7453c2cc32525a5eebe3b268433d0dfc73622917) +Signed-off-by: Daniel Axtens +--- + include/grub/file.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/include/grub/file.h b/include/grub/file.h +index 19dda67f68b..9aae463557a 100644 +--- a/include/grub/file.h ++++ b/include/grub/file.h +@@ -69,6 +69,8 @@ enum grub_file_type + + GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE, + ++ GRUB_FILE_TYPE_DEVICE_TREE_IMAGE, ++ + /* File holding signature. */ + GRUB_FILE_TYPE_SIGNATURE, + /* File holding public key to verify signature once. */ diff --git a/SOURCES/0336-kern-efi-Fix-memory-leak-on-failure.patch b/SOURCES/0336-kern-efi-Fix-memory-leak-on-failure.patch deleted file mode 100644 index 1aa52d6..0000000 --- a/SOURCES/0336-kern-efi-Fix-memory-leak-on-failure.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Thu, 5 Nov 2020 10:15:25 +0000 -Subject: [PATCH] kern/efi: Fix memory leak on failure - -Free the memory allocated to name before returning on failure. - -Fixes: CID 296222 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/kern/efi/efi.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c -index 5dfcf943322..4b95a400490 100644 ---- a/grub-core/kern/efi/efi.c -+++ b/grub-core/kern/efi/efi.c -@@ -400,6 +400,7 @@ grub_efi_get_filename (grub_efi_device_path_t *dp0) - { - grub_error (GRUB_ERR_OUT_OF_RANGE, - "malformed EFI Device Path node has length=%d", len); -+ grub_free (name); - return NULL; - } - diff --git a/SOURCES/0337-grub-core-loader-efi-fdt.c-Fixup-grub_file_open-call.patch b/SOURCES/0337-grub-core-loader-efi-fdt.c-Fixup-grub_file_open-call.patch new file mode 100644 index 0000000..73d1cda --- /dev/null +++ b/SOURCES/0337-grub-core-loader-efi-fdt.c-Fixup-grub_file_open-call.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Leif Lindholm +Date: Wed, 14 Nov 2018 19:29:17 +0000 +Subject: [PATCH] grub-core/loader/efi/fdt.c: Fixup grub_file_open() call + +The verifiers framework changed the API of grub_file_open(), but did not +fix up all users. Add the file type GRUB_FILE_TYPE_DEVICE_TREE_IMAGE +to the "devicetree" command handler call. + +Signed-off-by: Leif Lindholm +Reviewed-by: Daniel Kiper +--- + grub-core/loader/efi/fdt.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/loader/efi/fdt.c b/grub-core/loader/efi/fdt.c +index a9dbcfdfeaf..e3ee3ad79d6 100644 +--- a/grub-core/loader/efi/fdt.c ++++ b/grub-core/loader/efi/fdt.c +@@ -125,7 +125,7 @@ grub_cmd_devicetree (grub_command_t cmd __attribute__ ((unused)), + return GRUB_ERR_NONE; + } + +- dtb = grub_file_open (argv[0]); ++ dtb = grub_file_open (argv[0], GRUB_FILE_TYPE_DEVICE_TREE_IMAGE); + if (!dtb) + goto out; + diff --git a/SOURCES/0337-kern-efi-mm-Fix-possible-NULL-pointer-dereference.patch b/SOURCES/0337-kern-efi-mm-Fix-possible-NULL-pointer-dereference.patch deleted file mode 100644 index 5fb25a3..0000000 --- a/SOURCES/0337-kern-efi-mm-Fix-possible-NULL-pointer-dereference.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Fri, 11 Dec 2020 15:03:13 +0000 -Subject: [PATCH] kern/efi/mm: Fix possible NULL pointer dereference - -The model of grub_efi_get_memory_map() is that if memory_map is NULL, -then the purpose is to discover how much memory should be allocated to -it for the subsequent call. - -The problem here is that with grub_efi_is_finished set to 1, there is no -check at all that the function is being called with a non-NULL memory_map. - -While this MAY be true, we shouldn't assume it. - -The solution to this is to behave as expected, and if memory_map is NULL, -then don't try to use it and allow memory_map_size to be filled in, and -return 0 as is done later in the code if the buffer is too small (or NULL). - -Additionally, drop unneeded ret = 1. - -Fixes: CID 96632 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/kern/efi/mm.c | 23 ++++++++++++++++------- - 1 file changed, 16 insertions(+), 7 deletions(-) - -diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c -index 306924f73a4..2d9c9032b2a 100644 ---- a/grub-core/kern/efi/mm.c -+++ b/grub-core/kern/efi/mm.c -@@ -372,16 +372,25 @@ grub_efi_get_memory_map (grub_efi_uintn_t *memory_map_size, - if (grub_efi_is_finished) - { - int ret = 1; -- if (*memory_map_size < finish_mmap_size) -+ -+ if (memory_map != NULL) - { -- grub_memcpy (memory_map, finish_mmap_buf, *memory_map_size); -+ if (*memory_map_size < finish_mmap_size) -+ { -+ grub_memcpy (memory_map, finish_mmap_buf, *memory_map_size); -+ ret = 0; -+ } -+ else -+ grub_memcpy (memory_map, finish_mmap_buf, finish_mmap_size); -+ } -+ else -+ { -+ /* -+ * Incomplete, no buffer to copy into, same as -+ * GRUB_EFI_BUFFER_TOO_SMALL below. -+ */ - ret = 0; - } -- else -- { -- grub_memcpy (memory_map, finish_mmap_buf, finish_mmap_size); -- ret = 1; -- } - *memory_map_size = finish_mmap_size; - if (map_key) - *map_key = finish_key; diff --git a/SOURCES/0338-arm64-efi-Fix-breakage-caused-by-verifiers.patch b/SOURCES/0338-arm64-efi-Fix-breakage-caused-by-verifiers.patch new file mode 100644 index 0000000..debb2c6 --- /dev/null +++ b/SOURCES/0338-arm64-efi-Fix-breakage-caused-by-verifiers.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Leif Lindholm +Date: Wed, 14 Nov 2018 19:29:18 +0000 +Subject: [PATCH] arm64/efi: Fix breakage caused by verifiers + + - add variable "err" (used but not defined), + - add GRUB_FILE_TYPE_LINUX_KERNEL to grub_file_open() call. + +Signed-off-by: Leif Lindholm +Reviewed-by: Daniel Kiper + +Conflicts: + grub-core/loader/arm64/linux.c +--- + grub-core/loader/arm64/linux.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c +index 48ea66596ad..864724dd4fa 100644 +--- a/grub-core/loader/arm64/linux.c ++++ b/grub-core/loader/arm64/linux.c +@@ -338,6 +338,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + struct linux_armxx_kernel_header lh; + struct grub_armxx_linux_pe_header *pe; + int rc; ++ grub_err_t err; + + grub_dl_ref (my_mod); + +@@ -347,7 +348,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); + if (!file) + goto fail; + diff --git a/SOURCES/0338-gnulib-regexec-Resolve-unused-variable.patch b/SOURCES/0338-gnulib-regexec-Resolve-unused-variable.patch deleted file mode 100644 index 226abc8..0000000 --- a/SOURCES/0338-gnulib-regexec-Resolve-unused-variable.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Wed, 21 Oct 2020 14:41:27 +0000 -Subject: [PATCH] gnulib/regexec: Resolve unused variable - -This is a really minor issue where a variable is being assigned to but -not checked before it is overwritten again. - -The reason for this issue is that we are not building with DEBUG set and -this in turn means that the assert() that reads the value of the -variable match_last is being processed out. - -The solution, move the assignment to match_last in to an ifdef DEBUG too. - -Fixes: CID 292459 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/gnulib/regexec.c | 4 ++++ - conf/Makefile.extra-dist | 1 + - grub-core/gnulib-fix-unused-value.patch | 14 ++++++++++++++ - 3 files changed, 19 insertions(+) - create mode 100644 grub-core/gnulib-fix-unused-value.patch - -diff --git a/grub-core/gnulib/regexec.c b/grub-core/gnulib/regexec.c -index a7776f088f2..9264f262893 100644 ---- a/grub-core/gnulib/regexec.c -+++ b/grub-core/gnulib/regexec.c -@@ -879,7 +879,11 @@ re_search_internal (const regex_t *preg, - break; - if (BE (err != REG_NOMATCH, 0)) - goto free_return; -+#ifdef DEBUG -+ /* Only used for assertion below when DEBUG is set, otherwise -+ it will be over-written when we loop around. */ - match_last = REG_MISSING; -+#endif - } - else - break; /* We found a match. */ -diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist -index 5946ec24a65..b53fe6dfdcc 100644 ---- a/conf/Makefile.extra-dist -+++ b/conf/Makefile.extra-dist -@@ -31,6 +31,7 @@ EXTRA_DIST += grub-core/genemuinit.sh - EXTRA_DIST += grub-core/genemuinitheader.sh - - EXTRA_DIST += grub-core/gnulib-fix-null-deref.diff -+EXTRA_DIST += grub-core/gnulib-fix-unused-value.patch - EXTRA_DIST += grub-core/gnulib-fix-width.diff - EXTRA_DIST += grub-core/gnulib-no-abort.diff - EXTRA_DIST += grub-core/gnulib-no-gets.diff -diff --git a/grub-core/gnulib-fix-unused-value.patch b/grub-core/gnulib-fix-unused-value.patch -new file mode 100644 -index 00000000000..452a8732922 ---- /dev/null -+++ b/grub-core/gnulib-fix-unused-value.patch -@@ -0,0 +1,14 @@ -+--- grub-core/gnulib/regexec.c 2020-10-21 14:25:35.310195912 +0000 -++++ grub-core/gnulib/regexec.c 2020-10-21 14:32:07.961765604 +0000 -+@@ -828,7 +828,11 @@ -+ break; -+ if (BE (err != REG_NOMATCH, 0)) -+ goto free_return; -++#ifdef DEBUG -++ /* Only used for assertion below when DEBUG is set, otherwise -++ it will be over-written when we loop around. */ -+ match_last = REG_MISSING; -++#endif -+ } -+ else -+ break; /* We found a match. */ diff --git a/SOURCES/0339-arm-uboot-ia64-sparc64-Fix-up-grub_file_open-calls.patch b/SOURCES/0339-arm-uboot-ia64-sparc64-Fix-up-grub_file_open-calls.patch new file mode 100644 index 0000000..8cd7685 --- /dev/null +++ b/SOURCES/0339-arm-uboot-ia64-sparc64-Fix-up-grub_file_open-calls.patch @@ -0,0 +1,74 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Leif Lindholm +Date: Wed, 14 Nov 2018 19:29:19 +0000 +Subject: [PATCH] arm-uboot, ia64, sparc64: Fix up grub_file_open() calls + +The verifiers framework changed the grub_file_open() interface, breaking all +non-x86 linux loaders. Add file types to the grub_file_open() calls to make +them build again. + +Signed-off-by: Leif Lindholm +Reviewed-by: Daniel Kiper +--- + grub-core/loader/arm/linux.c | 6 +++--- + grub-core/loader/ia64/efi/linux.c | 2 +- + grub-core/loader/sparc64/ieee1275/linux.c | 2 +- + 3 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/grub-core/loader/arm/linux.c b/grub-core/loader/arm/linux.c +index beceda52030..1e944a2b671 100644 +--- a/grub-core/loader/arm/linux.c ++++ b/grub-core/loader/arm/linux.c +@@ -363,7 +363,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); + if (!file) + goto fail; + +@@ -408,7 +408,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_INITRD); + if (!file) + return grub_errno; + +@@ -471,7 +471,7 @@ grub_cmd_devicetree (grub_command_t cmd __attribute__ ((unused)), + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + +- dtb = grub_file_open (argv[0]); ++ dtb = grub_file_open (argv[0], GRUB_FILE_TYPE_DEVICE_TREE_IMAGE); + if (!dtb) + return grub_errno; + +diff --git a/grub-core/loader/ia64/efi/linux.c b/grub-core/loader/ia64/efi/linux.c +index e325fe0ee83..2ad0b0c0407 100644 +--- a/grub-core/loader/ia64/efi/linux.c ++++ b/grub-core/loader/ia64/efi/linux.c +@@ -502,7 +502,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); + if (! file) + goto fail; + +diff --git a/grub-core/loader/sparc64/ieee1275/linux.c b/grub-core/loader/sparc64/ieee1275/linux.c +index abe46faa012..bb47ee0cc64 100644 +--- a/grub-core/loader/sparc64/ieee1275/linux.c ++++ b/grub-core/loader/sparc64/ieee1275/linux.c +@@ -306,7 +306,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto out; + } + +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); + if (!file) + goto out; + diff --git a/SOURCES/0339-gnulib-regcomp-Fix-uninitialized-token-structure.patch b/SOURCES/0339-gnulib-regcomp-Fix-uninitialized-token-structure.patch deleted file mode 100644 index b18be72..0000000 --- a/SOURCES/0339-gnulib-regcomp-Fix-uninitialized-token-structure.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Thu, 22 Oct 2020 13:54:06 +0000 -Subject: [PATCH] gnulib/regcomp: Fix uninitialized token structure - -The code is assuming that the value of br_token.constraint was -initialized to zero when it wasn't. - -While some compilers will ensure that, not all do, so it is better to -fix this explicitly than leave it to chance. - -Fixes: CID 73749 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/gnulib/regcomp.c | 2 +- - conf/Makefile.extra-dist | 1 + - grub-core/gnulib-fix-uninit-structure.patch | 11 +++++++++++ - 3 files changed, 13 insertions(+), 1 deletion(-) - create mode 100644 grub-core/gnulib-fix-uninit-structure.patch - -diff --git a/grub-core/gnulib/regcomp.c b/grub-core/gnulib/regcomp.c -index 596e0cf3ef7..de9f622088f 100644 ---- a/grub-core/gnulib/regcomp.c -+++ b/grub-core/gnulib/regcomp.c -@@ -3641,7 +3641,7 @@ build_charclass_op (re_dfa_t *dfa, RE_TRANSLATE_TYPE trans, - Idx alloc = 0; - #endif /* not RE_ENABLE_I18N */ - reg_errcode_t ret; -- re_token_t br_token; -+ re_token_t br_token = {0}; - bin_tree_t *tree; - - sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); -diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist -index b53fe6dfdcc..883baba56d5 100644 ---- a/conf/Makefile.extra-dist -+++ b/conf/Makefile.extra-dist -@@ -31,6 +31,7 @@ EXTRA_DIST += grub-core/genemuinit.sh - EXTRA_DIST += grub-core/genemuinitheader.sh - - EXTRA_DIST += grub-core/gnulib-fix-null-deref.diff -+EXTRA_DIST += grub-core/gnulib-fix-uninit-structure.patch - EXTRA_DIST += grub-core/gnulib-fix-unused-value.patch - EXTRA_DIST += grub-core/gnulib-fix-width.diff - EXTRA_DIST += grub-core/gnulib-no-abort.diff -diff --git a/grub-core/gnulib-fix-uninit-structure.patch b/grub-core/gnulib-fix-uninit-structure.patch -new file mode 100644 -index 00000000000..7b4d9f67af4 ---- /dev/null -+++ b/grub-core/gnulib-fix-uninit-structure.patch -@@ -0,0 +1,11 @@ -+--- a/lib/regcomp.c 2020-10-22 13:49:06.770168928 +0000 -++++ b/lib/regcomp.c 2020-10-22 13:50:37.026528298 +0000 -+@@ -3662,7 +3662,7 @@ -+ Idx alloc = 0; -+ #endif /* not RE_ENABLE_I18N */ -+ reg_errcode_t ret; -+- re_token_t br_token; -++ re_token_t br_token = {0}; -+ bin_tree_t *tree; -+ -+ sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); diff --git a/SOURCES/0340-gnulib-argp-help-Fix-dereference-of-a-possibly-NULL-.patch b/SOURCES/0340-gnulib-argp-help-Fix-dereference-of-a-possibly-NULL-.patch deleted file mode 100644 index 97f127c..0000000 --- a/SOURCES/0340-gnulib-argp-help-Fix-dereference-of-a-possibly-NULL-.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Wed, 28 Oct 2020 14:43:01 +0000 -Subject: [PATCH] gnulib/argp-help: Fix dereference of a possibly NULL state - -All other instances of call to __argp_failure() where there is -a dgettext() call is first checking whether state is NULL before -attempting to dereference it to get the root_argp->argp_domain. - -Fixes: CID 292436 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/gnulib/argp-help.c | 3 ++- - conf/Makefile.extra-dist | 1 + - grub-core/gnulib-fix-null-state-deref.patch | 12 ++++++++++++ - 3 files changed, 15 insertions(+), 1 deletion(-) - create mode 100644 grub-core/gnulib-fix-null-state-deref.patch - -diff --git a/grub-core/gnulib/argp-help.c b/grub-core/gnulib/argp-help.c -index b9be63f40d2..8af8be07341 100644 ---- a/grub-core/gnulib/argp-help.c -+++ b/grub-core/gnulib/argp-help.c -@@ -145,7 +145,8 @@ validate_uparams (const struct argp_state *state, struct uparams *upptr) - if (*(int *)((char *)upptr + up->uparams_offs) >= upptr->rmargin) - { - __argp_failure (state, 0, 0, -- dgettext (state->root_argp->argp_domain, -+ dgettext (state == NULL ? NULL -+ : state->root_argp->argp_domain, - "\ - ARGP_HELP_FMT: %s value is less than or equal to %s"), - "rmargin", up->name); -diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist -index 883baba56d5..06606de8d19 100644 ---- a/conf/Makefile.extra-dist -+++ b/conf/Makefile.extra-dist -@@ -31,6 +31,7 @@ EXTRA_DIST += grub-core/genemuinit.sh - EXTRA_DIST += grub-core/genemuinitheader.sh - - EXTRA_DIST += grub-core/gnulib-fix-null-deref.diff -+EXTRA_DIST += grub-core/gnulib-fix-null-state-deref.patch - EXTRA_DIST += grub-core/gnulib-fix-uninit-structure.patch - EXTRA_DIST += grub-core/gnulib-fix-unused-value.patch - EXTRA_DIST += grub-core/gnulib-fix-width.diff -diff --git a/grub-core/gnulib-fix-null-state-deref.patch b/grub-core/gnulib-fix-null-state-deref.patch -new file mode 100644 -index 00000000000..813ec09c8a1 ---- /dev/null -+++ b/grub-core/gnulib-fix-null-state-deref.patch -@@ -0,0 +1,12 @@ -+--- a/lib/argp-help.c 2020-10-28 14:32:19.189215988 +0000 -++++ b/lib/argp-help.c 2020-10-28 14:38:21.204673940 +0000 -+@@ -145,7 +145,8 @@ -+ if (*(int *)((char *)upptr + up->uparams_offs) >= upptr->rmargin) -+ { -+ __argp_failure (state, 0, 0, -+- dgettext (state->root_argp->argp_domain, -++ dgettext (state == NULL ? NULL -++ : state->root_argp->argp_domain, -+ "\ -+ ARGP_HELP_FMT: %s value is less than or equal to %s"), -+ "rmargin", up->name); diff --git a/SOURCES/0340-verifiers-fix-double-close-on-pgp-s-sig-file-descrip.patch b/SOURCES/0340-verifiers-fix-double-close-on-pgp-s-sig-file-descrip.patch new file mode 100644 index 0000000..4704137 --- /dev/null +++ b/SOURCES/0340-verifiers-fix-double-close-on-pgp-s-sig-file-descrip.patch @@ -0,0 +1,146 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Tue, 20 Nov 2018 19:15:37 +0800 +Subject: [PATCH] verifiers: fix double close on pgp's sig file descriptor + +An error emerged as when I was testing the verifiers branch, so instead +of putting it in pgp prefix, the verifiers is used to reflect what the +patch is based on. + +While running verify_detached, grub aborts with error. + +verify_detached /@/.snapshots/1/snapshot/boot/grub/grub.cfg +/@/.snapshots/1/snapshot/boot/grub/grub.cfg.sig + +alloc magic is broken at 0x7beea660: 0 +Aborted. Press any key to exit. + +The error is caused by sig file descriptor been closed twice, first time +in grub_verify_signature() to which it is passed as parameter. Second in +grub_cmd_verify_signature() or in whichever opens the sig file +descriptor. The second close is not consider as bug to me either, as in +common rule of what opens a file has to close it to avoid file +descriptor leakage. + +After all the design of grub_verify_signature() makes it difficult to keep +a good trace on opened file descriptor from it's caller. Let's refine +the application interface to accept file path rather than descriptor, in +this way the caller doesn't have to care about closing the descriptor by +delegating it to grub_verify_signature() with full tracing to opened +file descriptor by itself. + +Also making it clear that sig descriptor is not referenced in error +returning path of grub_verify_signature_init(), so it can be closed +directly by it's caller. This also makes delegating it to +grub_pubkey_close() infeasible to help in relieving file descriptor +leakage as it has to depend on uncertainty of ctxt fields in error +returning path. + +Signed-off-by: Michael Chang +Reviewed-by: Daniel Kiper +--- + grub-core/commands/pgp.c | 35 +++++++++++++++++------------------ + include/grub/pubkey.h | 2 +- + 2 files changed, 18 insertions(+), 19 deletions(-) + +diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c +index 5c913c2e2fe..d39846d8cfe 100644 +--- a/grub-core/commands/pgp.c ++++ b/grub-core/commands/pgp.c +@@ -495,13 +495,12 @@ grub_verify_signature_init (struct grub_pubkey_context *ctxt, grub_file_t sig) + + grub_dprintf ("crypt", "alive\n"); + +- ctxt->sig = sig; +- + ctxt->hash_context = grub_zalloc (ctxt->hash->contextsize); + if (!ctxt->hash_context) + return grub_errno; + + ctxt->hash->init (ctxt->hash_context); ++ ctxt->sig = sig; + + return GRUB_ERR_NONE; + } +@@ -684,16 +683,26 @@ grub_pubkey_close (void *ctxt) + } + + grub_err_t +-grub_verify_signature (grub_file_t f, grub_file_t sig, ++grub_verify_signature (grub_file_t f, const char *fsig, + struct grub_public_key *pkey) + { ++ grub_file_t sig; + grub_err_t err; + struct grub_pubkey_context ctxt; + grub_uint8_t *readbuf = NULL; + ++ sig = grub_file_open (fsig, ++ GRUB_FILE_TYPE_SIGNATURE ++ | GRUB_FILE_TYPE_NO_DECOMPRESS); ++ if (!sig) ++ return grub_errno; ++ + err = grub_verify_signature_init (&ctxt, sig); + if (err) +- return err; ++ { ++ grub_file_close (sig); ++ return err; ++ } + + readbuf = grub_zalloc (READBUF_SIZE); + if (!readbuf) +@@ -807,7 +816,7 @@ static grub_err_t + grub_cmd_verify_signature (grub_extcmd_context_t ctxt, + int argc, char **args) + { +- grub_file_t f = NULL, sig = NULL; ++ grub_file_t f = NULL; + grub_err_t err = GRUB_ERR_NONE; + struct grub_public_key *pk = NULL; + +@@ -845,19 +854,8 @@ grub_cmd_verify_signature (grub_extcmd_context_t ctxt, + goto fail; + } + +- sig = grub_file_open (args[1], +- GRUB_FILE_TYPE_SIGNATURE +- | GRUB_FILE_TYPE_NO_DECOMPRESS); +- if (!sig) +- { +- err = grub_errno; +- goto fail; +- } +- +- err = grub_verify_signature (f, sig, pk); ++ err = grub_verify_signature (f, args[1], pk); + fail: +- if (sig) +- grub_file_close (sig); + if (f) + grub_file_close (f); + if (pk) +@@ -902,7 +900,8 @@ grub_pubkey_init (grub_file_t io, enum grub_file_type type __attribute__ ((unuse + err = grub_verify_signature_init (ctxt, sig); + if (err) + { +- grub_pubkey_close (ctxt); ++ grub_free (ctxt); ++ grub_file_close (sig); + return err; + } + *context = ctxt; +diff --git a/include/grub/pubkey.h b/include/grub/pubkey.h +index 4a9d04b4305..fb8be9cbb73 100644 +--- a/include/grub/pubkey.h ++++ b/include/grub/pubkey.h +@@ -25,7 +25,7 @@ struct grub_public_key * + grub_load_public_key (grub_file_t f); + + grub_err_t +-grub_verify_signature (grub_file_t f, grub_file_t sig, ++grub_verify_signature (grub_file_t f, const char *fsig, + struct grub_public_key *pk); + + diff --git a/SOURCES/0341-gnulib-regexec-Fix-possible-null-dereference.patch b/SOURCES/0341-gnulib-regexec-Fix-possible-null-dereference.patch deleted file mode 100644 index 78ae2b9..0000000 --- a/SOURCES/0341-gnulib-regexec-Fix-possible-null-dereference.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Thu, 5 Nov 2020 10:57:14 +0000 -Subject: [PATCH] gnulib/regexec: Fix possible null-dereference - -It appears to be possible that the mctx->state_log field may be NULL, -and the name of this function, clean_state_log_if_needed(), suggests -that it should be checking that it is valid to be cleaned before -assuming that it does. - -Fixes: CID 86720 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/gnulib/regexec.c | 3 +++ - conf/Makefile.extra-dist | 1 + - grub-core/gnulib-fix-regexec-null-deref.patch | 12 ++++++++++++ - 3 files changed, 16 insertions(+) - create mode 100644 grub-core/gnulib-fix-regexec-null-deref.patch - -diff --git a/grub-core/gnulib/regexec.c b/grub-core/gnulib/regexec.c -index 9264f262893..fdacff12ce3 100644 ---- a/grub-core/gnulib/regexec.c -+++ b/grub-core/gnulib/regexec.c -@@ -1754,6 +1754,9 @@ clean_state_log_if_needed (re_match_context_t *mctx, Idx next_state_log_idx) - { - Idx top = mctx->state_log_top; - -+ if (mctx->state_log == NULL) -+ return REG_NOERROR; -+ - if ((next_state_log_idx >= mctx->input.bufs_len - && mctx->input.bufs_len < mctx->input.len) - || (next_state_log_idx >= mctx->input.valid_len -diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist -index 06606de8d19..edbe7846eb1 100644 ---- a/conf/Makefile.extra-dist -+++ b/conf/Makefile.extra-dist -@@ -32,6 +32,7 @@ EXTRA_DIST += grub-core/genemuinitheader.sh - - EXTRA_DIST += grub-core/gnulib-fix-null-deref.diff - EXTRA_DIST += grub-core/gnulib-fix-null-state-deref.patch -+EXTRA_DIST += grub-core/gnulib-fix-regexec-null-deref.patch - EXTRA_DIST += grub-core/gnulib-fix-uninit-structure.patch - EXTRA_DIST += grub-core/gnulib-fix-unused-value.patch - EXTRA_DIST += grub-core/gnulib-fix-width.diff -diff --git a/grub-core/gnulib-fix-regexec-null-deref.patch b/grub-core/gnulib-fix-regexec-null-deref.patch -new file mode 100644 -index 00000000000..db6dac9c9e3 ---- /dev/null -+++ b/grub-core/gnulib-fix-regexec-null-deref.patch -@@ -0,0 +1,12 @@ -+--- a/lib/regexec.c 2020-10-21 14:25:35.310195912 +0000 -++++ b/lib/regexec.c 2020-11-05 10:55:09.621542984 +0000 -+@@ -1692,6 +1692,9 @@ -+ { -+ Idx top = mctx->state_log_top; -+ -++ if (mctx->state_log == NULL) -++ return REG_NOERROR; -++ -+ if ((next_state_log_idx >= mctx->input.bufs_len -+ && mctx->input.bufs_len < mctx->input.len) -+ || (next_state_log_idx >= mctx->input.valid_len diff --git a/SOURCES/0341-verifiers-Xen-fallout-cleanup.patch b/SOURCES/0341-verifiers-Xen-fallout-cleanup.patch new file mode 100644 index 0000000..7270f3e --- /dev/null +++ b/SOURCES/0341-verifiers-Xen-fallout-cleanup.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Kiper +Date: Thu, 6 Dec 2018 13:38:15 +0100 +Subject: [PATCH] verifiers: Xen fallout cleanup + +Xen fallout cleanup after commit ca0a4f689 (verifiers: File type for +fine-grained signature-verification controlling). + +Signed-off-by: Daniel Kiper +Reviewed-by: Ross Philipson +--- + grub-core/loader/i386/xen.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/grub-core/loader/i386/xen.c b/grub-core/loader/i386/xen.c +index 07a4837c532..071b530d744 100644 +--- a/grub-core/loader/i386/xen.c ++++ b/grub-core/loader/i386/xen.c +@@ -647,10 +647,10 @@ grub_cmd_xen (grub_command_t cmd __attribute__ ((unused)), + + grub_xen_reset (); + +- grub_create_loader_cmdline (argc - 1, argv + 1, +- (char *) xen_state.next_start.cmd_line, +- sizeof (xen_state.next_start.cmd_line) - 1); +- err = grub_verify_string (xen_state.next_start.cmd_line, GRUB_VERIFY_MODULE_CMDLINE); ++ err = grub_create_loader_cmdline (argc - 1, argv + 1, ++ (char *) xen_state.next_start.cmd_line, ++ sizeof (xen_state.next_start.cmd_line) - 1, ++ GRUB_VERIFY_KERNEL_CMDLINE); + if (err) + return err; + +@@ -918,9 +918,9 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)), + if (err) + goto fail; + +- grub_create_loader_cmdline (argc - 1, argv + 1, +- get_virtual_current_address (ch), cmdline_len); +- err = grub_verify_string (get_virtual_current_address (ch), GRUB_VERIFY_MODULE_CMDLINE); ++ err = grub_create_loader_cmdline (argc - 1, argv + 1, ++ get_virtual_current_address (ch), cmdline_len, ++ GRUB_VERIFY_MODULE_CMDLINE); + if (err) + goto fail; + diff --git a/SOURCES/0342-gnulib-regcomp-Fix-uninitialized-re_token.patch b/SOURCES/0342-gnulib-regcomp-Fix-uninitialized-re_token.patch deleted file mode 100644 index 342a020..0000000 --- a/SOURCES/0342-gnulib-regcomp-Fix-uninitialized-re_token.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Tue, 24 Nov 2020 18:04:22 +0000 -Subject: [PATCH] gnulib/regcomp: Fix uninitialized re_token - -This issue has been fixed in the latest version of gnulib, so to -maintain consistency, I've backported that change rather than doing -something different. - -Fixes: CID 73828 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/gnulib/regcomp.c | 3 +-- - conf/Makefile.extra-dist | 1 + - grub-core/gnulib-fix-regcomp-uninit-token.patch | 12 ++++++++++++ - 3 files changed, 14 insertions(+), 2 deletions(-) - create mode 100644 grub-core/gnulib-fix-regcomp-uninit-token.patch - -diff --git a/grub-core/gnulib/regcomp.c b/grub-core/gnulib/regcomp.c -index de9f622088f..6d0830ac691 100644 ---- a/grub-core/gnulib/regcomp.c -+++ b/grub-core/gnulib/regcomp.c -@@ -3790,8 +3790,7 @@ static bin_tree_t * - create_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, - re_token_type_t type) - { -- re_token_t t; -- t.type = type; -+ re_token_t t = { .type = type }; - return create_token_tree (dfa, left, right, &t); - } - -diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist -index edbe7846eb1..ee276a87764 100644 ---- a/conf/Makefile.extra-dist -+++ b/conf/Makefile.extra-dist -@@ -32,6 +32,7 @@ EXTRA_DIST += grub-core/genemuinitheader.sh - - EXTRA_DIST += grub-core/gnulib-fix-null-deref.diff - EXTRA_DIST += grub-core/gnulib-fix-null-state-deref.patch -+EXTRA_DIST += grub-core/gnulib-fix-regcomp-uninit-token.patch - EXTRA_DIST += grub-core/gnulib-fix-regexec-null-deref.patch - EXTRA_DIST += grub-core/gnulib-fix-uninit-structure.patch - EXTRA_DIST += grub-core/gnulib-fix-unused-value.patch -diff --git a/grub-core/gnulib-fix-regcomp-uninit-token.patch b/grub-core/gnulib-fix-regcomp-uninit-token.patch -new file mode 100644 -index 00000000000..d615745221b ---- /dev/null -+++ b/grub-core/gnulib-fix-regcomp-uninit-token.patch -@@ -0,0 +1,12 @@ -+--- grub-core/gnulib/regcomp.c -++++ grub-core/gnulib/regcomp.c -+@@ -3808,8 +3808,7 @@ static bin_tree_t * -+ create_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, -+ re_token_type_t type) -+ { -+- re_token_t t; -+- t.type = type; -++ re_token_t t = { .type = type }; -+ return create_token_tree (dfa, left, right, &t); -+ } -+ diff --git a/SOURCES/0342-verifiers-ARM-Xen-fallout-cleanup.patch b/SOURCES/0342-verifiers-ARM-Xen-fallout-cleanup.patch new file mode 100644 index 0000000..cc1bfea --- /dev/null +++ b/SOURCES/0342-verifiers-ARM-Xen-fallout-cleanup.patch @@ -0,0 +1,63 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Kiper +Date: Thu, 6 Dec 2018 13:43:05 +0100 +Subject: [PATCH] verifiers: ARM Xen fallout cleanup + +ARM Xen fallout cleanup after commit ca0a4f689 (verifiers: File type for +fine-grained signature-verification controlling). + +Signed-off-by: Daniel Kiper +Reviewed-by: Ross Philipson +[javierm: remove grub_file_filter_disable_compression() call leftovers] +Signed-off-by: Javier Martinez Canillas + +Conflicts: + grub-core/loader/arm64/xen_boot.c +--- + grub-core/loader/arm64/xen_boot.c | 9 +++++---- + include/grub/file.h | 5 +++++ + 2 files changed, 10 insertions(+), 4 deletions(-) + +diff --git a/grub-core/loader/arm64/xen_boot.c b/grub-core/loader/arm64/xen_boot.c +index f35b16caa92..318c833de57 100644 +--- a/grub-core/loader/arm64/xen_boot.c ++++ b/grub-core/loader/arm64/xen_boot.c +@@ -427,9 +427,10 @@ grub_cmd_xen_module (grub_command_t cmd __attribute__((unused)), + + grub_dprintf ("xen_loader", "Init module and node info\n"); + +- if (nounzip) +- grub_file_filter_disable_compression (); +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_XEN_MODULE ++ | (nounzip ? GRUB_FILE_TYPE_NO_DECOMPRESS ++ : GRUB_FILE_TYPE_NONE)); ++ + if (!file) + goto fail; + +@@ -461,7 +462,7 @@ grub_cmd_xen_hypervisor (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_XEN_HYPERVISOR); + if (!file) + goto fail; + +diff --git a/include/grub/file.h b/include/grub/file.h +index 9aae463557a..cbbd294655b 100644 +--- a/include/grub/file.h ++++ b/include/grub/file.h +@@ -42,6 +42,11 @@ enum grub_file_type + /* Multiboot module. */ + GRUB_FILE_TYPE_MULTIBOOT_MODULE, + ++ /* Xen hypervisor - used on ARM only. */ ++ GRUB_FILE_TYPE_XEN_HYPERVISOR, ++ /* Xen module - used on ARM only. */ ++ GRUB_FILE_TYPE_XEN_MODULE, ++ + GRUB_FILE_TYPE_BSD_KERNEL, + GRUB_FILE_TYPE_FREEBSD_ENV, + GRUB_FILE_TYPE_FREEBSD_MODULE, diff --git a/SOURCES/0343-io-lzopio-Resolve-unnecessary-self-assignment-errors.patch b/SOURCES/0343-io-lzopio-Resolve-unnecessary-self-assignment-errors.patch deleted file mode 100644 index 71d1979..0000000 --- a/SOURCES/0343-io-lzopio-Resolve-unnecessary-self-assignment-errors.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Wed, 21 Oct 2020 14:44:10 +0000 -Subject: [PATCH] io/lzopio: Resolve unnecessary self-assignment errors - -These 2 assignments are unnecessary since they are just assigning -to themselves. - -Fixes: CID 73643 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/io/lzopio.c | 4 ---- - 1 file changed, 4 deletions(-) - -diff --git a/grub-core/io/lzopio.c b/grub-core/io/lzopio.c -index 7559c6c9cab..dcb58746da1 100644 ---- a/grub-core/io/lzopio.c -+++ b/grub-core/io/lzopio.c -@@ -125,8 +125,6 @@ read_block_header (struct grub_lzopio *lzopio) - sizeof (lzopio->block.ucheck)) != - sizeof (lzopio->block.ucheck)) - return -1; -- -- lzopio->block.ucheck = lzopio->block.ucheck; - } - - /* Read checksum of compressed data. */ -@@ -143,8 +141,6 @@ read_block_header (struct grub_lzopio *lzopio) - sizeof (lzopio->block.ccheck)) != - sizeof (lzopio->block.ccheck)) - return -1; -- -- lzopio->block.ccheck = lzopio->block.ccheck; - } - } - diff --git a/SOURCES/0343-verifiers-IA-64-fallout-cleanup.patch b/SOURCES/0343-verifiers-IA-64-fallout-cleanup.patch new file mode 100644 index 0000000..005a324 --- /dev/null +++ b/SOURCES/0343-verifiers-IA-64-fallout-cleanup.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Kiper +Date: Thu, 14 Mar 2019 16:18:31 +0100 +Subject: [PATCH] verifiers: IA-64 fallout cleanup + +IA-64 fallout cleanup after commit 4d4a8c96e (verifiers: Add possibility +to verify kernel and modules command lines). + +Signed-off-by: Daniel Kiper +Reviewed-by: Ross Philipson +--- + grub-core/loader/ia64/efi/linux.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/grub-core/loader/ia64/efi/linux.c b/grub-core/loader/ia64/efi/linux.c +index 2ad0b0c0407..cfeb2c145bb 100644 +--- a/grub-core/loader/ia64/efi/linux.c ++++ b/grub-core/loader/ia64/efi/linux.c +@@ -547,8 +547,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + *p = '\0'; + +- err = grub_verify_string (cmdline, GRUB_VERIFY_KERNEL_CMDLINE); +- if (err) ++ if (grub_verify_string (cmdline, GRUB_VERIFY_KERNEL_CMDLINE)) + goto fail; + + boot_param->command_line = (grub_uint64_t) cmdline; diff --git a/SOURCES/0344-kern-partition-Check-for-NULL-before-dereferencing-i.patch b/SOURCES/0344-kern-partition-Check-for-NULL-before-dereferencing-i.patch deleted file mode 100644 index 35c4c01..0000000 --- a/SOURCES/0344-kern-partition-Check-for-NULL-before-dereferencing-i.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Fri, 23 Oct 2020 09:49:59 +0000 -Subject: [PATCH] kern/partition: Check for NULL before dereferencing input - string - -There is the possibility that the value of str comes from an external -source and continuing to use it before ever checking its validity is -wrong. So, needs fixing. - -Additionally, drop unneeded part initialization. - -Fixes: CID 292444 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/kern/partition.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/grub-core/kern/partition.c b/grub-core/kern/partition.c -index 2c401b866c4..3068c4dcac0 100644 ---- a/grub-core/kern/partition.c -+++ b/grub-core/kern/partition.c -@@ -109,11 +109,14 @@ grub_partition_map_probe (const grub_partition_map_t partmap, - grub_partition_t - grub_partition_probe (struct grub_disk *disk, const char *str) - { -- grub_partition_t part = 0; -+ grub_partition_t part; - grub_partition_t curpart = 0; - grub_partition_t tail; - const char *ptr; - -+ if (str == NULL) -+ return 0; -+ - part = tail = disk->partition; - - for (ptr = str; *ptr;) diff --git a/SOURCES/0344-verifiers-PowerPC-fallout-cleanup.patch b/SOURCES/0344-verifiers-PowerPC-fallout-cleanup.patch new file mode 100644 index 0000000..451e5f6 --- /dev/null +++ b/SOURCES/0344-verifiers-PowerPC-fallout-cleanup.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Kiper +Date: Thu, 14 Mar 2019 19:45:17 +0100 +Subject: [PATCH] verifiers: PowerPC fallout cleanup + +PowerPC fallout cleanup after commit 4d4a8c96e (verifiers: Add possibility +to verify kernel and modules command lines) and ca0a4f689 (verifiers: File +type for fine-grained signature-verification controlling). + +Signed-off-by: Daniel Kiper +Reviewed-by: Ross Philipson +--- + grub-core/loader/powerpc/ieee1275/linux.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/loader/powerpc/ieee1275/linux.c b/grub-core/loader/powerpc/ieee1275/linux.c +index c114e7df4fb..818b2a86d1a 100644 +--- a/grub-core/loader/powerpc/ieee1275/linux.c ++++ b/grub-core/loader/powerpc/ieee1275/linux.c +@@ -270,7 +270,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto out; + } + +- elf = grub_elf_open (argv[0]); ++ elf = grub_elf_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); + if (! elf) + goto out; + +@@ -303,7 +303,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + /* Create kernel command line. */ + grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE)); + if (grub_create_loader_cmdline (argc, argv, linux_args + sizeof (LINUX_IMAGE) - 1, +- size)) ++ size, GRUB_VERIFY_KERNEL_CMDLINE)) + goto out; + + out: diff --git a/SOURCES/0345-disk-ldm-Make-sure-comp-data-is-freed-before-exiting.patch b/SOURCES/0345-disk-ldm-Make-sure-comp-data-is-freed-before-exiting.patch deleted file mode 100644 index 7d4ea0e..0000000 --- a/SOURCES/0345-disk-ldm-Make-sure-comp-data-is-freed-before-exiting.patch +++ /dev/null @@ -1,125 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Marco A Benatto -Date: Mon, 7 Dec 2020 11:53:03 -0300 -Subject: [PATCH] disk/ldm: Make sure comp data is freed before exiting from - make_vg() - -Several error handling paths in make_vg() do not free comp data before -jumping to fail2 label and returning from the function. This will leak -memory. So, let's fix all issues of that kind. - -Fixes: CID 73804 - -Signed-off-by: Marco A Benatto -Reviewed-by: Daniel Kiper ---- - grub-core/disk/ldm.c | 51 ++++++++++++++++++++++++++++++++++++++++++++------- - 1 file changed, 44 insertions(+), 7 deletions(-) - -diff --git a/grub-core/disk/ldm.c b/grub-core/disk/ldm.c -index 58f8a53e1ab..428415fac24 100644 ---- a/grub-core/disk/ldm.c -+++ b/grub-core/disk/ldm.c -@@ -554,7 +554,11 @@ make_vg (grub_disk_t disk, - comp->segments = grub_calloc (comp->segment_alloc, - sizeof (*comp->segments)); - if (!comp->segments) -- goto fail2; -+ { -+ grub_free (comp->internal_id); -+ grub_free (comp); -+ goto fail2; -+ } - } - else - { -@@ -562,7 +566,11 @@ make_vg (grub_disk_t disk, - comp->segment_count = 1; - comp->segments = grub_malloc (sizeof (*comp->segments)); - if (!comp->segments) -- goto fail2; -+ { -+ grub_free (comp->internal_id); -+ grub_free (comp); -+ goto fail2; -+ } - comp->segments->start_extent = 0; - comp->segments->extent_count = lv->size; - comp->segments->layout = 0; -@@ -574,15 +582,26 @@ make_vg (grub_disk_t disk, - comp->segments->layout = GRUB_RAID_LAYOUT_SYMMETRIC_MASK; - } - else -- goto fail2; -+ { -+ grub_free (comp->segments); -+ grub_free (comp->internal_id); -+ grub_free (comp); -+ goto fail2; -+ } - ptr += *ptr + 1; - ptr++; - if (!(vblk[i].flags & 0x10)) -- goto fail2; -+ { -+ grub_free (comp->segments); -+ grub_free (comp->internal_id); -+ grub_free (comp); -+ goto fail2; -+ } - if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic) - || ptr + *ptr + 1 >= vblk[i].dynamic - + sizeof (vblk[i].dynamic)) - { -+ grub_free (comp->segments); - grub_free (comp->internal_id); - grub_free (comp); - goto fail2; -@@ -592,6 +611,7 @@ make_vg (grub_disk_t disk, - if (ptr + *ptr + 1 >= vblk[i].dynamic - + sizeof (vblk[i].dynamic)) - { -+ grub_free (comp->segments); - grub_free (comp->internal_id); - grub_free (comp); - goto fail2; -@@ -601,7 +621,12 @@ make_vg (grub_disk_t disk, - comp->segments->nodes = grub_calloc (comp->segments->node_alloc, - sizeof (*comp->segments->nodes)); - if (!lv->segments->nodes) -- goto fail2; -+ { -+ grub_free (comp->segments); -+ grub_free (comp->internal_id); -+ grub_free (comp); -+ goto fail2; -+ } - } - - if (lv->segments->node_alloc == lv->segments->node_count) -@@ -611,11 +636,23 @@ make_vg (grub_disk_t disk, - - if (grub_mul (lv->segments->node_alloc, 2, &lv->segments->node_alloc) || - grub_mul (lv->segments->node_alloc, sizeof (*lv->segments->nodes), &sz)) -- goto fail2; -+ { -+ grub_free (comp->segments->nodes); -+ grub_free (comp->segments); -+ grub_free (comp->internal_id); -+ grub_free (comp); -+ goto fail2; -+ } - - t = grub_realloc (lv->segments->nodes, sz); - if (!t) -- goto fail2; -+ { -+ grub_free (comp->segments->nodes); -+ grub_free (comp->segments); -+ grub_free (comp->internal_id); -+ grub_free (comp); -+ goto fail2; -+ } - lv->segments->nodes = t; - } - lv->segments->nodes[lv->segments->node_count].pv = 0; diff --git a/SOURCES/0345-verifiers-MIPS-fallout-cleanup.patch b/SOURCES/0345-verifiers-MIPS-fallout-cleanup.patch new file mode 100644 index 0000000..9fe0c40 --- /dev/null +++ b/SOURCES/0345-verifiers-MIPS-fallout-cleanup.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Kiper +Date: Mon, 18 Mar 2019 13:09:22 +0100 +Subject: [PATCH] verifiers: MIPS fallout cleanup + +MIPS fallout cleanup after commit 4d4a8c96e (verifiers: Add possibility +to verify kernel and modules command lines). + +Signed-off-by: Daniel Kiper +Reviewed-by: Ross Philipson +--- + grub-core/loader/mips/linux.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/loader/mips/linux.c b/grub-core/loader/mips/linux.c +index 20135ce253d..e4ed95921df 100644 +--- a/grub-core/loader/mips/linux.c ++++ b/grub-core/loader/mips/linux.c +@@ -314,7 +314,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + grub_memcpy (params, LINUX_IMAGE, sizeof (LINUX_IMAGE)); + grub_create_loader_cmdline (argc, argv, params + sizeof (LINUX_IMAGE) - 1, +- size); ++ size, GRUB_VERIFY_KERNEL_CMDLINE); + #else + linux_argv = extra; + argv_off = (grub_uint8_t *) linux_argv - (grub_uint8_t *) playground; diff --git a/SOURCES/0346-disk-ldm-If-failed-then-free-vg-variable-too.patch b/SOURCES/0346-disk-ldm-If-failed-then-free-vg-variable-too.patch deleted file mode 100644 index 6b8903a..0000000 --- a/SOURCES/0346-disk-ldm-If-failed-then-free-vg-variable-too.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Paulo Flabiano Smorigo -Date: Mon, 7 Dec 2020 10:07:47 -0300 -Subject: [PATCH] disk/ldm: If failed then free vg variable too - -Fixes: CID 73809 - -Signed-off-by: Paulo Flabiano Smorigo -Reviewed-by: Daniel Kiper ---- - grub-core/disk/ldm.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/grub-core/disk/ldm.c b/grub-core/disk/ldm.c -index 428415fac24..54713f45a12 100644 ---- a/grub-core/disk/ldm.c -+++ b/grub-core/disk/ldm.c -@@ -199,6 +199,7 @@ make_vg (grub_disk_t disk, - { - grub_free (vg->uuid); - grub_free (vg->name); -+ grub_free (vg); - return NULL; - } - grub_memcpy (vg->uuid, label->group_guid, LDM_GUID_STRLEN); diff --git a/SOURCES/0346-verifiers-Fix-calling-uninitialized-function-pointer.patch b/SOURCES/0346-verifiers-Fix-calling-uninitialized-function-pointer.patch new file mode 100644 index 0000000..19d383a --- /dev/null +++ b/SOURCES/0346-verifiers-Fix-calling-uninitialized-function-pointer.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Tue, 18 Feb 2020 18:08:18 +0800 +Subject: [PATCH] verifiers: Fix calling uninitialized function pointer + +The necessary check for NULL before use of function ver->close is not +taking place in the failure path. This patch simply adds the missing +check and fixes the problem that GRUB hangs indefinitely after booting +rogue image without valid signature if secure boot is turned on. + +Now it displays like this for booting rogue UEFI image: + + error: bad shim signature + error: you need to load the kernel first + + Press any key to continue... + +and then you can go back to boot menu by pressing any key or after a few +seconds expired. + +Signed-off-by: Michael Chang +Reviewed-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/commands/verifiers.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/grub-core/commands/verifiers.c b/grub-core/commands/verifiers.c +index c638d5f43e0..599d79b757e 100644 +--- a/grub-core/commands/verifiers.c ++++ b/grub-core/commands/verifiers.c +@@ -196,7 +196,8 @@ grub_verifiers_open (grub_file_t io, enum grub_file_type type) + return ret; + + fail: +- ver->close (context); ++ if (ver->close) ++ ver->close (context); + fail_noclose: + verified_free (verified); + grub_free (ret); diff --git a/SOURCES/0347-disk-ldm-Fix-memory-leak-on-uninserted-lv-references.patch b/SOURCES/0347-disk-ldm-Fix-memory-leak-on-uninserted-lv-references.patch deleted file mode 100644 index 3b0add6..0000000 --- a/SOURCES/0347-disk-ldm-Fix-memory-leak-on-uninserted-lv-references.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Tue, 8 Dec 2020 10:00:51 +0000 -Subject: [PATCH] disk/ldm: Fix memory leak on uninserted lv references - -The problem here is that the memory allocated to the variable lv is not -yet inserted into the list that is being processed at the label fail2. - -As we can already see at line 342, which correctly frees lv before going -to fail2, we should also be doing that at these earlier jumps to fail2. - -Fixes: CID 73824 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/disk/ldm.c | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - -diff --git a/grub-core/disk/ldm.c b/grub-core/disk/ldm.c -index 54713f45a12..e82e9899f96 100644 ---- a/grub-core/disk/ldm.c -+++ b/grub-core/disk/ldm.c -@@ -321,7 +321,10 @@ make_vg (grub_disk_t disk, - lv->visible = 1; - lv->segments = grub_zalloc (sizeof (*lv->segments)); - if (!lv->segments) -- goto fail2; -+ { -+ grub_free (lv); -+ goto fail2; -+ } - lv->segments->start_extent = 0; - lv->segments->type = GRUB_DISKFILTER_MIRROR; - lv->segments->node_count = 0; -@@ -329,7 +332,10 @@ make_vg (grub_disk_t disk, - lv->segments->nodes = grub_calloc (lv->segments->node_alloc, - sizeof (*lv->segments->nodes)); - if (!lv->segments->nodes) -- goto fail2; -+ { -+ grub_free (lv); -+ goto fail2; -+ } - ptr = vblk[i].dynamic; - if (ptr + *ptr + 1 >= vblk[i].dynamic - + sizeof (vblk[i].dynamic)) diff --git a/SOURCES/0347-rhel-extra-file-type-fixes.patch b/SOURCES/0347-rhel-extra-file-type-fixes.patch new file mode 100644 index 0000000..aa75443 --- /dev/null +++ b/SOURCES/0347-rhel-extra-file-type-fixes.patch @@ -0,0 +1,124 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 12 May 2020 17:26:26 +1000 +Subject: [PATCH] rhel: extra file type fixes + +Signed-off-by: Daniel Axtens +[javierm: fix a couple of build errors caused by mismerges] +Signed-off-by: Javier Martinez Canillas +--- + grub-core/commands/blscfg.c | 2 +- + grub-core/loader/arm64/linux.c | 1 + + grub-core/loader/i386/efi/linux.c | 9 +++++---- + grub-core/net/net.c | 2 +- + grub-core/normal/main.c | 2 +- + grub-core/osdep/generic/blocklist.c | 4 ++-- + 6 files changed, 11 insertions(+), 9 deletions(-) + +diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c +index 70ce5c7bf6f..795a9f9f178 100644 +--- a/grub-core/commands/blscfg.c ++++ b/grub-core/commands/blscfg.c +@@ -463,7 +463,7 @@ static int read_entry ( + + p = grub_xasprintf ("(%s)%s/%s", info->devid, info->dirname, filename); + +- f = grub_file_open (p); ++ f = grub_file_open (p, GRUB_FILE_TYPE_CONFIG); + if (!f) + goto finish; + +diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c +index 864724dd4fa..e1923cf7257 100644 +--- a/grub-core/loader/arm64/linux.c ++++ b/grub-core/loader/arm64/linux.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + #include + #include + #include +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 361e503cb52..576f8c07eaf 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -101,8 +101,8 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + + for (i = 0; i < argc; i++) + { +- grub_file_filter_disable_compression (); +- files[i] = grub_file_open (argv[i]); ++ files[i] = grub_file_open (argv[i], GRUB_FILE_TYPE_LINUX_INITRD | ++ GRUB_FILE_TYPE_NO_DECOMPRESS); + if (! files[i]) + goto fail; + nfiles++; +@@ -182,7 +182,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- file = grub_file_open (argv[0]); ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); + if (! file) + goto fail; + +@@ -302,7 +302,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); + 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); + + grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline); + grub_dprintf ("linux", "setting lh->cmd_line_ptr\n"); +diff --git a/grub-core/net/net.c b/grub-core/net/net.c +index 0e72bbb9b39..1fd104aeaf2 100644 +--- a/grub-core/net/net.c ++++ b/grub-core/net/net.c +@@ -1907,7 +1907,7 @@ grub_net_search_configfile (char *config) + grub_dprintf ("net", "probe %s\n", config); + + grub_file_t file; +- file = grub_file_open (config); ++ file = grub_file_open (config, GRUB_FILE_TYPE_CONFIG); + + if (file) + { +diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c +index cee71a4c2ab..49141039f8f 100644 +--- a/grub-core/normal/main.c ++++ b/grub-core/normal/main.c +@@ -363,7 +363,7 @@ grub_try_normal (const char *variable) + if (config) + { + grub_file_t file; +- file = grub_file_open (config); ++ file = grub_file_open (config, GRUB_FILE_TYPE_CONFIG); + if (file) + { + grub_file_close (file); +diff --git a/grub-core/osdep/generic/blocklist.c b/grub-core/osdep/generic/blocklist.c +index 74024fd06f3..ab1f96da62d 100644 +--- a/grub-core/osdep/generic/blocklist.c ++++ b/grub-core/osdep/generic/blocklist.c +@@ -60,7 +60,7 @@ grub_install_get_blocklist (grub_device_t root_dev, + grub_disk_cache_invalidate_all (); + + grub_file_filter_disable_compression (); +- file = grub_file_open (core_path_dev); ++ file = grub_file_open (core_path_dev, GRUB_FILE_TYPE_NONE); + if (file) + { + if (grub_file_size (file) != core_size) +@@ -118,7 +118,7 @@ grub_install_get_blocklist (grub_device_t root_dev, + grub_file_t file; + /* Now read the core image to determine where the sectors are. */ + grub_file_filter_disable_compression (); +- file = grub_file_open (core_path_dev); ++ file = grub_file_open (core_path_dev, GRUB_FILE_TYPE_NONE); + if (! file) + grub_util_error ("%s", grub_errmsg); + diff --git a/SOURCES/0348-disk-cryptodisk-Fix-potential-integer-overflow.patch b/SOURCES/0348-disk-cryptodisk-Fix-potential-integer-overflow.patch deleted file mode 100644 index 2470dc5..0000000 --- a/SOURCES/0348-disk-cryptodisk-Fix-potential-integer-overflow.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Thu, 21 Jan 2021 11:38:31 +0000 -Subject: [PATCH] disk/cryptodisk: Fix potential integer overflow - -The encrypt and decrypt functions expect a grub_size_t. So, we need to -ensure that the constant bit shift is using grub_size_t rather than -unsigned int when it is performing the shift. - -Fixes: CID 307788 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/disk/cryptodisk.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c -index bd60a66b384..78a902515e9 100644 ---- a/grub-core/disk/cryptodisk.c -+++ b/grub-core/disk/cryptodisk.c -@@ -311,10 +311,10 @@ grub_cryptodisk_endecrypt (struct grub_cryptodisk *dev, - case GRUB_CRYPTODISK_MODE_CBC: - if (do_encrypt) - err = grub_crypto_cbc_encrypt (dev->cipher, data + i, data + i, -- (1U << dev->log_sector_size), iv); -+ ((grub_size_t) 1 << dev->log_sector_size), iv); - else - err = grub_crypto_cbc_decrypt (dev->cipher, data + i, data + i, -- (1U << dev->log_sector_size), iv); -+ ((grub_size_t) 1 << dev->log_sector_size), iv); - if (err) - return err; - break; -@@ -322,10 +322,10 @@ grub_cryptodisk_endecrypt (struct grub_cryptodisk *dev, - case GRUB_CRYPTODISK_MODE_PCBC: - if (do_encrypt) - err = grub_crypto_pcbc_encrypt (dev->cipher, data + i, data + i, -- (1U << dev->log_sector_size), iv); -+ ((grub_size_t) 1 << dev->log_sector_size), iv); - else - err = grub_crypto_pcbc_decrypt (dev->cipher, data + i, data + i, -- (1U << dev->log_sector_size), iv); -+ ((grub_size_t) 1 << dev->log_sector_size), iv); - if (err) - return err; - break; diff --git a/SOURCES/0348-dl-Add-support-for-persistent-modules.patch b/SOURCES/0348-dl-Add-support-for-persistent-modules.patch new file mode 100644 index 0000000..e534415 --- /dev/null +++ b/SOURCES/0348-dl-Add-support-for-persistent-modules.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Kiper +Date: Tue, 2 Oct 2018 18:49:26 +0200 +Subject: [PATCH] dl: Add support for persistent modules + +This type of modules cannot be unloaded. This is useful if a given +functionality, e.g. UEFI secure boot shim signature verification, should +not be disabled if it was enabled at some point in time. Somebody may +say that we can use standalone GRUB2 here. That is true. However, the +code is not so big nor complicated hence it make sense to support +modularized configs too. + +Signed-off-by: Daniel Kiper +Reviewed-by: Ross Philipson +(cherry picked from commit ee7808e2197cbf5e8515d90ecbd81c9d0dd6fc15) +--- + grub-core/commands/minicmd.c | 3 +++ + include/grub/dl.h | 13 +++++++++++++ + 2 files changed, 16 insertions(+) + +diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c +index 46bf135e8f0..6d66b7c453a 100644 +--- a/grub-core/commands/minicmd.c ++++ b/grub-core/commands/minicmd.c +@@ -137,6 +137,9 @@ grub_mini_cmd_rmmod (struct grub_command *cmd __attribute__ ((unused)), + if (! mod) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such module"); + ++ if (grub_dl_is_persistent (mod)) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "cannot unload persistent module"); ++ + if (grub_dl_unref (mod) <= 0) + grub_dl_unload (mod); + +diff --git a/include/grub/dl.h b/include/grub/dl.h +index 7b5bfb07ce6..f7cfe64823c 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -177,6 +177,7 @@ struct grub_dl + { + char *name; + int ref_count; ++ int persistent; + grub_dl_dep_t dep; + grub_dl_segment_t segment; + Elf_Sym *symtab; +@@ -242,6 +243,18 @@ grub_dl_get (const char *name) + return 0; + } + ++static inline void ++grub_dl_set_persistent (grub_dl_t mod) ++{ ++ mod->persistent = 1; ++} ++ ++static inline int ++grub_dl_is_persistent (grub_dl_t mod) ++{ ++ return mod->persistent; ++} ++ + #endif + + void * EXPORT_FUNC(grub_resolve_symbol) (const char *name); diff --git a/SOURCES/0349-Add-suport-for-signing-grub-with-an-appended-signatu.patch b/SOURCES/0349-Add-suport-for-signing-grub-with-an-appended-signatu.patch new file mode 100644 index 0000000..538e916 --- /dev/null +++ b/SOURCES/0349-Add-suport-for-signing-grub-with-an-appended-signatu.patch @@ -0,0 +1,309 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Rashmica Gupta +Date: Thu, 11 Jun 2020 11:26:23 +1000 +Subject: [PATCH] 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). +--- + util/grub-install-common.c | 16 +++++++++++++--- + util/grub-mkimage.c | 11 +++++++++++ + util/grub-mkimagexx.c | 39 ++++++++++++++++++++++++++++++++++++++- + util/mkimage.c | 10 +++++----- + include/grub/util/install.h | 8 ++++++-- + include/grub/util/mkimage.h | 4 ++-- + 6 files changed, 75 insertions(+), 13 deletions(-) + +diff --git a/util/grub-install-common.c b/util/grub-install-common.c +index cf993c059ad..561e671ff34 100644 +--- a/util/grub-install-common.c ++++ b/util/grub-install-common.c +@@ -303,10 +303,12 @@ handle_install_list (struct install_list *il, const char *val, + static char **pubkeys; + static size_t npubkeys; + 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': +@@ -395,6 +397,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; + } +@@ -493,10 +501,12 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, + grub_util_info ("grub-mkimage --directory '%s' --prefix '%s'" + " --output '%s' " + " --dtb '%s' " +- "--format '%s' --compression '%s' %s %s\n", ++ "--format '%s' --compression '%s' " ++ "--appended-signature-size %zu %s %s\n", + dir, prefix, + outname, dtb ? : "", mkimage_target, +- compnames[compression], note ? "--note" : "", s); ++ compnames[compression], appsig_size, ++ note ? "--note" : "", s); + free (s); + + tgt = grub_install_get_image_target (mkimage_target); +@@ -506,7 +516,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); ++ note, appsig_size, compression, dtb); + while (dc--) + grub_install_pop_module (); + } +diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c +index 98d24cc06ea..65a015d8a04 100644 +--- a/util/grub-mkimage.c ++++ b/util/grub-mkimage.c +@@ -82,6 +82,7 @@ static struct argp_option options[] = { + {"format", 'O', N_("FORMAT"), 0, 0, 0}, + {"compression", 'C', "(xz|none|auto)", 0, N_("choose the compression to use for core image"), 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 } + }; + +@@ -124,6 +125,7 @@ struct arguments + char *font; + char *config; + int note; ++ size_t appsig_size; + const struct grub_install_image_target_desc *image_target; + grub_compression_t comp; + }; +@@ -134,6 +136,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) + { +@@ -166,6 +169,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); +@@ -309,6 +319,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); + + grub_util_file_sync (fp); +diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c +index f9aa1a033b5..1bb5eb84c14 100644 +--- a/util/grub-mkimagexx.c ++++ b/util/grub-mkimagexx.c +@@ -82,6 +82,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 +@@ -205,7 +214,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) + { +@@ -219,6 +228,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; + +@@ -449,6 +464,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 e22d82afa61..a81120f26be 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -777,7 +777,7 @@ 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) ++ int note, size_t appsig_size, grub_compression_t comp, const char *dtb_path) + { + char *kernel_img, *core_img; + size_t total_module_size, core_size; +@@ -1694,11 +1694,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; + } +diff --git a/include/grub/util/install.h b/include/grub/util/install.h +index 0dba8b67f93..ba5e6a2ea8f 100644 +--- a/include/grub/util/install.h ++++ b/include/grub/util/install.h +@@ -63,6 +63,9 @@ + /* TRANSLATORS: "embed" is a verb (command description). "*/ \ + { "pubkey", 'k', N_("FILE"), 0, \ + N_("embed FILE as public key 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}, \ + { "verbose", 'v', 0, 0, \ + N_("print verbose messages."), 1 } + +@@ -119,7 +122,8 @@ enum grub_install_options { + GRUB_INSTALL_OPTIONS_THEMES_DIRECTORY, + GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE, + GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS, +- GRUB_INSTALL_OPTIONS_DTB ++ GRUB_INSTALL_OPTIONS_DTB, ++ GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE + }; + + extern char *grub_install_source_directory; +@@ -179,7 +183,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 struct grub_install_image_target_desc * +diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h +index b3a5ca132bc..cef7fffa7ae 100644 +--- a/include/grub/util/mkimage.h ++++ b/include/grub/util/mkimage.h +@@ -50,12 +50,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/SOURCES/0349-hfsplus-Check-that-the-volume-name-length-is-valid.patch b/SOURCES/0349-hfsplus-Check-that-the-volume-name-length-is-valid.patch deleted file mode 100644 index c32f6e8..0000000 --- a/SOURCES/0349-hfsplus-Check-that-the-volume-name-length-is-valid.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Fri, 23 Oct 2020 17:09:31 +0000 -Subject: [PATCH] hfsplus: Check that the volume name length is valid - -HFS+ documentation suggests that the maximum filename and volume name is -255 Unicode characters in length. - -So, when converting from big-endian to little-endian, we should ensure -that the name of the volume has a length that is between 0 and 255, -inclusive. - -Fixes: CID 73641 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/fs/hfsplus.c | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/grub-core/fs/hfsplus.c b/grub-core/fs/hfsplus.c -index e06bcbb9ba3..03a33ea2477 100644 ---- a/grub-core/fs/hfsplus.c -+++ b/grub-core/fs/hfsplus.c -@@ -1012,6 +1012,15 @@ grub_hfsplus_label (grub_device_t device, char **label) - grub_hfsplus_btree_recptr (&data->catalog_tree, node, ptr); - - label_len = grub_be_to_cpu16 (catkey->namelen); -+ -+ /* Ensure that the length is >= 0. */ -+ if (label_len < 0) -+ label_len = 0; -+ -+ /* Ensure label length is at most 255 Unicode characters. */ -+ if (label_len > 255) -+ label_len = 255; -+ - label_name = grub_calloc (label_len, sizeof (*label_name)); - if (!label_name) - { diff --git a/SOURCES/0350-docs-grub-Document-signing-grub-under-UEFI.patch b/SOURCES/0350-docs-grub-Document-signing-grub-under-UEFI.patch new file mode 100644 index 0000000..dee54ce --- /dev/null +++ b/SOURCES/0350-docs-grub-Document-signing-grub-under-UEFI.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Sat, 15 Aug 2020 02:00:57 +1000 +Subject: [PATCH] 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. + +(adjusted from upstream - s/grub/grub2/ in the docs) +Signed-off-by: Daniel Axtens +--- + docs/grub.texi | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index fa11cc0aff7..acace6c0737 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -5610,6 +5610,7 @@ environment variables and commands are listed in the same order. + @menu + * Authentication and authorisation:: Users and access control + * Using digital signatures:: Booting digitally signed code ++* Signing GRUB itself:: Ensuring the integrity of the GRUB core image + @end menu + + @node Authentication and authorisation +@@ -5687,7 +5688,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} +@@ -5772,6 +5773,22 @@ 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 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}. It will also be ++necessary to enrol the public key used into a relevant firmware key database. ++ + @node Platform limitations + @chapter Platform limitations + diff --git a/SOURCES/0350-zfs-Fix-possible-negative-shift-operation.patch b/SOURCES/0350-zfs-Fix-possible-negative-shift-operation.patch deleted file mode 100644 index dd9d90f..0000000 --- a/SOURCES/0350-zfs-Fix-possible-negative-shift-operation.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Tue, 24 Nov 2020 16:41:49 +0000 -Subject: [PATCH] zfs: Fix possible negative shift operation - -While it is possible for the return value from zfs_log2() to be zero -(0), it is quite unlikely, given that the previous assignment to blksz -is shifted up by SPA_MINBLOCKSHIFT (9) before 9 is subtracted at the -assignment to epbs. - -But, while unlikely during a normal operation, it may be that a carefully -crafted ZFS filesystem could result in a zero (0) value to the -dn_datalbkszsec field, which means that the shift left does nothing -and assigns zero (0) to blksz, resulting in a negative epbs value. - -Fixes: CID 73608 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/fs/zfs/zfs.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c -index c6204367e78..3dfde080750 100644 ---- a/grub-core/fs/zfs/zfs.c -+++ b/grub-core/fs/zfs/zfs.c -@@ -2667,6 +2667,11 @@ dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type, - blksz = grub_zfs_to_cpu16 (mdn->dn.dn_datablkszsec, - mdn->endian) << SPA_MINBLOCKSHIFT; - epbs = zfs_log2 (blksz) - DNODE_SHIFT; -+ -+ /* While this should never happen, we should check that epbs is not negative. */ -+ if (epbs < 0) -+ epbs = 0; -+ - blkid = objnum >> epbs; - idx = objnum & ((1 << epbs) - 1); - diff --git a/SOURCES/0351-docs-grub-Document-signing-grub-with-an-appended-sig.patch b/SOURCES/0351-docs-grub-Document-signing-grub-with-an-appended-sig.patch new file mode 100644 index 0000000..6e65133 --- /dev/null +++ b/SOURCES/0351-docs-grub-Document-signing-grub-with-an-appended-sig.patch @@ -0,0 +1,67 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Sat, 15 Aug 2020 02:19:36 +1000 +Subject: [PATCH] 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 acace6c0737..61c92a1e03d 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -5789,6 +5789,48 @@ 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}. 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 + diff --git a/SOURCES/0351-zfs-Fix-resource-leaks-while-constructing-path.patch b/SOURCES/0351-zfs-Fix-resource-leaks-while-constructing-path.patch deleted file mode 100644 index 3c37522..0000000 --- a/SOURCES/0351-zfs-Fix-resource-leaks-while-constructing-path.patch +++ /dev/null @@ -1,118 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Paulo Flabiano Smorigo -Date: Mon, 14 Dec 2020 18:54:49 -0300 -Subject: [PATCH] zfs: Fix resource leaks while constructing path - -There are several exit points in dnode_get_path() that are causing possible -memory leaks. - -In the while(1) the correct exit mechanism should not be to do a direct return, -but to instead break out of the loop, setting err first if it is not already set. - -The reason behind this is that the dnode_path is a linked list, and while doing -through this loop, it is being allocated and built up - the only way to -correctly unravel it is to traverse it, which is what is being done at the end -of the function outside of the loop. - -Several of the existing exit points correctly did a break, but not all so this -change makes that more consistent and should resolve the leaking of memory as -found by Coverity. - -Fixes: CID 73741 - -Signed-off-by: Paulo Flabiano Smorigo -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/fs/zfs/zfs.c | 30 +++++++++++++++++++++--------- - 1 file changed, 21 insertions(+), 9 deletions(-) - -diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c -index 3dfde080750..44d8bde6b33 100644 ---- a/grub-core/fs/zfs/zfs.c -+++ b/grub-core/fs/zfs/zfs.c -@@ -2836,8 +2836,8 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, - - if (dnode_path->dn.dn.dn_type != DMU_OT_DIRECTORY_CONTENTS) - { -- grub_free (path_buf); -- return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory")); -+ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory")); -+ break; - } - err = zap_lookup (&(dnode_path->dn), cname, &objnum, - data, subvol->case_insensitive); -@@ -2879,11 +2879,18 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, - << SPA_MINBLOCKSHIFT); - - if (blksz == 0) -- return grub_error(GRUB_ERR_BAD_FS, "0-sized block"); -+ { -+ err = grub_error (GRUB_ERR_BAD_FS, "0-sized block"); -+ break; -+ } - - sym_value = grub_malloc (sym_sz); - if (!sym_value) -- return grub_errno; -+ { -+ err = grub_errno; -+ break; -+ } -+ - for (block = 0; block < (sym_sz + blksz - 1) / blksz; block++) - { - void *t; -@@ -2893,7 +2900,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, - if (err) - { - grub_free (sym_value); -- return err; -+ break; - } - - movesize = sym_sz - block * blksz; -@@ -2903,6 +2910,8 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, - grub_memcpy (sym_value + block * blksz, t, movesize); - grub_free (t); - } -+ if (err) -+ break; - free_symval = 1; - } - path = path_buf = grub_malloc (sym_sz + grub_strlen (oldpath) + 1); -@@ -2911,7 +2920,8 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, - grub_free (oldpathbuf); - if (free_symval) - grub_free (sym_value); -- return grub_errno; -+ err = grub_errno; -+ break; - } - grub_memcpy (path, sym_value, sym_sz); - if (free_symval) -@@ -2949,11 +2959,12 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, - - err = zio_read (bp, dnode_path->dn.endian, &sahdrp, NULL, data); - if (err) -- return err; -+ break; - } - else - { -- return grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt"); -+ err = grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt"); -+ break; - } - - hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp)); -@@ -2974,7 +2985,8 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, - if (!path_buf) - { - grub_free (oldpathbuf); -- return grub_errno; -+ err = grub_errno; -+ break; - } - grub_memcpy (path, sym_value, sym_sz); - path [sym_sz] = 0; diff --git a/SOURCES/0352-docs-grub-grub-install-is-no-longer-a-shell-script.patch b/SOURCES/0352-docs-grub-grub-install-is-no-longer-a-shell-script.patch new file mode 100644 index 0000000..2e5823f --- /dev/null +++ b/SOURCES/0352-docs-grub-grub-install-is-no-longer-a-shell-script.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Sat, 15 Aug 2020 01:00:11 +1000 +Subject: [PATCH] docs/grub: grub-install is no longer a shell script + +Since commit cd46aa6cefab in 2013, grub-install hasn't been a shell +script. The para doesn't really add that much, especially since it's +the user manual, so just drop it. + +(adjust docs: s/grub/grub2) +Signed-off-by: Daniel Axtens +--- + docs/grub.texi | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index 61c92a1e03d..34517e67439 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -695,13 +695,6 @@ floppy instead of exposing the USB drive as a hard disk (they call it + This install doesn't conflict with standard install as long as they are in + separate directories. + +-Note that @command{grub2-install} is actually just a shell script and the +-real task is done by other tools such as @command{grub2-mkimage}. Therefore, +-you may run those commands directly to install GRUB, without using +-@command{grub2-install}. Don't do that, however, unless you are very familiar +-with the internals of GRUB. Installing a boot loader on a running OS may be +-extremely dangerous. +- + On EFI systems for fixed disk install you have to mount EFI System Partition. + If you mount it at @file{/boot/efi} then you don't need any special arguments: + diff --git a/SOURCES/0352-zfs-Fix-possible-integer-overflows.patch b/SOURCES/0352-zfs-Fix-possible-integer-overflows.patch deleted file mode 100644 index 1017056..0000000 --- a/SOURCES/0352-zfs-Fix-possible-integer-overflows.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Tue, 8 Dec 2020 22:17:04 +0000 -Subject: [PATCH] zfs: Fix possible integer overflows - -In all cases the problem is that the value being acted upon by -a left-shift is a 32-bit number which is then being used in the -context of a 64-bit number. - -To avoid overflow we ensure that the number being shifted is 64-bit -before the shift is done. - -Fixes: CID 73684, CID 73695, CID 73764 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/fs/zfs/zfs.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c -index 44d8bde6b33..0d8c08eec92 100644 ---- a/grub-core/fs/zfs/zfs.c -+++ b/grub-core/fs/zfs/zfs.c -@@ -564,7 +564,7 @@ find_bestub (uberblock_phys_t * ub_array, - ubptr = (uberblock_phys_t *) ((grub_properly_aligned_t *) ub_array - + ((i << ub_shift) - / sizeof (grub_properly_aligned_t))); -- err = uberblock_verify (ubptr, offset, 1 << ub_shift); -+ err = uberblock_verify (ubptr, offset, (grub_size_t) 1 << ub_shift); - if (err) - { - grub_errno = GRUB_ERR_NONE; -@@ -1543,7 +1543,7 @@ read_device (grub_uint64_t offset, struct grub_zfs_device_desc *desc, - - high = grub_divmod64 ((offset >> desc->ashift) + c, - desc->n_children, &devn); -- csize = bsize << desc->ashift; -+ csize = (grub_size_t) bsize << desc->ashift; - if (csize > len) - csize = len; - -@@ -1635,8 +1635,8 @@ read_device (grub_uint64_t offset, struct grub_zfs_device_desc *desc, - - while (len > 0) - { -- grub_size_t csize; -- csize = ((s / (desc->n_children - desc->nparity)) -+ grub_size_t csize = s; -+ csize = ((csize / (desc->n_children - desc->nparity)) - << desc->ashift); - if (csize > len) - csize = len; diff --git a/SOURCES/0353-docs-grub-pubkey-has-been-supported-for-some-time.patch b/SOURCES/0353-docs-grub-pubkey-has-been-supported-for-some-time.patch new file mode 100644 index 0000000..f8a2e9e --- /dev/null +++ b/SOURCES/0353-docs-grub-pubkey-has-been-supported-for-some-time.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Sat, 15 Aug 2020 02:04:01 +1000 +Subject: [PATCH] docs/grub: --pubkey has been supported for some time + +--pubkey is supported, so we can now document it. + +(adjust docs: s/grub/grub2) +Signed-off-by: Daniel Axtens +--- + docs/grub.texi | 12 +++--------- + 1 file changed, 3 insertions(+), 9 deletions(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index 34517e67439..a833364d5ff 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -5695,15 +5695,9 @@ verified with a public key currently trusted by GRUB + validation fails, then file @file{foo} cannot be opened. This failure + may halt or otherwise impact the boot process. + +-@comment Unfortunately --pubkey is not yet supported by grub2-install, +-@comment but we should not bring up internal detail grub2-mkimage here +-@comment in the user guide (as opposed to developer's manual). +- +-@comment An initial trusted public key can be embedded within the GRUB +-@comment @file{core.img} using the @code{--pubkey} option to +-@comment @command{grub2-mkimage} (@pxref{Invoking grub2-install}). Presently it +-@comment is necessary to write a custom wrapper around @command{grub2-mkimage} +-@comment using the @code{--grub-mkimage} flag to @command{grub2-install}. ++An initial trusted public key can be embedded within the GRUB ++@file{core.img} using the @code{--pubkey} option to ++@command{grub2-install} (@pxref{Invoking grub2-install}). + + GRUB uses GPG-style detached signatures (meaning that a file + @file{foo.sig} will be produced when file @file{foo} is signed), and diff --git a/SOURCES/0353-zfsinfo-Correct-a-check-for-error-allocating-memory.patch b/SOURCES/0353-zfsinfo-Correct-a-check-for-error-allocating-memory.patch deleted file mode 100644 index 4951204..0000000 --- a/SOURCES/0353-zfsinfo-Correct-a-check-for-error-allocating-memory.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Thu, 26 Nov 2020 10:56:45 +0000 -Subject: [PATCH] zfsinfo: Correct a check for error allocating memory - -While arguably the check for grub_errno is correct, we should really be -checking the return value from the function since it is always possible -that grub_errno was set elsewhere, making this code behave incorrectly. - -Fixes: CID 73668 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/fs/zfs/zfsinfo.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/grub-core/fs/zfs/zfsinfo.c b/grub-core/fs/zfs/zfsinfo.c -index c8a28acf52b..bf2918018e7 100644 ---- a/grub-core/fs/zfs/zfsinfo.c -+++ b/grub-core/fs/zfs/zfsinfo.c -@@ -358,8 +358,8 @@ grub_cmd_zfs_bootfs (grub_command_t cmd __attribute__ ((unused)), int argc, - return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); - - devname = grub_file_get_device_name (args[0]); -- if (grub_errno) -- return grub_errno; -+ if (devname == NULL) -+ return GRUB_ERR_OUT_OF_MEMORY; - - dev = grub_device_open (devname); - grub_free (devname); diff --git a/SOURCES/0354-affs-Fix-memory-leaks.patch b/SOURCES/0354-affs-Fix-memory-leaks.patch deleted file mode 100644 index 57c42a0..0000000 --- a/SOURCES/0354-affs-Fix-memory-leaks.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Thu, 26 Nov 2020 12:48:07 +0000 -Subject: [PATCH] affs: Fix memory leaks - -The node structure reference is being allocated but not freed if it -reaches the end of the function. If any of the hooks had returned -a non-zero value, then node would have been copied in to the context -reference, but otherwise node is not stored and should be freed. - -Similarly, the call to grub_affs_create_node() replaces the allocated -memory in node with a newly allocated structure, leaking the existing -memory pointed by node. - -Finally, when dir->parent is set, then we again replace node with newly -allocated memory, which seems unnecessary when we copy in the values -from dir->parent immediately after. - -Fixes: CID 73759 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/fs/affs.c | 18 ++++++++---------- - 1 file changed, 8 insertions(+), 10 deletions(-) - -diff --git a/grub-core/fs/affs.c b/grub-core/fs/affs.c -index 91073795f90..e4615c74381 100644 ---- a/grub-core/fs/affs.c -+++ b/grub-core/fs/affs.c -@@ -400,12 +400,12 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir, - { - unsigned int i; - struct grub_affs_file file; -- struct grub_fshelp_node *node = 0; -+ struct grub_fshelp_node *node, *orig_node; - struct grub_affs_data *data = dir->data; - grub_uint32_t *hashtable; - - /* Create the directory entries for `.' and `..'. */ -- node = grub_zalloc (sizeof (*node)); -+ node = orig_node = grub_zalloc (sizeof (*node)); - if (!node) - return 1; - -@@ -414,9 +414,6 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir, - return 1; - if (dir->parent) - { -- node = grub_zalloc (sizeof (*node)); -- if (!node) -- return 1; - *node = *dir->parent; - if (hook ("..", GRUB_FSHELP_DIR, node, hook_data)) - return 1; -@@ -456,17 +453,18 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir, - - if (grub_affs_create_node (dir, hook, hook_data, &node, &hashtable, - next, &file)) -- return 1; -+ { -+ /* Node has been replaced in function. */ -+ grub_free (orig_node); -+ return 1; -+ } - - next = grub_be_to_cpu32 (file.next); - } - } - -- grub_free (hashtable); -- return 0; -- - fail: -- grub_free (node); -+ grub_free (orig_node); - grub_free (hashtable); - return 0; - } diff --git a/SOURCES/0354-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch b/SOURCES/0354-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch new file mode 100644 index 0000000..859472d --- /dev/null +++ b/SOURCES/0354-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 30 Jul 2020 00:13:21 +1000 +Subject: [PATCH] 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 f7cfe64823c..877821dcb04 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) diff --git a/SOURCES/0355-libgcrypt-mpi-Fix-possible-unintended-sign-extension.patch b/SOURCES/0355-libgcrypt-mpi-Fix-possible-unintended-sign-extension.patch deleted file mode 100644 index c9f3a35..0000000 --- a/SOURCES/0355-libgcrypt-mpi-Fix-possible-unintended-sign-extension.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Tue, 3 Nov 2020 16:43:37 +0000 -Subject: [PATCH] libgcrypt/mpi: Fix possible unintended sign extension - -The array of unsigned char gets promoted to a signed 32-bit int before -it is finally promoted to a size_t. There is the possibility that this -may result in the signed-bit being set for the intermediate signed -32-bit int. We should ensure that the promotion is to the correct type -before we bitwise-OR the values. - -Fixes: CID 96697 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/lib/libgcrypt/mpi/mpicoder.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/grub-core/lib/libgcrypt/mpi/mpicoder.c b/grub-core/lib/libgcrypt/mpi/mpicoder.c -index a3435ed142a..7ecad27b23a 100644 ---- a/grub-core/lib/libgcrypt/mpi/mpicoder.c -+++ b/grub-core/lib/libgcrypt/mpi/mpicoder.c -@@ -458,7 +458,7 @@ gcry_mpi_scan (struct gcry_mpi **ret_mpi, enum gcry_mpi_format format, - if (len && len < 4) - return gcry_error (GPG_ERR_TOO_SHORT); - -- n = (s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]); -+ n = ((size_t)s[0] << 24 | (size_t)s[1] << 16 | (size_t)s[2] << 8 | (size_t)s[3]); - s += 4; - if (len) - len -= 4; diff --git a/SOURCES/0355-verifiers-provide-unsafe-module-list.patch b/SOURCES/0355-verifiers-provide-unsafe-module-list.patch new file mode 100644 index 0000000..5a6148f --- /dev/null +++ b/SOURCES/0355-verifiers-provide-unsafe-module-list.patch @@ -0,0 +1,96 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Wed, 29 Jul 2020 17:46:16 +1000 +Subject: [PATCH] verifiers: provide unsafe module list + +Other verifiers that implement secure boot may want to be able to +use this list and behaviour. + +Upstream, this factors the list out of the shim_lock verifier. +However, that hasn't hit the RHEL8.4 tree yet, so instead +of factoring it out of that we just create it. + +Signed-off-by: Daniel Axtens +--- + grub-core/commands/verifiers.c | 46 ++++++++++++++++++++++++++++++++++++++++++ + include/grub/verify.h | 13 ++++++++++++ + 2 files changed, 59 insertions(+) + +diff --git a/grub-core/commands/verifiers.c b/grub-core/commands/verifiers.c +index 599d79b757e..f64343ac90b 100644 +--- a/grub-core/commands/verifiers.c ++++ b/grub-core/commands/verifiers.c +@@ -218,6 +218,52 @@ grub_verify_string (char *str, enum grub_verify_string_type type) + return GRUB_ERR_NONE; + } + ++/* List of modules which may allow for verifcation to be bypassed. */ ++static const char *const disabled_mods[] = { "iorw", "memrw", "wrmsr", NULL }; ++ ++/* ++ * Does the module in file `io' allow for the a verifier to be bypassed? ++ * ++ * Returns 1 if so, otherwise 0. ++ */ ++char ++grub_is_dangerous_module (grub_file_t io) ++{ ++ char *b, *e; ++ int i; ++ ++ /* Establish GRUB module name. */ ++ b = grub_strrchr (io->name, '/'); ++ e = grub_strrchr (io->name, '.'); ++ ++ b = b ? (b + 1) : io->name; ++ e = e ? e : io->name + grub_strlen (io->name); ++ e = (e > b) ? e : io->name + grub_strlen (io->name); ++ ++ for (i = 0; disabled_mods[i]; i++) ++ if (!grub_strncmp (b, disabled_mods[i], ++ grub_strlen (b) - grub_strlen (e))) ++ return 1; ++ return 0; ++} ++ ++/* ++ * Is there already an unsafe module in memory? ++ * Returns the name if one is loaded, otherwise NULL. ++ */ ++const char * ++grub_dangerous_module_loaded (void) ++{ ++ int i; ++ ++ for (i = 0; disabled_mods[i]; i++) ++ if (grub_dl_get (disabled_mods[i])) ++ { ++ return disabled_mods[i]; ++ } ++ return NULL; ++} ++ + GRUB_MOD_INIT(verifiers) + { + grub_file_filter_register (GRUB_FILE_FILTER_VERIFY, grub_verifiers_open); +diff --git a/include/grub/verify.h b/include/grub/verify.h +index 79022b42258..60c13e7ea8e 100644 +--- a/include/grub/verify.h ++++ b/include/grub/verify.h +@@ -76,3 +76,16 @@ grub_verifier_unregister (struct grub_file_verifier *ver) + + grub_err_t + grub_verify_string (char *str, enum grub_verify_string_type type); ++ ++/* ++ * Does the module in file `io' allow for the a verifier to be bypassed? ++ * ++ * Returns 1 if so, otherwise 0. ++ */ ++char grub_is_dangerous_module (grub_file_t io); ++ ++/* ++ * Is there already an unsafe module in memory? ++ * Returns the name if one is loaded, otherwise NULL. ++ */ ++const char *grub_dangerous_module_loaded (void); diff --git a/SOURCES/0356-libgcrypt-mpi-Fix-possible-NULL-dereference.patch b/SOURCES/0356-libgcrypt-mpi-Fix-possible-NULL-dereference.patch deleted file mode 100644 index 89257f5..0000000 --- a/SOURCES/0356-libgcrypt-mpi-Fix-possible-NULL-dereference.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Thu, 26 Nov 2020 10:41:54 +0000 -Subject: [PATCH] libgcrypt/mpi: Fix possible NULL dereference - -The code in gcry_mpi_scan() assumes that buffer is not NULL, but there -is no explicit check for that, so we add one. - -Fixes: CID 73757 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/lib/libgcrypt/mpi/mpicoder.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/grub-core/lib/libgcrypt/mpi/mpicoder.c b/grub-core/lib/libgcrypt/mpi/mpicoder.c -index 7ecad27b23a..6fe38916532 100644 ---- a/grub-core/lib/libgcrypt/mpi/mpicoder.c -+++ b/grub-core/lib/libgcrypt/mpi/mpicoder.c -@@ -379,6 +379,9 @@ gcry_mpi_scan (struct gcry_mpi **ret_mpi, enum gcry_mpi_format format, - unsigned int len; - int secure = (buffer && gcry_is_secure (buffer)); - -+ if (!buffer) -+ return gcry_error (GPG_ERR_INV_ARG); -+ - if (format == GCRYMPI_FMT_SSH) - len = 0; - else diff --git a/SOURCES/0356-pgp-factor-out-rsa_pad.patch b/SOURCES/0356-pgp-factor-out-rsa_pad.patch new file mode 100644 index 0000000..79a73ec --- /dev/null +++ b/SOURCES/0356-pgp-factor-out-rsa_pad.patch @@ -0,0 +1,191 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 1 Oct 2020 20:23:48 +1000 +Subject: [PATCH] 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 809f11feaef..99615c07b94 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2387,6 +2387,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 d39846d8cfe..bb6543819f0 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 00000000000..dbacd563d01 +--- /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 00000000000..5c338c84a15 +--- /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); ++ diff --git a/SOURCES/0357-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch b/SOURCES/0357-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch new file mode 100644 index 0000000..e8004d2 --- /dev/null +++ b/SOURCES/0357-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch @@ -0,0 +1,71 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 2 Oct 2020 10:49:26 +1000 +Subject: [PATCH] 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 bb6543819f0..75de32c2a00 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 e6c78d16d39..ff62fa30e1a 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) diff --git a/SOURCES/0357-syslinux-Fix-memory-leak-while-parsing.patch b/SOURCES/0357-syslinux-Fix-memory-leak-while-parsing.patch deleted file mode 100644 index 80ed160..0000000 --- a/SOURCES/0357-syslinux-Fix-memory-leak-while-parsing.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Thu, 26 Nov 2020 15:31:53 +0000 -Subject: [PATCH] syslinux: Fix memory leak while parsing - -In syslinux_parse_real() the 2 points where return is being called -didn't release the memory stored in buf which is no longer required. - -Fixes: CID 176634 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/lib/syslinux_parse.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/grub-core/lib/syslinux_parse.c b/grub-core/lib/syslinux_parse.c -index 21ca040ada7..2eb59ff8ac4 100644 ---- a/grub-core/lib/syslinux_parse.c -+++ b/grub-core/lib/syslinux_parse.c -@@ -737,7 +737,10 @@ syslinux_parse_real (struct syslinux_menu *menu) - && grub_strncasecmp ("help", ptr3, ptr4 - ptr3) == 0)) - { - if (helptext (ptr5, file, menu)) -- return 1; -+ { -+ grub_free (buf); -+ return 1; -+ } - continue; - } - -@@ -757,6 +760,7 @@ syslinux_parse_real (struct syslinux_menu *menu) - } - fail: - grub_file_close (file); -+ grub_free (buf); - return err; - } - diff --git a/SOURCES/0358-normal-completion-Fix-leaking-of-memory-when-process.patch b/SOURCES/0358-normal-completion-Fix-leaking-of-memory-when-process.patch deleted file mode 100644 index 984c608..0000000 --- a/SOURCES/0358-normal-completion-Fix-leaking-of-memory-when-process.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Fri, 4 Dec 2020 18:56:48 +0000 -Subject: [PATCH] normal/completion: Fix leaking of memory when processing a - completion - -It is possible for the code to reach the end of the function without -freeing the memory allocated to argv and argc still to be 0. - -We should always call grub_free(argv). The grub_free() will handle -a NULL argument correctly if it reaches that code without the memory -being allocated. - -Fixes: CID 96672 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/normal/completion.c | 10 ++++------ - 1 file changed, 4 insertions(+), 6 deletions(-) - -diff --git a/grub-core/normal/completion.c b/grub-core/normal/completion.c -index 93aa0d8eda8..5036bcf2d98 100644 ---- a/grub-core/normal/completion.c -+++ b/grub-core/normal/completion.c -@@ -401,8 +401,8 @@ char * - grub_normal_do_completion (char *buf, int *restore, - void (*hook) (const char *, grub_completion_type_t, int)) - { -- int argc; -- char **argv; -+ int argc = 0; -+ char **argv = NULL; - - /* Initialize variables. */ - match = 0; -@@ -517,10 +517,8 @@ grub_normal_do_completion (char *buf, int *restore, - - fail: - if (argc != 0) -- { -- grub_free (argv[0]); -- grub_free (argv); -- } -+ grub_free (argv[0]); -+ grub_free (argv); - grub_free (match); - grub_errno = GRUB_ERR_NONE; - diff --git a/SOURCES/0358-posix_wrap-tweaks-in-preparation-for-libtasn1.patch b/SOURCES/0358-posix_wrap-tweaks-in-preparation-for-libtasn1.patch new file mode 100644 index 0000000..2db2a84 --- /dev/null +++ b/SOURCES/0358-posix_wrap-tweaks-in-preparation-for-libtasn1.patch @@ -0,0 +1,64 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Sat, 2 May 2020 00:27:57 +1000 +Subject: [PATCH] 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 95529540398..474a923b074 100644 +--- a/grub-core/lib/posix_wrap/limits.h ++++ b/grub-core/lib/posix_wrap/limits.h +@@ -31,5 +31,6 @@ + #define INT_MAX GRUB_INT_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 7a8d385e973..4634db09f29 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 854eb0122ef..f63412c8da0 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 diff --git a/SOURCES/0359-commands-hashsum-Fix-a-memory-leak.patch b/SOURCES/0359-commands-hashsum-Fix-a-memory-leak.patch deleted file mode 100644 index 5fe9eb6..0000000 --- a/SOURCES/0359-commands-hashsum-Fix-a-memory-leak.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Chris Coulson -Date: Tue, 1 Dec 2020 23:41:24 +0000 -Subject: [PATCH] commands/hashsum: Fix a memory leak - -check_list() uses grub_file_getline(), which allocates a buffer. -If the hash list file contains invalid lines, the function leaks -this buffer when it returns an error. - -Fixes: CID 176635 - -Signed-off-by: Chris Coulson -Reviewed-by: Daniel Kiper ---- - grub-core/commands/hashsum.c | 15 ++++++++++++--- - 1 file changed, 12 insertions(+), 3 deletions(-) - -diff --git a/grub-core/commands/hashsum.c b/grub-core/commands/hashsum.c -index d18687351a5..282922bba1e 100644 ---- a/grub-core/commands/hashsum.c -+++ b/grub-core/commands/hashsum.c -@@ -128,11 +128,17 @@ check_list (const gcry_md_spec_t *hash, const char *hashfilename, - high = hextoval (*p++); - low = hextoval (*p++); - if (high < 0 || low < 0) -- return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list"); -+ { -+ grub_free (buf); -+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list"); -+ } - expected[i] = (high << 4) | low; - } - if ((p[0] != ' ' && p[0] != '\t') || (p[1] != ' ' && p[1] != '\t')) -- return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list"); -+ { -+ grub_free (buf); -+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list"); -+ } - p += 2; - if (prefix) - { -@@ -140,7 +146,10 @@ check_list (const gcry_md_spec_t *hash, const char *hashfilename, - - filename = grub_xasprintf ("%s/%s", prefix, p); - if (!filename) -- return grub_errno; -+ { -+ grub_free (buf); -+ return grub_errno; -+ } - if (!uncompress) - grub_file_filter_disable_compression (); - file = grub_file_open (filename); diff --git a/SOURCES/0359-libtasn1-import-libtasn1-4.16.0.patch b/SOURCES/0359-libtasn1-import-libtasn1-4.16.0.patch new file mode 100644 index 0000000..89552c8 --- /dev/null +++ b/SOURCES/0359-libtasn1-import-libtasn1-4.16.0.patch @@ -0,0 +1,8934 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Wed, 10 Jun 2020 16:31:22 +1000 +Subject: [PATCH] libtasn1: import libtasn1-4.16.0 + +Import a very trimmed-down set of libtasn1 files: + +pushd /tmp +wget https://ftp.gnu.org/gnu/libtasn1/libtasn1-4.16.0.tar.gz +popd +pushd grub-core/lib +mkdir libtasn1 +cp /tmp/libtasn1-4.16.0/{README.md,LICENSE} libtasn1/ +mkdir libtasn1/lib +cp /tmp/libtasn1-4.16.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.16.0/lib/includes/libtasn1.h ../../include/grub/ +git add libtasn1/ ../../include/grub/libtasn1.h +popd + +Signed-off-by: Daniel Axtens +--- + grub-core/lib/libtasn1/lib/coding.c | 1415 ++++++++++++++++++ + grub-core/lib/libtasn1/lib/decoding.c | 2478 +++++++++++++++++++++++++++++++ + grub-core/lib/libtasn1/lib/element.c | 1111 ++++++++++++++ + grub-core/lib/libtasn1/lib/errors.c | 100 ++ + grub-core/lib/libtasn1/lib/gstr.c | 74 + + grub-core/lib/libtasn1/lib/parser_aux.c | 1173 +++++++++++++++ + grub-core/lib/libtasn1/lib/structure.c | 1220 +++++++++++++++ + grub-core/lib/libtasn1/lib/element.h | 40 + + grub-core/lib/libtasn1/lib/gstr.h | 47 + + grub-core/lib/libtasn1/lib/int.h | 221 +++ + grub-core/lib/libtasn1/lib/parser_aux.h | 172 +++ + grub-core/lib/libtasn1/lib/structure.h | 45 + + include/grub/libtasn1.h | 588 ++++++++ + grub-core/lib/libtasn1/LICENSE | 16 + + grub-core/lib/libtasn1/README.md | 91 ++ + 15 files changed, 8791 insertions(+) + 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/errors.c + create mode 100644 grub-core/lib/libtasn1/lib/gstr.c + create mode 100644 grub-core/lib/libtasn1/lib/parser_aux.c + create mode 100644 grub-core/lib/libtasn1/lib/structure.c + create mode 100644 grub-core/lib/libtasn1/lib/element.h + 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.h + create mode 100644 grub-core/lib/libtasn1/lib/structure.h + create mode 100644 include/grub/libtasn1.h + create mode 100644 grub-core/lib/libtasn1/LICENSE + create mode 100644 grub-core/lib/libtasn1/README.md + +diff --git a/grub-core/lib/libtasn1/lib/coding.c b/grub-core/lib/libtasn1/lib/coding.c +new file mode 100644 +index 00000000000..245ea64cf0a +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/coding.c +@@ -0,0 +1,1415 @@ ++/* ++ * Copyright (C) 2002-2014 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; ++ ++ if (der == NULL) ++ return ASN1_VALUE_NOT_VALID; ++ ++ 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; ++ ++ if (der == NULL) ++ return ASN1_VALUE_NOT_VALID; ++ ++ 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; ++ ++ 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) ++ return ASN1_VALUE_NOT_VALID; ++ ++ 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 + counter, &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 + counter, &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 + len2, 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 + len2, 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 00000000000..ff04eb778cb +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/decoding.c +@@ -0,0 +1,2478 @@ ++/* ++ * Copyright (C) 2002-2016 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 ++ ++#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 00000000000..997eb2725dc +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/element.c +@@ -0,0 +1,1111 @@ ++/* ++ * Copyright (C) 2000-2014 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]; ++ 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/errors.c b/grub-core/lib/libtasn1/lib/errors.c +new file mode 100644 +index 00000000000..cee74daf795 +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/errors.c +@@ -0,0 +1,100 @@ ++/* ++ * Copyright (C) 2002-2014 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 00000000000..e91a3a151c0 +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/gstr.c +@@ -0,0 +1,74 @@ ++/* ++ * Copyright (C) 2002-2014 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 > 0) ++ { ++ 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/parser_aux.c b/grub-core/lib/libtasn1/lib/parser_aux.c +new file mode 100644 +index 00000000000..d5dbbf8765d +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/parser_aux.c +@@ -0,0 +1,1173 @@ ++/* ++ * Copyright (C) 2000-2016 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/structure.c b/grub-core/lib/libtasn1/lib/structure.c +new file mode 100644 +index 00000000000..8189c56a4c9 +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/structure.c +@@ -0,0 +1,1220 @@ ++/* ++ * Copyright (C) 2002-2014 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) ++ * ++ * 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); ++ ++ 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/element.h b/grub-core/lib/libtasn1/lib/element.h +new file mode 100644 +index 00000000000..440a33f4bb1 +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/element.h +@@ -0,0 +1,40 @@ ++/* ++ * Copyright (C) 2000-2014 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/gstr.h b/grub-core/lib/libtasn1/lib/gstr.h +new file mode 100644 +index 00000000000..48229844ff3 +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/gstr.h +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (C) 2002-2014 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 00000000000..ea1625786c1 +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/int.h +@@ -0,0 +1,221 @@ ++/* ++ * Copyright (C) 2002-2014 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.h b/grub-core/lib/libtasn1/lib/parser_aux.h +new file mode 100644 +index 00000000000..598e684b355 +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/parser_aux.h +@@ -0,0 +1,172 @@ ++/* ++ * Copyright (C) 2000-2014 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.h b/grub-core/lib/libtasn1/lib/structure.h +new file mode 100644 +index 00000000000..99e685da07a +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/structure.h +@@ -0,0 +1,45 @@ ++/* ++ * Copyright (C) 2002-2014 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 00000000000..6fd7a30dc35 +--- /dev/null ++++ b/include/grub/libtasn1.h +@@ -0,0 +1,588 @@ ++/* ++ * Copyright (C) 2002-2014 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 ++ * ++ */ ++ ++/** ++ * libtasn1:Short_Description: ++ * ++ * GNU ASN.1 library ++ */ ++/** ++ * libtasn1:Long_Description: ++ * ++ * 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.16.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 16 ++ ++/** ++ * 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 0x041000 ++ ++ ++#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(). ++ */ ++struct asn1_static_node_st ++{ ++ const char *name; /* Node name */ ++ unsigned int type; /* Node type */ ++ const void *value; /* Node value */ ++}; ++typedef struct asn1_static_node_st asn1_static_node; ++ ++/* List of constants for field type of node_asn */ ++#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; ++ ++/** ++ * node_asn_struct: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_node instead. ++ */ ++#define node_asn_struct asn1_node_st ++ ++/** ++ * node_asn: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_node instead. ++ */ ++#define node_asn asn1_node_st ++ ++/** ++ * ASN1_TYPE: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_node instead. ++ */ ++#define ASN1_TYPE asn1_node ++ ++/** ++ * ASN1_TYPE_EMPTY: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use NULL instead. ++ */ ++#define ASN1_TYPE_EMPTY NULL ++ ++/** ++ * static_struct_asn: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_static_node instead. ++ */ ++#define static_struct_asn asn1_static_node_st ++ ++/** ++ * ASN1_ARRAY_TYPE: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_static_node instead. ++ */ ++#define ASN1_ARRAY_TYPE asn1_static_node ++ ++/** ++ * asn1_static_node_t: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_static_node instead. ++ */ ++#define asn1_static_node_t asn1_static_node ++ ++/** ++ * node_data_struct: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_data_node_st instead. ++ */ ++#define node_data_struct asn1_data_node_st ++ ++/** ++ * ASN1_DATA_NODE: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_data_node_st instead. ++ */ ++#define ASN1_DATA_NODE asn1_data_node_st ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* LIBTASN1_H */ +diff --git a/grub-core/lib/libtasn1/LICENSE b/grub-core/lib/libtasn1/LICENSE +new file mode 100644 +index 00000000000..e8b3628db9b +--- /dev/null ++++ b/grub-core/lib/libtasn1/LICENSE +@@ -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 00000000000..50a8642296c +--- /dev/null ++++ b/grub-core/lib/libtasn1/README.md +@@ -0,0 +1,91 @@ ++|Branch|CI system|Status| ++|:----:|:-------:|-----:| ++|Master|Gitlab|[![build status](https://gitlab.com/gnutls/libtasn1/badges/master/pipeline.svg)](https://gitlab.com/gnutls/libtasn1/commits/master)[![coverage report](https://gitlab.com/gnutls/libtasn1/badges/master/coverage.svg)](https://gnutls.gitlab.io/libtasn1/coverage)| ++ ++# libtasn1 ++ ++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: ++ ++gNewSense/Debian/Ubuntu: ++``` ++sudo apt-get install make git-core autoconf automake libtool ++sudo apt-get install texinfo texlive texlive-generic-recommended texlive-extra-utils ++sudo apt-get install help2man gtk-doc-tools valgrind abigail-tools ++``` ++ ++The next step is to run autoreconf, ./configure, etc: ++ ++``` ++$ ./bootstrap ++``` ++ ++Then build the project normally: ++ ++``` ++$ make ++$ make check ++``` ++ ++Happy hacking! ++ ++ ++## Manual ++ ++The manual is in the `doc/` directory of the release. You can also browse ++the manual online at: ++ ++ - https://gnutls.gitlab.io/libtasn1/ ++ ++ ++## 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: ++ ++http://www.gnu.org/software/libtasn1/ ++ ++ ++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/SOURCES/0360-libtasn1-disable-code-not-needed-in-grub.patch b/SOURCES/0360-libtasn1-disable-code-not-needed-in-grub.patch new file mode 100644 index 0000000..00f5588 --- /dev/null +++ b/SOURCES/0360-libtasn1-disable-code-not-needed-in-grub.patch @@ -0,0 +1,307 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 1 May 2020 17:12:23 +1000 +Subject: [PATCH] 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 245ea64cf0a..52def598368 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 */ +@@ -281,7 +283,7 @@ _asn1_time_der (unsigned char *str, int str_len, unsigned char *der, + + return ASN1_SUCCESS; + } +- ++#endif + + /* + void +@@ -520,6 +522,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 */ +@@ -596,6 +599,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] = +@@ -648,6 +652,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 */ +@@ -1413,3 +1419,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 ff04eb778cb..42f9a92b5d4 100644 +--- a/grub-core/lib/libtasn1/lib/decoding.c ++++ b/grub-core/lib/libtasn1/lib/decoding.c +@@ -1613,6 +1613,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 +@@ -1643,6 +1644,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 997eb2725dc..539008d8e94 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 +@@ -645,7 +645,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 cee74daf795..42785e8622b 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 8189c56a4c9..fcfde01a393 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, char *output_file_name, + + return ASN1_SUCCESS; + } +- ++#endif + + /** + * asn1_array2tree: +@@ -718,7 +718,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). +@@ -1058,7 +1058,7 @@ asn1_print_structure (FILE * out, asn1_node_const structure, const char *name, + } + } + } +- ++#endif + + + /** +@@ -1153,6 +1153,7 @@ asn1_find_structure_from_oid (asn1_node_const definitions, const char *oidValue) + return NULL; /* ASN1_ELEMENT_NOT_FOUND; */ + } + ++#if 0 + /** + * asn1_copy_node: + * @dst: Destination asn1 node. +@@ -1202,6 +1203,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 6fd7a30dc35..785eda2ae3f 100644 +--- a/include/grub/libtasn1.h ++++ b/include/grub/libtasn1.h +@@ -319,6 +319,8 @@ typedef struct asn1_data_node_st asn1_data_node_st; + /* 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); +@@ -327,14 +329,17 @@ extern ASN1_API int + 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, +@@ -347,9 +352,11 @@ extern ASN1_API int asn1_delete_structure2 (asn1_node * structure, unsigned int + 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, +@@ -365,9 +372,11 @@ extern ASN1_API int + extern ASN1_API int + 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, +@@ -378,12 +387,14 @@ extern ASN1_API int + 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, + const char *elementName, + const void *ider, int len, + char *errorDescription) _ASN1_GCC_ATTR_DEPRECATED; ++#endif + + extern ASN1_API int + asn1_der_decoding_startEnd (asn1_node element, +@@ -408,13 +419,17 @@ extern ASN1_API const char *asn1_find_structure_from_oid (asn1_node_const + 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 diff --git a/SOURCES/0360-video-efi_gop-Remove-unnecessary-return-value-of-gru.patch b/SOURCES/0360-video-efi_gop-Remove-unnecessary-return-value-of-gru.patch deleted file mode 100644 index fce5f99..0000000 --- a/SOURCES/0360-video-efi_gop-Remove-unnecessary-return-value-of-gru.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Tue, 8 Dec 2020 21:14:31 +0000 -Subject: [PATCH] video/efi_gop: Remove unnecessary return value of - grub_video_gop_fill_mode_info() - -The return value of grub_video_gop_fill_mode_info() is never able to be -anything other than GRUB_ERR_NONE. So, rather than continue to return -a value and checking it each time, it is more correct to redefine the -function to not return anything and remove checks of its return value -altogether. - -Fixes: CID 96701 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/video/efi_gop.c | 25 ++++++------------------- - 1 file changed, 6 insertions(+), 19 deletions(-) - -diff --git a/grub-core/video/efi_gop.c b/grub-core/video/efi_gop.c -index c9e40e8d4e9..9fcc41ac03c 100644 ---- a/grub-core/video/efi_gop.c -+++ b/grub-core/video/efi_gop.c -@@ -229,7 +229,7 @@ grub_video_gop_fill_real_mode_info (unsigned mode, - return GRUB_ERR_NONE; - } - --static grub_err_t -+static void - grub_video_gop_fill_mode_info (unsigned mode, - struct grub_efi_gop_mode_info *in, - struct grub_video_mode_info *out) -@@ -254,8 +254,6 @@ grub_video_gop_fill_mode_info (unsigned mode, - out->blit_format = GRUB_VIDEO_BLIT_FORMAT_BGRA_8888; - out->mode_type |= (GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED - | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP); -- -- return GRUB_ERR_NONE; - } - - static int -@@ -268,7 +266,6 @@ grub_video_gop_iterate (int (*hook) (const struct grub_video_mode_info *info, vo - grub_efi_uintn_t size; - grub_efi_status_t status; - struct grub_efi_gop_mode_info *info = NULL; -- grub_err_t err; - struct grub_video_mode_info mode_info; - - status = efi_call_4 (gop->query_mode, gop, mode, &size, &info); -@@ -279,12 +276,7 @@ grub_video_gop_iterate (int (*hook) (const struct grub_video_mode_info *info, vo - continue; - } - -- err = grub_video_gop_fill_mode_info (mode, info, &mode_info); -- if (err) -- { -- grub_errno = GRUB_ERR_NONE; -- continue; -- } -+ grub_video_gop_fill_mode_info (mode, info, &mode_info); - if (hook (&mode_info, hook_arg)) - return 1; - } -@@ -468,13 +460,8 @@ grub_video_gop_setup (unsigned int width, unsigned int height, - - info = gop->mode->info; - -- err = grub_video_gop_fill_mode_info (gop->mode->mode, info, -- &framebuffer.mode_info); -- if (err) -- { -- grub_dprintf ("video", "GOP: couldn't fill mode info\n"); -- return err; -- } -+ grub_video_gop_fill_mode_info (gop->mode->mode, info, -+ &framebuffer.mode_info); - - framebuffer.ptr = (void *) (grub_addr_t) gop->mode->fb_base; - framebuffer.offscreen -@@ -488,8 +475,8 @@ grub_video_gop_setup (unsigned int width, unsigned int height, - { - grub_dprintf ("video", "GOP: couldn't allocate shadow\n"); - grub_errno = 0; -- err = grub_video_gop_fill_mode_info (gop->mode->mode, info, -- &framebuffer.mode_info); -+ grub_video_gop_fill_mode_info (gop->mode->mode, info, -+ &framebuffer.mode_info); - buffer = framebuffer.ptr; - } - diff --git a/SOURCES/0361-libtasn1-changes-for-grub-compatibility.patch b/SOURCES/0361-libtasn1-changes-for-grub-compatibility.patch new file mode 100644 index 0000000..9b2275c --- /dev/null +++ b/SOURCES/0361-libtasn1-changes-for-grub-compatibility.patch @@ -0,0 +1,202 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 1 May 2020 20:44:29 +1000 +Subject: [PATCH] libtasn1: changes for grub compatibility + +Do a few things to make libtasn1 compile as part of grub: + + - replace strcat. grub removed strcat so replace it with the appropriate + calls to memcpy and strlen. + + - 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 +--- + 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/parser_aux.c | 7 ++++--- + grub-core/lib/libtasn1/lib/int.h | 4 ++-- + include/grub/libtasn1.h | 26 ++++++-------------------- + 6 files changed, 22 insertions(+), 33 deletions(-) + +diff --git a/grub-core/lib/libtasn1/lib/decoding.c b/grub-core/lib/libtasn1/lib/decoding.c +index 42f9a92b5d4..7856858b272 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 ++ ++#define c_isdigit grub_isdigit + + #ifdef DEBUG + # define warn() fprintf(stderr, "%s: %d\n", __func__, __LINE__) +@@ -2008,8 +2009,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); ++ memcpy (name + strlen(name), ".", sizeof(" . ")); ++ memcpy (name + strlen(name), p2->name, strlen(p2->name) + 1); + + len = sizeof (value); + result = asn1_read_value (definitions, name, value, &len); +@@ -2026,8 +2027,8 @@ asn1_expand_octet_string (asn1_node_const definitions, asn1_node * element, + if (p2) + { + strcpy (name, definitions->name); +- strcat (name, "."); +- strcat (name, p2->name); ++ memcpy (name + strlen(name), ".", sizeof(" . ")); ++ memcpy (name + strlen(name), p2->name, strlen(p2->name) + 1); + + 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 539008d8e94..ed761ff56bd 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 e91a3a151c0..e33875c2c7c 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); ++ memcpy (dest + dest_size, src, str_size + 1); + } + else + { + if (dest_tot_size - dest_size > 0) + { +- 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/parser_aux.c b/grub-core/lib/libtasn1/lib/parser_aux.c +index d5dbbf8765d..89c9be69dc2 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 ++__attribute__((__pure__)) + static unsigned int + _asn1_hash_name (const char *x) + { +@@ -634,7 +635,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/grub-core/lib/libtasn1/lib/int.h b/grub-core/lib/libtasn1/lib/int.h +index ea1625786c1..4a568efee9c 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/include/grub/libtasn1.h b/include/grub/libtasn1.h +index 785eda2ae3f..28dbf16c4e0 100644 +--- a/include/grub/libtasn1.h ++++ b/include/grub/libtasn1.h +@@ -38,29 +38,15 @@ + #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 ++/* grub: ASN1_API is not used */ + #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 ++/* grub: all our supported compilers support these attributes */ ++#define __LIBTASN1_CONST__ __attribute__((const)) ++#define __LIBTASN1_PURE__ __attribute__((pure)) + +-#include +-#include +-#include /* for FILE* */ ++#include ++#include + + #ifdef __cplusplus + extern "C" diff --git a/SOURCES/0361-video-fb-fbfill-Fix-potential-integer-overflow.patch b/SOURCES/0361-video-fb-fbfill-Fix-potential-integer-overflow.patch deleted file mode 100644 index 895fd9d..0000000 --- a/SOURCES/0361-video-fb-fbfill-Fix-potential-integer-overflow.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Wed, 4 Nov 2020 15:10:51 +0000 -Subject: [PATCH] video/fb/fbfill: Fix potential integer overflow - -The multiplication of 2 unsigned 32-bit integers may overflow before -promotion to unsigned 64-bit. We should ensure that the multiplication -is done with overflow detection. Additionally, use grub_sub() for -subtraction. - -Fixes: CID 73640, CID 73697, CID 73702, CID 73823 - -Signed-off-by: Darren Kenny -Signed-off-by: Marco A Benatto -Reviewed-by: Daniel Kiper ---- - grub-core/video/fb/fbfill.c | 17 +++++++++++++---- - 1 file changed, 13 insertions(+), 4 deletions(-) - -diff --git a/grub-core/video/fb/fbfill.c b/grub-core/video/fb/fbfill.c -index 11816d07a0b..a37acd1e293 100644 ---- a/grub-core/video/fb/fbfill.c -+++ b/grub-core/video/fb/fbfill.c -@@ -31,6 +31,7 @@ - #include - #include - #include -+#include - #include - - /* Generic filler that works for every supported mode. */ -@@ -61,7 +62,9 @@ grub_video_fbfill_direct32 (struct grub_video_fbblit_info *dst, - - /* Calculate the number of bytes to advance from the end of one line - to the beginning of the next line. */ -- rowskip = dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width; -+ if (grub_mul (dst->mode_info->bytes_per_pixel, width, &rowskip) || -+ grub_sub (dst->mode_info->pitch, rowskip, &rowskip)) -+ return; - - /* Get the start address. */ - dstptr = grub_video_fb_get_video_ptr (dst, x, y); -@@ -98,7 +101,9 @@ grub_video_fbfill_direct24 (struct grub_video_fbblit_info *dst, - #endif - /* Calculate the number of bytes to advance from the end of one line - to the beginning of the next line. */ -- rowskip = dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width; -+ if (grub_mul (dst->mode_info->bytes_per_pixel, width, &rowskip) || -+ grub_sub (dst->mode_info->pitch, rowskip, &rowskip)) -+ return; - - /* Get the start address. */ - dstptr = grub_video_fb_get_video_ptr (dst, x, y); -@@ -131,7 +136,9 @@ grub_video_fbfill_direct16 (struct grub_video_fbblit_info *dst, - - /* Calculate the number of bytes to advance from the end of one line - to the beginning of the next line. */ -- rowskip = (dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width); -+ if (grub_mul (dst->mode_info->bytes_per_pixel, width, &rowskip) || -+ grub_sub (dst->mode_info->pitch, rowskip, &rowskip)) -+ return; - - /* Get the start address. */ - dstptr = grub_video_fb_get_video_ptr (dst, x, y); -@@ -161,7 +168,9 @@ grub_video_fbfill_direct8 (struct grub_video_fbblit_info *dst, - - /* Calculate the number of bytes to advance from the end of one line - to the beginning of the next line. */ -- rowskip = dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width; -+ if (grub_mul (dst->mode_info->bytes_per_pixel, width, &rowskip) || -+ grub_sub (dst->mode_info->pitch, rowskip, &rowskip)) -+ return; - - /* Get the start address. */ - dstptr = grub_video_fb_get_video_ptr (dst, x, y); diff --git a/SOURCES/0362-libtasn1-compile-into-asn1-module.patch b/SOURCES/0362-libtasn1-compile-into-asn1-module.patch new file mode 100644 index 0000000..8fbb427 --- /dev/null +++ b/SOURCES/0362-libtasn1-compile-into-asn1-module.patch @@ -0,0 +1,70 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 5 Jun 2020 17:47:25 +1000 +Subject: [PATCH] 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 99615c07b94..c2d922e6d48 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2436,3 +2436,18 @@ module = { + common = loader/i386/xen_file64.c; + extra_dist = loader/i386/xen_fileXX.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 00000000000..622ba942e33 +--- /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+"); diff --git a/SOURCES/0362-video-fb-video_fb-Fix-multiple-integer-overflows.patch b/SOURCES/0362-video-fb-video_fb-Fix-multiple-integer-overflows.patch deleted file mode 100644 index fa61935..0000000 --- a/SOURCES/0362-video-fb-video_fb-Fix-multiple-integer-overflows.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Wed, 4 Nov 2020 14:43:44 +0000 -Subject: [PATCH] video/fb/video_fb: Fix multiple integer overflows - -The calculation of the unsigned 64-bit value is being generated by -multiplying 2, signed or unsigned, 32-bit integers which may overflow -before promotion to unsigned 64-bit. Fix all of them. - -Fixes: CID 73703, CID 73767, CID 73833 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/video/fb/video_fb.c | 52 ++++++++++++++++++++++++++++++------------- - 1 file changed, 36 insertions(+), 16 deletions(-) - -diff --git a/grub-core/video/fb/video_fb.c b/grub-core/video/fb/video_fb.c -index 1a602c8b251..1c9a138dcdc 100644 ---- a/grub-core/video/fb/video_fb.c -+++ b/grub-core/video/fb/video_fb.c -@@ -25,6 +25,7 @@ - #include - #include - #include -+#include - - GRUB_MOD_LICENSE ("GPLv3+"); - -@@ -1417,15 +1418,23 @@ doublebuf_blit_update_screen (void) - { - if (framebuffer.current_dirty.first_line - <= framebuffer.current_dirty.last_line) -- grub_memcpy ((char *) framebuffer.pages[0] -- + framebuffer.current_dirty.first_line -- * framebuffer.back_target->mode_info.pitch, -- (char *) framebuffer.back_target->data -- + framebuffer.current_dirty.first_line -- * framebuffer.back_target->mode_info.pitch, -- framebuffer.back_target->mode_info.pitch -- * (framebuffer.current_dirty.last_line -- - framebuffer.current_dirty.first_line)); -+ { -+ grub_size_t copy_size; -+ -+ if (grub_sub (framebuffer.current_dirty.last_line, -+ framebuffer.current_dirty.first_line, ©_size) || -+ grub_mul (framebuffer.back_target->mode_info.pitch, copy_size, ©_size)) -+ { -+ /* Shouldn't happen, but if it does we've a bug. */ -+ return GRUB_ERR_BUG; -+ } -+ -+ grub_memcpy ((char *) framebuffer.pages[0] + framebuffer.current_dirty.first_line * -+ framebuffer.back_target->mode_info.pitch, -+ (char *) framebuffer.back_target->data + framebuffer.current_dirty.first_line * -+ framebuffer.back_target->mode_info.pitch, -+ copy_size); -+ } - framebuffer.current_dirty.first_line - = framebuffer.back_target->mode_info.height; - framebuffer.current_dirty.last_line = 0; -@@ -1439,7 +1448,7 @@ grub_video_fb_doublebuf_blit_init (struct grub_video_fbrender_target **back, - volatile void *framebuf) - { - grub_err_t err; -- grub_size_t page_size = mode_info.pitch * mode_info.height; -+ grub_size_t page_size = (grub_size_t) mode_info.pitch * mode_info.height; - - framebuffer.offscreen_buffer = grub_zalloc (page_size); - if (! framebuffer.offscreen_buffer) -@@ -1482,12 +1491,23 @@ doublebuf_pageflipping_update_screen (void) - last_line = framebuffer.previous_dirty.last_line; - - if (first_line <= last_line) -- grub_memcpy ((char *) framebuffer.pages[framebuffer.render_page] -- + first_line * framebuffer.back_target->mode_info.pitch, -- (char *) framebuffer.back_target->data -- + first_line * framebuffer.back_target->mode_info.pitch, -- framebuffer.back_target->mode_info.pitch -- * (last_line - first_line)); -+ { -+ grub_size_t copy_size; -+ -+ if (grub_sub (last_line, first_line, ©_size) || -+ grub_mul (framebuffer.back_target->mode_info.pitch, copy_size, ©_size)) -+ { -+ /* Shouldn't happen, but if it does we've a bug. */ -+ return GRUB_ERR_BUG; -+ } -+ -+ grub_memcpy ((char *) framebuffer.pages[framebuffer.render_page] + first_line * -+ framebuffer.back_target->mode_info.pitch, -+ (char *) framebuffer.back_target->data + first_line * -+ framebuffer.back_target->mode_info.pitch, -+ copy_size); -+ } -+ - framebuffer.previous_dirty = framebuffer.current_dirty; - framebuffer.current_dirty.first_line - = framebuffer.back_target->mode_info.height; diff --git a/SOURCES/0363-test_asn1-test-module-for-libtasn1.patch b/SOURCES/0363-test_asn1-test-module-for-libtasn1.patch new file mode 100644 index 0000000..d777fcd --- /dev/null +++ b/SOURCES/0363-test_asn1-test-module-for-libtasn1.patch @@ -0,0 +1,1455 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Wed, 10 Jun 2020 17:48:42 +1000 +Subject: [PATCH] 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 ++ + .../lib/libtasn1_wrap/tests/CVE-2018-1000654.c | 61 ++++++ + grub-core/lib/libtasn1_wrap/tests/Test_overflow.c | 138 ++++++++++++++ + grub-core/lib/libtasn1_wrap/tests/Test_simple.c | 207 ++++++++++++++++++++ + grub-core/lib/libtasn1_wrap/tests/Test_strings.c | 150 +++++++++++++++ + .../lib/libtasn1_wrap/tests/object-id-decoding.c | 116 +++++++++++ + .../lib/libtasn1_wrap/tests/object-id-encoding.c | 120 ++++++++++++ + grub-core/lib/libtasn1_wrap/tests/octet-string.c | 211 +++++++++++++++++++++ + grub-core/lib/libtasn1_wrap/tests/reproducers.c | 81 ++++++++ + grub-core/lib/libtasn1_wrap/wrap_tests.c | 75 ++++++++ + .../tests/CVE-2018-1000654-1_asn1_tab.h | 32 ++++ + .../tests/CVE-2018-1000654-2_asn1_tab.h | 36 ++++ + grub-core/lib/libtasn1_wrap/wrap_tests.h | 38 ++++ + .gitignore | 1 + + tests/test_asn1.in | 12 ++ + 16 files changed, 1297 insertions(+) + 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/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/wrap_tests.h + create mode 100644 tests/test_asn1.in + +diff --git a/Makefile.util.def b/Makefile.util.def +index 5062a0e50fa..3987d4cdacd 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -1275,6 +1275,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 c2d922e6d48..fd1229c6328 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2451,3 +2451,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.c b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c +new file mode 100644 +index 00000000000..534e304521e +--- /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 00000000000..f48aea0ef8b +--- /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 00000000000..9f01006ddf4 +--- /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 00000000000..dbe1474b204 +--- /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 00000000000..d367bbfb5a7 +--- /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 00000000000..3a83b58c59f +--- /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 00000000000..d8a049e8df0 +--- /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 00000000000..dc7268d4c6c +--- /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 00000000000..75fcd21f0d5 +--- /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/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 00000000000..1e7d3d64f55 +--- /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 00000000000..e2561e5ec6d +--- /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/wrap_tests.h b/grub-core/lib/libtasn1_wrap/wrap_tests.h +new file mode 100644 +index 00000000000..555e56dd202 +--- /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/.gitignore b/.gitignore +index a999024652e..f8c5a51af4e 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -133,4 +133,5 @@ grub-*.tar.* + /libgrub_a_init.c + /libgrub_a_init.lst + /stamp-h.in ++/test_asn1 + /widthspec.h +diff --git a/tests/test_asn1.in b/tests/test_asn1.in +new file mode 100644 +index 00000000000..8173c5c270e +--- /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 ++ diff --git a/SOURCES/0363-video-fb-video_fb-Fix-possible-integer-overflow.patch b/SOURCES/0363-video-fb-video_fb-Fix-possible-integer-overflow.patch deleted file mode 100644 index ce9204f..0000000 --- a/SOURCES/0363-video-fb-video_fb-Fix-possible-integer-overflow.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Fri, 4 Dec 2020 14:51:30 +0000 -Subject: [PATCH] video/fb/video_fb: Fix possible integer overflow - -It is minimal possibility that the values being used here will overflow. -So, change the code to use the safemath function grub_mul() to ensure -that doesn't happen. - -Fixes: CID 73761 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/video/fb/video_fb.c | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/grub-core/video/fb/video_fb.c b/grub-core/video/fb/video_fb.c -index 1c9a138dcdc..ae6b89f9aea 100644 ---- a/grub-core/video/fb/video_fb.c -+++ b/grub-core/video/fb/video_fb.c -@@ -1537,7 +1537,13 @@ doublebuf_pageflipping_init (struct grub_video_mode_info *mode_info, - volatile void *page1_ptr) - { - grub_err_t err; -- grub_size_t page_size = mode_info->pitch * mode_info->height; -+ grub_size_t page_size = 0; -+ -+ if (grub_mul (mode_info->pitch, mode_info->height, &page_size)) -+ { -+ /* Shouldn't happen, but if it does we've a bug. */ -+ return GRUB_ERR_BUG; -+ } - - framebuffer.offscreen_buffer = grub_malloc (page_size); - if (! framebuffer.offscreen_buffer) diff --git a/SOURCES/0364-grub-install-support-embedding-x509-certificates.patch b/SOURCES/0364-grub-install-support-embedding-x509-certificates.patch new file mode 100644 index 0000000..3413d7e --- /dev/null +++ b/SOURCES/0364-grub-install-support-embedding-x509-certificates.patch @@ -0,0 +1,255 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Alastair D'Silva +Date: Mon, 6 Jul 2020 13:33:04 +1000 +Subject: [PATCH] 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 +- + util/grub-install-common.c | 23 ++++++++++++++++++++++- + util/grub-mkimage.c | 15 +++++++++++++-- + util/mkimage.c | 41 ++++++++++++++++++++++++++++++++++++++--- + include/grub/kernel.h | 3 ++- + include/grub/util/install.h | 7 +++++-- + 6 files changed, 81 insertions(+), 10 deletions(-) + +diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c +index 75de32c2a00..55d354be0ae 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/util/grub-install-common.c b/util/grub-install-common.c +index 561e671ff34..fa6b65347ea 100644 +--- a/util/grub-install-common.c ++++ b/util/grub-install-common.c +@@ -302,6 +302,8 @@ handle_install_list (struct install_list *il, const char *val, + + static char **pubkeys; + static size_t npubkeys; ++static char **x509keys; ++static size_t nx509keys; + static grub_compression_t compression; + static size_t appsig_size; + +@@ -334,6 +336,12 @@ grub_install_parse (int key, char *arg) + * (npubkeys + 1)); + pubkeys[npubkeys++] = xstrdup (arg); + return 1; ++ case 'x': ++ x509keys = xrealloc (x509keys, ++ sizeof (x509keys[0]) ++ * (nx509keys + 1)); ++ x509keys[nx509keys++] = xstrdup (arg); ++ return 1; + + case GRUB_INSTALL_OPTIONS_VERBOSITY: + verbosity++; +@@ -460,6 +468,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); +@@ -488,6 +499,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++ = '\''; +@@ -515,7 +534,9 @@ 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); + while (dc--) + grub_install_pop_module (); +diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c +index 65a015d8a04..394d2dc5fc9 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}, +@@ -122,6 +123,8 @@ struct arguments + char *dtb; + char **pubkeys; + size_t npubkeys; ++ char **x509keys; ++ size_t nx509keys; + char *font; + char *config; + int note; +@@ -202,6 +205,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); +@@ -317,7 +327,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 a81120f26be..2529de4bb78 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -774,8 +774,10 @@ grub_install_get_image_targets_string (void) + 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) + { +@@ -819,6 +821,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); +@@ -933,7 +948,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); + +@@ -942,6 +957,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; +diff --git a/include/grub/kernel.h b/include/grub/kernel.h +index 9548d552aad..75a057d4666 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 + }; + +diff --git a/include/grub/util/install.h b/include/grub/util/install.h +index ba5e6a2ea8f..95059285bd4 100644 +--- a/include/grub/util/install.h ++++ b/include/grub/util/install.h +@@ -63,6 +63,8 @@ + /* TRANSLATORS: "embed" is a verb (command description). "*/ \ + { "pubkey", 'k', N_("FILE"), 0, \ + N_("embed FILE as public key for signature checking"), 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}, \ +@@ -179,8 +181,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/SOURCES/0364-video-readers-jpeg-Test-for-an-invalid-next-marker-r.patch b/SOURCES/0364-video-readers-jpeg-Test-for-an-invalid-next-marker-r.patch deleted file mode 100644 index e59c09c..0000000 --- a/SOURCES/0364-video-readers-jpeg-Test-for-an-invalid-next-marker-r.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Fri, 4 Dec 2020 15:39:00 +0000 -Subject: [PATCH] video/readers/jpeg: Test for an invalid next marker reference - from a jpeg file - -While it may never happen, and potentially could be caught at the end of -the function, it is worth checking up front for a bad reference to the -next marker just in case of a maliciously crafted file being provided. - -Fixes: CID 73694 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/video/readers/jpeg.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c -index 21b0d9ded67..a4a8269e237 100644 ---- a/grub-core/video/readers/jpeg.c -+++ b/grub-core/video/readers/jpeg.c -@@ -253,6 +253,12 @@ grub_jpeg_decode_quan_table (struct grub_jpeg_data *data) - next_marker = data->file->offset; - next_marker += grub_jpeg_get_word (data); - -+ if (next_marker > data->file->size) -+ { -+ /* Should never be set beyond the size of the file. */ -+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid next reference"); -+ } -+ - while (data->file->offset + sizeof (data->quan_table[id]) + 1 - <= next_marker) - { diff --git a/SOURCES/0365-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch b/SOURCES/0365-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch new file mode 100644 index 0000000..7b7d70c --- /dev/null +++ b/SOURCES/0365-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch @@ -0,0 +1,639 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 30 Jul 2020 01:35:10 +1000 +Subject: [PATCH] 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 +--- + grub-core/commands/appendedsig/gnutls_asn1_tab.c | 121 ++++++ + grub-core/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 00000000000..ddd1314e63b +--- /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 00000000000..adef69d95ce +--- /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 } ++}; diff --git a/SOURCES/0365-gfxmenu-gui_list-Remove-code-that-coverity-is-flaggi.patch b/SOURCES/0365-gfxmenu-gui_list-Remove-code-that-coverity-is-flaggi.patch deleted file mode 100644 index c9caf70..0000000 --- a/SOURCES/0365-gfxmenu-gui_list-Remove-code-that-coverity-is-flaggi.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Mon, 7 Dec 2020 14:44:47 +0000 -Subject: [PATCH] gfxmenu/gui_list: Remove code that coverity is flagging as - dead - -The test of value for NULL before calling grub_strdup() is not required, -since the if condition prior to this has already tested for value being -NULL and cannot reach this code if it is. - -Fixes: CID 73659 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/gfxmenu/gui_list.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/grub-core/gfxmenu/gui_list.c b/grub-core/gfxmenu/gui_list.c -index 01477cdf2b3..df334a6c56f 100644 ---- a/grub-core/gfxmenu/gui_list.c -+++ b/grub-core/gfxmenu/gui_list.c -@@ -771,7 +771,7 @@ list_set_property (void *vself, const char *name, const char *value) - { - self->need_to_recreate_boxes = 1; - grub_free (self->selected_item_box_pattern); -- self->selected_item_box_pattern = value ? grub_strdup (value) : 0; -+ self->selected_item_box_pattern = grub_strdup (value); - self->selected_item_box_pattern_inherit = 0; - } - } diff --git a/SOURCES/0366-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch b/SOURCES/0366-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch new file mode 100644 index 0000000..c638457 --- /dev/null +++ b/SOURCES/0366-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch @@ -0,0 +1,1542 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 30 Jul 2020 01:33:46 +1000 +Subject: [PATCH] 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. + +Signed-off-by: Daniel Axtens +--- + grub-core/commands/appendedsig/asn1util.c | 102 +++ + grub-core/commands/appendedsig/pkcs7.c | 305 +++++++++ + grub-core/commands/appendedsig/x509.c | 972 +++++++++++++++++++++++++++ + grub-core/commands/appendedsig/appendedsig.h | 110 +++ + 4 files changed, 1489 insertions(+) + 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 + create mode 100644 grub-core/commands/appendedsig/appendedsig.h + +diff --git a/grub-core/commands/appendedsig/asn1util.c b/grub-core/commands/appendedsig/asn1util.c +new file mode 100644 +index 00000000000..eff095a9df2 +--- /dev/null ++++ b/grub-core/commands/appendedsig/asn1util.c +@@ -0,0 +1,102 @@ ++/* ++ * 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 "appendedsig.h" ++ ++asn1_node _gnutls_gnutls_asn = ASN1_TYPE_EMPTY; ++asn1_node _gnutls_pkix_asn = ASN1_TYPE_EMPTY; ++ ++extern const ASN1_ARRAY_TYPE gnutls_asn1_tab[]; ++extern const ASN1_ARRAY_TYPE 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 00000000000..dc6afe203f7 +--- /dev/null ++++ b/grub-core/commands/appendedsig/pkcs7.c +@@ -0,0 +1,305 @@ ++/* ++ * 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 ++ ++ ++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; ++ 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; ++ ++ 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 != 1) ++ { ++ err = ++ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ "Only 1 digest algorithm is supported"); ++ goto cleanup_signed_part; ++ } ++ ++ res = ++ asn1_read_value (signed_part, "digestAlgorithms.?1.algorithm", algo_oid, ++ &algo_oid_size); ++ if (res != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error reading digest algorithm: %s", ++ asn1_strerror (res)); ++ goto cleanup_signed_part; ++ } ++ ++ if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0) ++ { ++ msg->hash = grub_crypto_lookup_md_by_name ("sha512"); ++ } ++ else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 0) ++ { ++ msg->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_signed_part; ++ } ++ ++ if (!msg->hash) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Hash algorithm for OID %s not loaded", algo_oid); ++ goto cleanup_signed_part; ++ } ++ ++ /* ++ * 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 signature */ ++ result_buf = ++ grub_asn1_allocate_and_read (signed_part, "signerInfos.?1.signature", ++ "signature data", &result_size); ++ if (!result_buf) ++ { ++ err = grub_errno; ++ goto cleanup_signed_part; ++ } ++ ++ gcry_err = ++ gcry_mpi_scan (&(msg->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 into MPI structure: %d", ++ gcry_err); ++ goto cleanup_result; ++ } ++ ++cleanup_result: ++ grub_free (result_buf); ++cleanup_signed_part: ++ asn1_delete_structure (&signed_part); ++ ++ return err; ++} ++ ++grub_err_t ++parse_pkcs7_signedData (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_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) ++{ ++ gcry_mpi_release (msg->sig_mpi); ++} +diff --git a/grub-core/commands/appendedsig/x509.c b/grub-core/commands/appendedsig/x509.c +new file mode 100644 +index 00000000000..652e4f16870 +--- /dev/null ++++ b/grub-core/commands/appendedsig/x509.c +@@ -0,0 +1,972 @@ ++/* ++ * 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 "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"; ++ ++/* ++ * RFC 5280 4.2.1.9 Basic Constraints ++ */ ++const char *basicConstraints_oid = "2.5.29.19"; ++ ++/* ++ * 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 = ASN1_TYPE_EMPTY; ++ 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 = 1; ++ ++ 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; ++ } ++ ++ 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; ++} ++ ++/* ++ * details here ++ */ ++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 = 1; ++ ++ 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; ++ } ++ ++ /* Only the first bit is permitted to be set */ ++ if (usage != 0x80) ++ { ++ 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; ++} ++ ++ ++/* ++ * 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 ++ * } ++ * ++ * We require that a certificate: ++ * - contain the Digital Signature usage only ++ * - not be a CA ++ * - MUST 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; ++ 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 != GRUB_ERR_NONE) ++ { ++ 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 ("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); ++ } ++ 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 ++certificate_import (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_name; ++ ++ ++ /* ++ * 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_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]); ++} +diff --git a/grub-core/commands/appendedsig/appendedsig.h b/grub-core/commands/appendedsig/appendedsig.h +new file mode 100644 +index 00000000000..9792ef3901e +--- /dev/null ++++ b/grub-core/commands/appendedsig/appendedsig.h +@@ -0,0 +1,110 @@ ++/* ++ * 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 message. ++ * ++ * We make no attempt to match intelligently, so we don't save any info about ++ * the signer. We also support only 1 signerInfo, so we only store a single ++ * MPI for the signature. ++ */ ++struct pkcs7_signedData ++{ ++ const gcry_md_spec_t *hash; ++ gcry_mpi_t sig_mpi; ++}; ++ ++ ++/* 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 ++certificate_import (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 (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/SOURCES/0366-loader-bsd-Check-for-NULL-arg-up-front.patch b/SOURCES/0366-loader-bsd-Check-for-NULL-arg-up-front.patch deleted file mode 100644 index bb1585f..0000000 --- a/SOURCES/0366-loader-bsd-Check-for-NULL-arg-up-front.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Tue, 8 Dec 2020 21:47:13 +0000 -Subject: [PATCH] loader/bsd: Check for NULL arg up-front - -The code in the next block suggests that it is possible for .set to be -true but .arg may still be NULL. - -This code assumes that it is never NULL, yet later is testing if it is -NULL - that is inconsistent. - -So we should check first if .arg is not NULL, and remove this check that -is being flagged by Coverity since it is no longer required. - -Fixes: CID 292471 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/loader/i386/bsd.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c -index 0f317632a3b..35a06e66d38 100644 ---- a/grub-core/loader/i386/bsd.c -+++ b/grub-core/loader/i386/bsd.c -@@ -1600,7 +1600,7 @@ grub_cmd_openbsd (grub_extcmd_context_t ctxt, int argc, char *argv[]) - kernel_type = KERNEL_TYPE_OPENBSD; - bootflags = grub_bsd_parse_flags (ctxt->state, openbsd_flags); - -- if (ctxt->state[OPENBSD_ROOT_ARG].set) -+ if (ctxt->state[OPENBSD_ROOT_ARG].set && ctxt->state[OPENBSD_ROOT_ARG].arg != NULL) - { - const char *arg = ctxt->state[OPENBSD_ROOT_ARG].arg; - unsigned type, unit, part; -@@ -1617,7 +1617,7 @@ grub_cmd_openbsd (grub_extcmd_context_t ctxt, int argc, char *argv[]) - "unknown disk type name"); - - unit = grub_strtoul (arg, (char **) &arg, 10); -- if (! (arg && *arg >= 'a' && *arg <= 'z')) -+ if (! (*arg >= 'a' && *arg <= 'z')) - return grub_error (GRUB_ERR_BAD_ARGUMENT, - "only device specifications of form " - " are supported"); diff --git a/SOURCES/0367-appended-signatures-support-verifying-appended-signa.patch b/SOURCES/0367-appended-signatures-support-verifying-appended-signa.patch new file mode 100644 index 0000000..52a057c --- /dev/null +++ b/SOURCES/0367-appended-signatures-support-verifying-appended-signa.patch @@ -0,0 +1,719 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 30 Jul 2020 01:35:43 +1000 +Subject: [PATCH] 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 kernels and grub modules have appended + signatures. It shares lots of logic with shim-lock verifier about what + files need to be verified and what modules are unsafe to have loaded. + + - commands to manage the list of trusted certificates for verification. + +Similar to the PGP verifier, if a certificate is embedded in the core +image, verification will be enforced unless disabled on the the grub +command line or by load_env. + +Thus, as with the PGP verifier, it is not a complete secure-boot solution: +other mechanisms must be used to ensure that a user cannot drop to the +grub shell and disable verification. + +Signed-off-by: Daniel Axtens +--- + grub-core/Makefile.core.def | 12 + + grub-core/commands/appendedsig/appendedsig.c | 644 +++++++++++++++++++++++++++ + include/grub/file.h | 2 + + 3 files changed, 658 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 fd1229c6328..1cf6b60f82e 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -921,6 +921,18 @@ module = { + cppflags = '-I$(srcdir)/lib/posix_wrap'; + }; + ++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; ++ cflags = '$(CFLAGS_POSIX)'; ++ cppflags = '-I$(srcdir)/lib/posix_wrap'; ++}; ++ + module = { + name = verifiers; + common = commands/verifiers.c; +diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c +new file mode 100644 +index 00000000000..5d8897be5c8 +--- /dev/null ++++ b/grub-core/commands/appendedsig/appendedsig.c +@@ -0,0 +1,644 @@ ++/* ++ * 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 ++#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 int check_sigs = 0; ++ ++static char * ++grub_env_write_sec (struct grub_env_var *var __attribute__((unused)), ++ const char *val) ++{ ++ check_sigs = (*val == '1') || (*val == 'e'); ++ return grub_strdup (check_sigs ? "enforce" : "no"); ++} ++ ++static grub_err_t ++read_cert_from_file (grub_file_t f, struct x509_certificate *certificate) ++{ ++ grub_err_t err; ++ grub_uint8_t *buf = NULL; ++ grub_ssize_t read_size; ++ grub_off_t total_read_size = 0; ++ grub_off_t file_size = grub_file_size (f); ++ ++ ++ if (file_size == GRUB_FILE_SIZE_UNKNOWN) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("Cannot parse a certificate file of unknown size")); ++ ++ buf = grub_zalloc (file_size); ++ if (!buf) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ N_("Could not allocate buffer for certificate file contents")); ++ ++ while (total_read_size < file_size) ++ { ++ read_size = ++ grub_file_read (f, &buf[total_read_size], ++ file_size - total_read_size); ++ if (read_size < 0) ++ { ++ err = grub_error (GRUB_ERR_READ_ERROR, ++ N_("Error reading certificate file")); ++ goto cleanup_buf; ++ } ++ total_read_size += read_size; ++ } ++ ++ err = certificate_import (buf, total_read_size, certificate); ++ if (err != GRUB_ERR_NONE) ++ goto cleanup_buf; ++ ++ return GRUB_ERR_NONE; ++ ++cleanup_buf: ++ grub_free (buf); ++ return err; ++} ++ ++static grub_err_t ++extract_appended_signature (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; ++ 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")); ++ ++#ifdef GRUB_TARGET_WORDS_BIGENDIAN ++ pkcs7_size = sig->sig_metadata.sig_len; ++#else ++ pkcs7_size = __builtin_bswap32 (sig->sig_metadata.sig_len); ++#endif ++ ++ 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 (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; ++ ++ 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; ++ ++ context = grub_zalloc (sig.pkcs7.hash->contextsize); ++ if (!context) ++ return grub_errno; ++ ++ sig.pkcs7.hash->init (context); ++ sig.pkcs7.hash->write (context, buf, datasize); ++ sig.pkcs7.hash->final (context); ++ hash = sig.pkcs7.hash->read (context); ++ grub_dprintf ("appendedsig", ++ "data size %" PRIxGRUB_SIZE ", hash %02x%02x%02x%02x...\n", ++ datasize, 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, sig.pkcs7.hash, pk->mpis[0]); ++ if (rc) ++ { ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("Error padding hash for RSA verification: %d"), ++ rc); ++ goto cleanup; ++ } ++ ++ rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi, &sig.pkcs7.sig_mpi, ++ pk->mpis, NULL, NULL); ++ gcry_mpi_release (hashmpi); ++ ++ if (rc == 0) ++ { ++ grub_dprintf ("appendedsig", "verify with key '%s' succeeded\n", ++ pk->subject); ++ err = GRUB_ERR_NONE; ++ break; ++ } ++ ++ grub_dprintf ("appendedsig", "verify with key '%s' failed with %d\n", ++ pk->subject, rc); ++ } ++ ++ /* 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: ++ grub_free (context); ++ 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_ssize_t read_size; ++ grub_off_t file_size, total_read_size = 0; ++ ++ 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; ++ } ++ ++ file_size = grub_file_size (f); ++ if (file_size == GRUB_FILE_SIZE_UNKNOWN) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("Cannot verify the signature of a file of unknown size")); ++ ++ data = grub_malloc (file_size); ++ if (!data) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ N_("Could not allocate data buffer size " ++ PRIuGRUB_UINT64_T " for verification"), file_size); ++ ++ while (total_read_size < file_size) ++ { ++ read_size = ++ grub_file_read (f, &data[total_read_size], ++ file_size - total_read_size); ++ if (read_size < 0) ++ { ++ err = grub_error (GRUB_ERR_READ_ERROR, ++ N_("Error reading file to verify")); ++ goto cleanup_data; ++ } ++ total_read_size += read_size; ++ } ++ ++ err = grub_verify_appended_signature (data, file_size); ++ ++cleanup_data: ++ 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 %d found - only %d 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, enum grub_file_type type, ++ void **context __attribute__((unused)), ++ enum grub_verify_flags *flags) ++{ ++ const char *dangerous_mod; ++ ++ if (!check_sigs) ++ { ++ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; ++ return GRUB_ERR_NONE; ++ } ++ ++ switch (type & GRUB_FILE_TYPE_MASK) ++ { ++ case GRUB_FILE_TYPE_GRUB_MODULE: ++ if (grub_is_dangerous_module (io)) ++ return grub_error (GRUB_ERR_ACCESS_DENIED, ++ N_("module cannot be loaded in appended signature mode: %s"), ++ io->name); ++ ++ *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK; ++ return GRUB_ERR_NONE; ++ ++ case GRUB_FILE_TYPE_ACPI_TABLE: ++ case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE: ++ *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH; ++ return GRUB_ERR_NONE; ++ ++ 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_MULTIBOOT_KERNEL: ++ case GRUB_FILE_TYPE_BSD_KERNEL: ++ case GRUB_FILE_TYPE_XNU_KERNEL: ++ case GRUB_FILE_TYPE_PLAN9_KERNEL: ++ ++ dangerous_mod = grub_dangerous_module_loaded (); ++ if (dangerous_mod) ++ return grub_error (GRUB_ERR_ACCESS_DENIED, ++ N_("cannot proceed due to dangerous module in memory: %s"), ++ dangerous_mod); ++ ++ *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK; ++ return GRUB_ERR_NONE; ++ ++ default: ++ /* ++ * powerpc only supports the linux loader. If you support more, ++ * (especially chain loaded binaries) make sure they're checked! ++ */ ++ *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", ++ .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; ++ const char *val; ++ ++ val = grub_env_get ("check_appended_signatures"); ++ grub_dprintf ("appendedsig", "check_appended_signatures='%s'\n", val); ++ ++ if (val && (val[0] == '1' || val[0] == 'e')) ++ check_sigs = 1; ++ else ++ check_sigs = 0; ++ ++ grub_trusted_key = NULL; ++ ++ grub_register_variable_hook ("check_appended_signatures", 0, ++ 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; ++ } ++ ++ if (!val || val[0] == '\0') ++ { ++ grub_env_set ("check_appended_signatures", ++ grub_trusted_key ? "enforce" : "no"); ++ } ++ ++ 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 cbbd294655b..2e337dbd68d 100644 +--- a/include/grub/file.h ++++ b/include/grub/file.h +@@ -82,6 +82,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. */ diff --git a/SOURCES/0367-loader-xnu-Fix-memory-leak.patch b/SOURCES/0367-loader-xnu-Fix-memory-leak.patch deleted file mode 100644 index 7d43b7b..0000000 --- a/SOURCES/0367-loader-xnu-Fix-memory-leak.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Thu, 26 Nov 2020 12:53:10 +0000 -Subject: [PATCH] loader/xnu: Fix memory leak - -The code here is finished with the memory stored in name, but it only -frees it if there curvalue is valid, while it could actually free it -regardless. - -The fix is a simple relocation of the grub_free() to before the test -of curvalue. - -Fixes: CID 96646 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/loader/xnu.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c -index 0c4b33250fb..2adeac8a549 100644 ---- a/grub-core/loader/xnu.c -+++ b/grub-core/loader/xnu.c -@@ -1383,9 +1383,9 @@ grub_xnu_fill_devicetree (void) - name[len] = 0; - - curvalue = grub_xnu_create_value (curkey, name); -- if (!curvalue) -- return grub_errno; - grub_free (name); -+ if (!curvalue) -+ return grub_errno; - - data = grub_malloc (grub_strlen (var->value) + 1); - if (!data) diff --git a/SOURCES/0368-appended-signatures-verification-tests.patch b/SOURCES/0368-appended-signatures-verification-tests.patch new file mode 100644 index 0000000..db1aa9b --- /dev/null +++ b/SOURCES/0368-appended-signatures-verification-tests.patch @@ -0,0 +1,897 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 30 Jul 2020 01:31:02 +1000 +Subject: [PATCH] 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 +--- + grub-core/Makefile.core.def | 6 + + grub-core/tests/appended_signature_test.c | 281 +++++++++++++++ + grub-core/tests/lib/functional_test.c | 1 + + grub-core/tests/appended_signatures.h | 557 ++++++++++++++++++++++++++++++ + 4 files changed, 845 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 1cf6b60f82e..8914083d13f 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2040,6 +2040,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 00000000000..88a485200d8 +--- /dev/null ++++ b/grub-core/tests/appended_signature_test.c +@@ -0,0 +1,281 @@ ++/* ++ * 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 DEFINE_TEST_CASE(case_name) \ ++static char * \ ++get_ ## case_name (grub_size_t *sz) \ ++{ \ ++ char *ret; \ ++ *sz = case_name ## _len; \ ++ ret = grub_malloc (*sz); \ ++ if (ret) \ ++ grub_memcpy (ret, case_name, *sz); \ ++ return ret; \ ++} \ ++\ ++static struct grub_procfs_entry case_name ## _entry = \ ++{ \ ++ .name = #case_name, \ ++ .get_contents = get_ ## 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); ++ ++static char * ++get_certificate_der (grub_size_t * sz) ++{ ++ char *ret; ++ *sz = certificate_der_len; ++ ret = grub_malloc (*sz); ++ if (ret) ++ grub_memcpy (ret, certificate_der, *sz); ++ return ret; ++} ++ ++static struct grub_procfs_entry certificate_der_entry = { ++ .name = "certificate.der", ++ .get_contents = get_certificate_der ++}; ++ ++static char * ++get_certificate2_der (grub_size_t * sz) ++{ ++ char *ret; ++ *sz = certificate2_der_len; ++ ret = grub_malloc (*sz); ++ if (ret) ++ grub_memcpy (ret, certificate2_der, *sz); ++ return ret; ++} ++ ++static struct grub_procfs_entry certificate2_der_entry = { ++ .name = "certificate2.der", ++ .get_contents = get_certificate2_der ++}; ++ ++static char * ++get_certificate_printable_der (grub_size_t * sz) ++{ ++ char *ret; ++ *sz = certificate_printable_der_len; ++ ret = grub_malloc (*sz); ++ if (ret) ++ grub_memcpy (ret, certificate_printable_der, *sz); ++ return ret; ++} ++ ++static struct grub_procfs_entry certificate_printable_der_entry = { ++ .name = "certificate_printable.der", ++ .get_contents = get_certificate_printable_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 *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); ++ ++ 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"); ++ ++ DO_TEST (hi_signed, 1); ++ DO_TEST (hi_signed_sha256, 1); ++ DO_TEST (hj_signed, 0); ++ DO_TEST (short_msg, 0); ++ DO_TEST (unsigned_msg, 0); ++ ++ /* ++ * 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); ++ ++ /* ++ * 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); ++ ++ /* ++ * 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); ++ ++ /* ++ * Lastly, check a certificate that uses printableString rather than ++ * utf8String loads properly. ++ */ ++ err = (cmd_trust->func) (cmd_trust, 1, trust_args_printable); ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "distrusting printable certificate 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_FUNCTIONAL_TEST (appended_signature_test, appended_signature_test); +diff --git a/grub-core/tests/lib/functional_test.c b/grub-core/tests/lib/functional_test.c +index 96781fb39b5..403fa5c789a 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"); +diff --git a/grub-core/tests/appended_signatures.h b/grub-core/tests/appended_signatures.h +new file mode 100644 +index 00000000000..aa3dc6278e3 +--- /dev/null ++++ b/grub-core/tests/appended_signatures.h +@@ -0,0 +1,557 @@ ++unsigned char certificate_der[] = { ++ 0x30, 0x82, 0x03, 0x88, 0x30, 0x82, 0x02, 0x70, 0xa0, 0x03, 0x02, 0x01, ++ 0x02, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d, ++ 0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 0x30, ++ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, ++ 0x05, 0x00, 0x30, 0x49, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, ++ 0x03, 0x0c, 0x1f, 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, 0x41, 0x31, 0x1d, ++ 0x30, 0x1b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, ++ 0x01, 0x16, 0x0e, 0x64, 0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, ++ 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x30, 0x30, ++ 0x37, 0x30, 0x39, 0x30, 0x36, 0x32, 0x32, 0x30, 0x37, 0x5a, 0x18, 0x0f, ++ 0x32, 0x31, 0x32, 0x30, 0x30, 0x36, 0x31, 0x35, 0x30, 0x36, 0x32, 0x32, ++ 0x30, 0x37, 0x5a, 0x30, 0x52, 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, 0x31, 0x1d, 0x30, 0x1b, ++ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, ++ 0x0e, 0x64, 0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e, ++ 0x6e, 0x65, 0x74, 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, ++ 0xcd, 0xe8, 0x1c, 0x08, 0x68, 0x2e, 0xcb, 0xfe, 0x8c, 0x4b, 0x3b, 0x61, ++ 0xe7, 0x8e, 0x80, 0x58, 0x85, 0x85, 0xea, 0xc8, 0x3b, 0x42, 0xba, 0x72, ++ 0x84, 0x65, 0x20, 0xbc, 0x48, 0xa2, 0x25, 0x49, 0x6e, 0x1c, 0xb9, 0x7d, ++ 0xeb, 0xc1, 0x0c, 0xa8, 0xb7, 0xcc, 0x13, 0x78, 0xba, 0x11, 0xa4, 0x98, ++ 0xd7, 0xd0, 0x7c, 0xdd, 0xf5, 0x5a, 0xb7, 0xcd, 0x31, 0x0e, 0xcd, 0x9e, ++ 0xa7, 0x19, 0xf0, 0xbd, 0x0f, 0xa6, 0xfe, 0x8a, 0x11, 0x97, 0xed, 0x8b, ++ 0xe5, 0x16, 0xa6, 0x21, 0x13, 0x36, 0xad, 0x05, 0x49, 0xec, 0x29, 0x12, ++ 0x38, 0xa7, 0x4b, 0x0f, 0xa1, 0xfb, 0x72, 0xc0, 0xc0, 0x09, 0x67, 0x78, ++ 0xa8, 0xb6, 0xd6, 0x1a, 0x39, 0xc0, 0xa8, 0xbf, 0x5f, 0x14, 0x89, 0x5c, ++ 0xbc, 0x41, 0x0c, 0x0c, 0x5d, 0x42, 0x2e, 0x1c, 0xdf, 0x1f, 0x1d, 0xc9, ++ 0x43, 0x94, 0x5b, 0x6e, 0x8f, 0x15, 0x8c, 0x8f, 0x94, 0x73, 0x4f, 0x97, ++ 0x54, 0xf1, 0x86, 0x8a, 0xbc, 0xe4, 0xe4, 0x93, 0xc1, 0x5e, 0xc2, 0x3e, ++ 0x31, 0x5e, 0xd4, 0x85, 0x57, 0x14, 0xd0, 0x11, 0x07, 0x65, 0xf4, 0x7c, ++ 0x8f, 0x07, 0x57, 0xe1, 0x22, 0xd4, 0x78, 0x47, 0x65, 0x4e, 0xa9, 0xb3, ++ 0xaa, 0xce, 0xc7, 0x36, 0xfe, 0xda, 0x66, 0x02, 0xb6, 0x8d, 0x18, 0x2f, ++ 0x3b, 0x41, 0x8d, 0x02, 0x08, 0x72, 0x4b, 0x69, 0xbd, 0x1e, 0x58, 0xfc, ++ 0x1b, 0x64, 0x04, 0x52, 0x35, 0x35, 0xe2, 0x3d, 0x3e, 0xde, 0xd6, 0x64, ++ 0xf4, 0xec, 0x57, 0x7e, 0x65, 0x59, 0x00, 0xa6, 0xd3, 0x4b, 0x09, 0x93, ++ 0x2a, 0x95, 0x0f, 0x30, 0xb6, 0xa1, 0x8c, 0xe7, 0x8b, 0x49, 0xa4, 0x1d, ++ 0x25, 0x2d, 0x65, 0x48, 0x8a, 0x0f, 0xcf, 0x2a, 0xa2, 0xe1, 0xef, 0x72, ++ 0x92, 0xc3, 0xf5, 0x21, 0x37, 0x83, 0x9b, 0x6d, 0x0b, 0x1b, 0xb3, 0xa2, ++ 0x32, 0x38, 0x11, 0xb1, 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, 0xe5, 0x2a, 0x4f, 0xf2, 0x84, 0x91, 0x57, 0x91, 0xaf, ++ 0x12, 0xd2, 0xf1, 0xa1, 0x87, 0x73, 0x0f, 0x90, 0x25, 0xa0, 0x7a, 0x30, ++ 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, ++ 0x56, 0xd1, 0xfd, 0xe2, 0x1e, 0x7e, 0x1c, 0x63, 0x4f, 0x47, 0xdb, 0xe4, ++ 0xc4, 0x51, 0x04, 0x03, 0x9a, 0x48, 0x35, 0x6e, 0x30, 0x0d, 0x06, 0x09, ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, ++ 0x82, 0x01, 0x01, 0x00, 0x65, 0x82, 0xd5, 0x88, 0x30, 0xe2, 0x2c, 0x47, ++ 0xf3, 0x31, 0x39, 0xa1, 0x75, 0x9a, 0xb0, 0x8a, 0x6c, 0x4b, 0xac, 0xdf, ++ 0x09, 0x7b, 0x90, 0xb6, 0x9e, 0x76, 0x62, 0x94, 0xc1, 0x3a, 0x99, 0x49, ++ 0x68, 0x29, 0x47, 0x42, 0xc3, 0x06, 0xcb, 0x88, 0x75, 0xe6, 0x79, 0x13, ++ 0x8c, 0x4b, 0x49, 0x6a, 0xb5, 0x56, 0x95, 0xc0, 0x42, 0x21, 0x9b, 0xd4, ++ 0x61, 0xd0, 0x02, 0x41, 0xdd, 0x20, 0x61, 0xe5, 0x91, 0xdf, 0x75, 0x00, ++ 0x25, 0x0e, 0x99, 0x65, 0x5c, 0x54, 0x49, 0x32, 0xa3, 0xe2, 0xcd, 0xa1, ++ 0x5f, 0x40, 0xf3, 0xc5, 0x81, 0xd9, 0x3c, 0xa3, 0x63, 0x5a, 0x38, 0x79, ++ 0xab, 0x77, 0x98, 0xde, 0x8f, 0x4e, 0x9e, 0x26, 0xbc, 0x4e, 0x80, 0x9e, ++ 0x8f, 0xbe, 0xf1, 0x00, 0xb3, 0x78, 0xb9, 0x4b, 0x1d, 0xc7, 0xa4, 0x83, ++ 0x59, 0x56, 0x11, 0xd1, 0x11, 0x1e, 0x50, 0x39, 0xd5, 0x78, 0x14, 0xf3, ++ 0xb9, 0x1d, 0xda, 0xe4, 0xc4, 0x63, 0x74, 0x26, 0xab, 0xa3, 0xfd, 0x9d, ++ 0x58, 0xa2, 0xee, 0x7b, 0x28, 0x34, 0xa3, 0xbe, 0x85, 0x7e, 0xaa, 0x97, ++ 0xb7, 0x5b, 0x9d, 0xa9, 0x4d, 0x96, 0xdb, 0x6b, 0x21, 0xe1, 0x96, 0x5d, ++ 0xc7, 0xad, 0x23, 0x03, 0x9a, 0x16, 0xdb, 0xa4, 0x1f, 0x63, 0xef, 0xaf, ++ 0x1e, 0x4f, 0xf8, 0x27, 0xdc, 0x4b, 0xfc, 0x2b, 0x68, 0x2e, 0xa0, 0xd3, ++ 0xae, 0xf2, 0xce, 0xf5, 0xfc, 0x97, 0x92, 0xd2, 0x29, 0x0f, 0x4f, 0x4b, ++ 0x29, 0xeb, 0x06, 0xcb, 0xf8, 0x21, 0x6e, 0xbc, 0x8b, 0x5c, 0xc5, 0xc9, ++ 0xf7, 0xe2, 0x7c, 0x47, 0xcd, 0x43, 0x98, 0xc4, 0xa3, 0x9a, 0xd7, 0x3e, ++ 0xdc, 0x01, 0x13, 0x28, 0x96, 0xc4, 0x60, 0x83, 0xe2, 0x79, 0xa1, 0x46, ++ 0xef, 0xf5, 0xa4, 0x7b, 0x00, 0xe3, 0x3d, 0x7d, 0xbc, 0xa8, 0x98, 0x49, ++ 0xa8, 0xcf, 0x3b, 0x41, 0xb6, 0x09, 0x97, 0x07 ++}; ++unsigned int certificate_der_len = 908; ++ ++unsigned char hi_signed[] = { ++ 0x68, 0x69, 0x0a, 0x30, 0x82, 0x01, 0xc0, 0x06, 0x09, 0x2a, 0x86, 0x48, ++ 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x01, 0xb1, 0x30, 0x82, ++ 0x01, 0xad, 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, 0x01, ++ 0x8a, 0x30, 0x82, 0x01, 0x86, 0x02, 0x01, 0x01, 0x30, 0x61, 0x30, 0x49, ++ 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1f, 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, 0x41, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x09, ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0e, 0x64, ++ 0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e, 0x6e, 0x65, ++ 0x74, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d, ++ 0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 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, 0x01, 0x00, 0xc7, 0x69, 0x35, 0x21, 0x66, ++ 0x4d, 0x50, 0xd4, 0x73, 0xde, 0xbd, 0x3a, 0xf6, 0x45, 0xe3, 0xe4, 0xd0, ++ 0xb6, 0xa1, 0xe7, 0xc0, 0xa2, 0xc9, 0xf4, 0xf0, 0x05, 0x8c, 0xa4, 0x16, ++ 0x9e, 0x81, 0x0d, 0x21, 0x68, 0xf3, 0xfe, 0x03, 0x96, 0x77, 0x31, 0x69, ++ 0x01, 0xd8, 0x26, 0xd9, 0x48, 0x95, 0xcf, 0xd1, 0x17, 0xb1, 0x0b, 0x6b, ++ 0x2c, 0xf1, 0xb0, 0xab, 0x65, 0x65, 0x56, 0xf8, 0x0c, 0xa7, 0xf7, 0xbb, ++ 0xf6, 0x5a, 0x55, 0x98, 0x14, 0x07, 0x8d, 0x2a, 0xbc, 0x16, 0x48, 0x94, ++ 0xab, 0x2f, 0x85, 0x97, 0x90, 0x51, 0x78, 0xa0, 0xda, 0x60, 0xb5, 0x41, ++ 0x4b, 0xe8, 0x78, 0xc5, 0xa6, 0x04, 0x9d, 0x54, 0x2a, 0x85, 0xfd, 0x86, ++ 0x0b, 0x6d, 0xc2, 0xd2, 0xad, 0x07, 0xff, 0x16, 0x42, 0x82, 0xe3, 0x5c, ++ 0xaa, 0x22, 0x59, 0x78, 0x92, 0xea, 0x94, 0xc3, 0x41, 0xb7, 0xa1, 0x86, ++ 0x44, 0xea, 0xd1, 0xdb, 0xe5, 0xac, 0x30, 0x32, 0xfb, 0x7d, 0x3f, 0xf7, ++ 0x8b, 0x11, 0x7f, 0x80, 0x3b, 0xe5, 0xc7, 0x82, 0x0f, 0x92, 0x07, 0x14, ++ 0x66, 0x01, 0x6e, 0x85, 0xab, 0x3a, 0x14, 0xcf, 0x76, 0xd1, 0x7e, 0x14, ++ 0x85, 0xca, 0x01, 0x73, 0x72, 0x38, 0xdc, 0xde, 0x30, 0x5c, 0xfb, 0xc0, ++ 0x3d, 0x93, 0xef, 0x9c, 0xbc, 0xf8, 0xcc, 0xd2, 0xbf, 0x47, 0xec, 0xf8, ++ 0x88, 0x9b, 0xe1, 0x43, 0xbe, 0xa7, 0x47, 0x96, 0xb6, 0x5d, 0x46, 0x0e, ++ 0x7a, 0x78, 0x38, 0x19, 0xbc, 0xb5, 0xbc, 0x9b, 0x3c, 0x39, 0x92, 0x70, ++ 0x0d, 0x9d, 0x8a, 0x35, 0xaf, 0xb4, 0x9e, 0xf4, 0xef, 0xc1, 0xb8, 0x25, ++ 0xd0, 0x14, 0x91, 0xd6, 0xc2, 0xb6, 0xc7, 0x3c, 0x72, 0x91, 0x0f, 0xad, ++ 0xde, 0xb2, 0x36, 0xf8, 0x4e, 0x59, 0xd4, 0xa4, 0x21, 0x9f, 0x03, 0x95, ++ 0x48, 0x01, 0xb4, 0x05, 0xc3, 0x39, 0x60, 0x51, 0x08, 0xd0, 0xbe, 0x00, ++ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, 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 = 495; ++ ++unsigned char hj_signed[] = { ++ 0x68, 0x6a, 0x0a, 0x30, 0x82, 0x01, 0xc0, 0x06, 0x09, 0x2a, 0x86, 0x48, ++ 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x01, 0xb1, 0x30, 0x82, ++ 0x01, 0xad, 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, 0x01, ++ 0x8a, 0x30, 0x82, 0x01, 0x86, 0x02, 0x01, 0x01, 0x30, 0x61, 0x30, 0x49, ++ 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1f, 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, 0x41, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x09, ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0e, 0x64, ++ 0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e, 0x6e, 0x65, ++ 0x74, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d, ++ 0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 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, 0x01, 0x00, 0xc7, 0x69, 0x35, 0x21, 0x66, ++ 0x4d, 0x50, 0xd4, 0x73, 0xde, 0xbd, 0x3a, 0xf6, 0x45, 0xe3, 0xe4, 0xd0, ++ 0xb6, 0xa1, 0xe7, 0xc0, 0xa2, 0xc9, 0xf4, 0xf0, 0x05, 0x8c, 0xa4, 0x16, ++ 0x9e, 0x81, 0x0d, 0x21, 0x68, 0xf3, 0xfe, 0x03, 0x96, 0x77, 0x31, 0x69, ++ 0x01, 0xd8, 0x26, 0xd9, 0x48, 0x95, 0xcf, 0xd1, 0x17, 0xb1, 0x0b, 0x6b, ++ 0x2c, 0xf1, 0xb0, 0xab, 0x65, 0x65, 0x56, 0xf8, 0x0c, 0xa7, 0xf7, 0xbb, ++ 0xf6, 0x5a, 0x55, 0x98, 0x14, 0x07, 0x8d, 0x2a, 0xbc, 0x16, 0x48, 0x94, ++ 0xab, 0x2f, 0x85, 0x97, 0x90, 0x51, 0x78, 0xa0, 0xda, 0x60, 0xb5, 0x41, ++ 0x4b, 0xe8, 0x78, 0xc5, 0xa6, 0x04, 0x9d, 0x54, 0x2a, 0x85, 0xfd, 0x86, ++ 0x0b, 0x6d, 0xc2, 0xd2, 0xad, 0x07, 0xff, 0x16, 0x42, 0x82, 0xe3, 0x5c, ++ 0xaa, 0x22, 0x59, 0x78, 0x92, 0xea, 0x94, 0xc3, 0x41, 0xb7, 0xa1, 0x86, ++ 0x44, 0xea, 0xd1, 0xdb, 0xe5, 0xac, 0x30, 0x32, 0xfb, 0x7d, 0x3f, 0xf7, ++ 0x8b, 0x11, 0x7f, 0x80, 0x3b, 0xe5, 0xc7, 0x82, 0x0f, 0x92, 0x07, 0x14, ++ 0x66, 0x01, 0x6e, 0x85, 0xab, 0x3a, 0x14, 0xcf, 0x76, 0xd1, 0x7e, 0x14, ++ 0x85, 0xca, 0x01, 0x73, 0x72, 0x38, 0xdc, 0xde, 0x30, 0x5c, 0xfb, 0xc0, ++ 0x3d, 0x93, 0xef, 0x9c, 0xbc, 0xf8, 0xcc, 0xd2, 0xbf, 0x47, 0xec, 0xf8, ++ 0x88, 0x9b, 0xe1, 0x43, 0xbe, 0xa7, 0x47, 0x96, 0xb6, 0x5d, 0x46, 0x0e, ++ 0x7a, 0x78, 0x38, 0x19, 0xbc, 0xb5, 0xbc, 0x9b, 0x3c, 0x39, 0x92, 0x70, ++ 0x0d, 0x9d, 0x8a, 0x35, 0xaf, 0xb4, 0x9e, 0xf4, 0xef, 0xc1, 0xb8, 0x25, ++ 0xd0, 0x14, 0x91, 0xd6, 0xc2, 0xb6, 0xc7, 0x3c, 0x72, 0x91, 0x0f, 0xad, ++ 0xde, 0xb2, 0x36, 0xf8, 0x4e, 0x59, 0xd4, 0xa4, 0x21, 0x9f, 0x03, 0x95, ++ 0x48, 0x01, 0xb4, 0x05, 0xc3, 0x39, 0x60, 0x51, 0x08, 0xd0, 0xbe, 0x00, ++ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, 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 = 495; ++ ++unsigned char hi_signed_sha256[] = { ++ 0x68, 0x69, 0x0a, 0x30, 0x82, 0x01, 0xc0, 0x06, 0x09, 0x2a, 0x86, 0x48, ++ 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x01, 0xb1, 0x30, 0x82, ++ 0x01, 0xad, 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, 0x01, ++ 0x8a, 0x30, 0x82, 0x01, 0x86, 0x02, 0x01, 0x01, 0x30, 0x61, 0x30, 0x49, ++ 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1f, 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, 0x41, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x09, ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0e, 0x64, ++ 0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e, 0x6e, 0x65, ++ 0x74, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d, ++ 0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 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, 0x01, 0x00, 0x7b, 0x5e, 0x82, 0x1d, 0x21, ++ 0xb6, 0x40, 0xd3, 0x33, 0x79, 0xa7, 0x52, 0x2b, 0xfc, 0x46, 0x51, 0x26, ++ 0xfe, 0x0f, 0x81, 0x90, 0x81, 0xab, 0x57, 0x5e, 0xf6, 0x45, 0x41, 0xa3, ++ 0x7b, 0x48, 0xdd, 0xd6, 0x59, 0x60, 0x51, 0x31, 0x14, 0x14, 0x7b, 0xb4, ++ 0x55, 0x7b, 0x4d, 0xfe, 0x09, 0x7a, 0x5d, 0xae, 0xc4, 0x58, 0x50, 0x80, ++ 0x75, 0xf2, 0x23, 0x20, 0x62, 0xe3, 0x7c, 0x26, 0x1d, 0x2a, 0x4d, 0x9f, ++ 0x89, 0xf0, 0x4f, 0x95, 0x8a, 0x80, 0x6e, 0x1a, 0xea, 0x87, 0xdb, 0x1f, ++ 0xf3, 0xda, 0x04, 0x91, 0x37, 0xea, 0x0a, 0xfb, 0x6c, 0xc9, 0x3d, 0x73, ++ 0xf9, 0x58, 0x7c, 0x15, 0x6b, 0xa2, 0x52, 0x5a, 0x97, 0xff, 0xd6, 0xb0, ++ 0xf1, 0xbf, 0xa5, 0x04, 0x6d, 0x91, 0xc1, 0x54, 0x05, 0xdc, 0x7f, 0x5d, ++ 0x19, 0xaf, 0x55, 0xec, 0x51, 0xfb, 0x66, 0x0a, 0xa4, 0x4e, 0x96, 0x47, ++ 0x43, 0x54, 0x7c, 0x64, 0xa8, 0xaa, 0xb4, 0x90, 0x02, 0xf3, 0xa7, 0x0b, ++ 0xb7, 0xbf, 0x06, 0xdb, 0x5e, 0x9c, 0x32, 0x6d, 0x45, 0x14, 0x1c, 0xaf, ++ 0x46, 0x30, 0x08, 0x55, 0x49, 0x78, 0xfa, 0x57, 0xda, 0x3d, 0xf5, 0xa0, ++ 0xef, 0x11, 0x0a, 0x81, 0x0d, 0x82, 0xcd, 0xaf, 0xdb, 0xda, 0x0e, 0x1a, ++ 0x44, 0xd1, 0xee, 0xc4, 0xb8, 0xde, 0x97, 0xb4, 0xda, 0xb4, 0x8b, 0x4f, ++ 0x58, 0x24, 0x59, 0xc0, 0xe0, 0x08, 0x97, 0x14, 0x68, 0xbe, 0x31, 0x09, ++ 0x5e, 0x67, 0x45, 0xf0, 0xcb, 0x81, 0x4f, 0x17, 0x44, 0x61, 0xe0, 0xe2, ++ 0xf0, 0xfc, 0x1e, 0xb9, 0x73, 0xaf, 0x42, 0xff, 0x33, 0xde, 0x61, 0x6b, ++ 0x7f, 0xc2, 0x69, 0x0d, 0x66, 0x54, 0xae, 0xf6, 0xde, 0x20, 0x47, 0x44, ++ 0x9b, 0x73, 0xd1, 0x07, 0x6e, 0x77, 0x37, 0x0a, 0xbb, 0x7f, 0xa0, 0x93, ++ 0x2d, 0x8d, 0x44, 0xba, 0xe2, 0xdd, 0x34, 0x32, 0xd7, 0x56, 0x71, 0x00, ++ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, 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 = 495; ++ ++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 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; diff --git a/SOURCES/0368-loader-xnu-Free-driverkey-data-when-an-error-is-dete.patch b/SOURCES/0368-loader-xnu-Free-driverkey-data-when-an-error-is-dete.patch deleted file mode 100644 index 5faa317..0000000 --- a/SOURCES/0368-loader-xnu-Free-driverkey-data-when-an-error-is-dete.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Marco A Benatto -Date: Mon, 30 Nov 2020 12:18:24 -0300 -Subject: [PATCH] loader/xnu: Free driverkey data when an error is detected in - grub_xnu_writetree_toheap() - -... to avoid memory leaks. - -Fixes: CID 96640 - -Signed-off-by: Marco A Benatto -Reviewed-by: Daniel Kiper ---- - grub-core/loader/xnu.c | 24 ++++++++++++++++++++---- - 1 file changed, 20 insertions(+), 4 deletions(-) - -diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c -index 2adeac8a549..a0aaa290ef7 100644 ---- a/grub-core/loader/xnu.c -+++ b/grub-core/loader/xnu.c -@@ -227,26 +227,33 @@ grub_xnu_writetree_toheap (grub_addr_t *target, grub_size_t *size) - if (! memorymap) - return grub_errno; - -- driverkey = (struct grub_xnu_devtree_key *) grub_malloc (sizeof (*driverkey)); -+ driverkey = (struct grub_xnu_devtree_key *) grub_zalloc (sizeof (*driverkey)); - if (! driverkey) - return grub_errno; - driverkey->name = grub_strdup ("DeviceTree"); - if (! driverkey->name) -- return grub_errno; -+ { -+ err = grub_errno; -+ goto fail; -+ } -+ - driverkey->datasize = sizeof (*extdesc); - driverkey->next = memorymap->first_child; - memorymap->first_child = driverkey; - driverkey->data = extdesc - = (struct grub_xnu_extdesc *) grub_malloc (sizeof (*extdesc)); - if (! driverkey->data) -- return grub_errno; -+ { -+ err = grub_errno; -+ goto fail; -+ } - - /* Allocate the space based on the size with dummy value. */ - *size = grub_xnu_writetree_get_size (grub_xnu_devtree_root, "/"); - err = grub_xnu_heap_malloc (ALIGN_UP (*size + 1, GRUB_XNU_PAGESIZE), - &src, target); - if (err) -- return err; -+ goto fail; - - /* Put real data in the dummy. */ - extdesc->addr = *target; -@@ -255,6 +262,15 @@ grub_xnu_writetree_toheap (grub_addr_t *target, grub_size_t *size) - /* Write the tree to heap. */ - grub_xnu_writetree_toheap_real (src, grub_xnu_devtree_root, "/"); - return GRUB_ERR_NONE; -+ -+ fail: -+ memorymap->first_child = NULL; -+ -+ grub_free (driverkey->data); -+ grub_free (driverkey->name); -+ grub_free (driverkey); -+ -+ return err; - } - - /* Find a key or value in parent key. */ diff --git a/SOURCES/0369-appended-signatures-documentation.patch b/SOURCES/0369-appended-signatures-documentation.patch new file mode 100644 index 0000000..82f50de --- /dev/null +++ b/SOURCES/0369-appended-signatures-documentation.patch @@ -0,0 +1,329 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 1 Oct 2020 13:02:09 +1000 +Subject: [PATCH] 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. + +(docs: s/grub/grub2/) +Signed-off-by: Daniel Axtens +--- + docs/grub.texi | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 172 insertions(+), 13 deletions(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index a833364d5ff..97f0f47e082 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -3160,6 +3160,7 @@ These variables have special meaning to GRUB. + + @menu + * biosnum:: ++* check_appended_signatures:: + * check_signatures:: + * chosen:: + * cmdpath:: +@@ -3219,11 +3220,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 +@@ -3937,6 +3945,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 +@@ -3953,6 +3962,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 +@@ -3989,9 +3999,11 @@ 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 + * uppermem:: Set the upper memory size + @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 +@@ -4282,9 +4294,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 + +@@ -4542,6 +4573,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 + +@@ -4561,7 +4607,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 + +@@ -4596,8 +4642,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 + + +@@ -4883,7 +4933,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 + + +@@ -5208,11 +5258,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 an 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 + +@@ -5237,6 +5307,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 +@@ -5255,7 +5337,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 +@@ -5601,9 +5683,10 @@ 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 +-* 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 ++* Signing GRUB itself:: Ensuring the integrity of the GRUB core image + @end menu + + @node Authentication and authorisation +@@ -5676,8 +5759,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. +@@ -5760,6 +5843,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 Signing GRUB itself + @section Signing GRUB itself + diff --git a/SOURCES/0369-loader-xnu-Check-if-pointer-is-NULL-before-using-it.patch b/SOURCES/0369-loader-xnu-Check-if-pointer-is-NULL-before-using-it.patch deleted file mode 100644 index 4677022..0000000 --- a/SOURCES/0369-loader-xnu-Check-if-pointer-is-NULL-before-using-it.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Paulo Flabiano Smorigo -Date: Mon, 30 Nov 2020 10:36:00 -0300 -Subject: [PATCH] loader/xnu: Check if pointer is NULL before using it - -Fixes: CID 73654 - -Signed-off-by: Paulo Flabiano Smorigo -Reviewed-by: Daniel Kiper ---- - grub-core/loader/xnu.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c -index a0aaa290ef7..5e0c8c84797 100644 ---- a/grub-core/loader/xnu.c -+++ b/grub-core/loader/xnu.c -@@ -662,6 +662,9 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile, - char *name, *nameend; - int namelen; - -+ if (infoplistname == NULL) -+ return grub_error (GRUB_ERR_BAD_FILENAME, N_("missing p-list filename")); -+ - name = get_name_ptr (infoplistname); - nameend = grub_strchr (name, '/'); - -@@ -693,10 +696,7 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile, - else - macho = 0; - -- if (infoplistname) -- infoplist = grub_file_open (infoplistname); -- else -- infoplist = 0; -+ infoplist = grub_file_open (infoplistname); - grub_errno = GRUB_ERR_NONE; - if (infoplist) - { diff --git a/SOURCES/0370-ieee1275-link-appended-signature-enforcement-to-ibm-.patch b/SOURCES/0370-ieee1275-link-appended-signature-enforcement-to-ibm-.patch new file mode 100644 index 0000000..219d181 --- /dev/null +++ b/SOURCES/0370-ieee1275-link-appended-signature-enforcement-to-ibm-.patch @@ -0,0 +1,137 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 28 Sep 2020 11:11:17 +1000 +Subject: [PATCH] ieee1275: link appended-signature enforcement to + /ibm,secure-boot + +If the 'ibm,secure-boot' property of the root node is 2 or greater, +require that the kernel pass appended-signature verification. + +Do not consider the presence of a certificate to enforce verification. + +Signed-off-by: Daniel Axtens +--- + grub-core/commands/appendedsig/appendedsig.c | 44 +++++++++++++++++++++------- + grub-core/kern/ieee1275/init.c | 26 ++++++++++++++++ + 2 files changed, 60 insertions(+), 10 deletions(-) + +diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c +index 5d8897be5c8..4ef2ec2893c 100644 +--- a/grub-core/commands/appendedsig/appendedsig.c ++++ b/grub-core/commands/appendedsig/appendedsig.c +@@ -95,10 +95,24 @@ static char * + grub_env_write_sec (struct grub_env_var *var __attribute__((unused)), + const char *val) + { ++ if (check_sigs == 2) ++ return grub_strdup ("forced"); + check_sigs = (*val == '1') || (*val == 'e'); + return grub_strdup (check_sigs ? "enforce" : "no"); + } + ++static const char * ++grub_env_read_sec (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ if (check_sigs == 2) ++ return "forced"; ++ else if (check_sigs == 1) ++ return "enforce"; ++ else ++ return "no"; ++} ++ + static grub_err_t + read_cert_from_file (grub_file_t f, struct x509_certificate *certificate) + { +@@ -552,14 +566,20 @@ GRUB_MOD_INIT (appendedsig) + val = grub_env_get ("check_appended_signatures"); + grub_dprintf ("appendedsig", "check_appended_signatures='%s'\n", val); + +- if (val && (val[0] == '1' || val[0] == 'e')) +- check_sigs = 1; +- else +- check_sigs = 0; ++ if (val) ++ { ++ if (val[0] == '2' || val[0] == 'f') ++ check_sigs = 2; ++ else if (val[0] == '1' || val[0] == 'e') ++ check_sigs = 1; ++ else ++ check_sigs = 0; ++ } + + grub_trusted_key = NULL; + +- grub_register_variable_hook ("check_appended_signatures", 0, ++ grub_register_variable_hook ("check_appended_signatures", ++ grub_env_read_sec, + grub_env_write_sec); + grub_env_export ("check_appended_signatures"); + +@@ -603,11 +623,15 @@ GRUB_MOD_INIT (appendedsig) + grub_trusted_key = pk; + } + +- if (!val || val[0] == '\0') +- { +- grub_env_set ("check_appended_signatures", +- grub_trusted_key ? "enforce" : "no"); +- } ++ /* ++ * When controlled by ibm,secure-boot, we don't want the presence of ++ * a certificate to enforce secure boot. ++ * if (!val || val[0] == '\0') ++ * { ++ * grub_env_set ("check_appended_signatures", ++ * grub_trusted_key ? "enforce" : "no"); ++ * } ++ */ + + cmd_trust = + grub_register_command ("trust_certificate", grub_cmd_trust, +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index e731a57a47b..22dc3013d86 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -268,6 +268,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_env_set("check_appended_signatures", "forced"); ++} ++ + grub_addr_t grub_modbase; + + void +@@ -290,6 +314,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/SOURCES/0370-util-grub-editenv-Fix-incorrect-casting-of-a-signed-.patch b/SOURCES/0370-util-grub-editenv-Fix-incorrect-casting-of-a-signed-.patch deleted file mode 100644 index c90ca09..0000000 --- a/SOURCES/0370-util-grub-editenv-Fix-incorrect-casting-of-a-signed-.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Thu, 5 Nov 2020 14:33:50 +0000 -Subject: [PATCH] util/grub-editenv: Fix incorrect casting of a signed value - -The return value of ftell() may be negative (-1) on error. While it is -probably unlikely to occur, we should not blindly cast to an unsigned -value without first testing that it is not negative. - -Fixes: CID 73856 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - util/grub-editenv.c | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/util/grub-editenv.c b/util/grub-editenv.c -index 2918bb71cfe..e9011e0fbde 100644 ---- a/util/grub-editenv.c -+++ b/util/grub-editenv.c -@@ -128,6 +128,7 @@ open_envblk_file (const char *name) - { - FILE *fp; - char *buf; -+ long loc; - size_t size; - grub_envblk_t envblk; - -@@ -146,7 +147,12 @@ open_envblk_file (const char *name) - grub_util_error (_("cannot seek `%s': %s"), name, - strerror (errno)); - -- size = (size_t) ftell (fp); -+ loc = ftell (fp); -+ if (loc < 0) -+ grub_util_error (_("cannot get file location `%s': %s"), name, -+ strerror (errno)); -+ -+ size = (size_t) loc; - - if (fseek (fp, 0, SEEK_SET) < 0) - grub_util_error (_("cannot seek `%s': %s"), name, diff --git a/SOURCES/0371-include-grub-verify.h-Add-include-guard.patch b/SOURCES/0371-include-grub-verify.h-Add-include-guard.patch new file mode 100644 index 0000000..d757ffd --- /dev/null +++ b/SOURCES/0371-include-grub-verify.h-Add-include-guard.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Leif Lindholm +Date: Wed, 14 Nov 2018 19:29:15 +0000 +Subject: [PATCH] include/grub/verify.h: Add include guard + +verify.h was added without include guards. This means compiling anything +including both include/grub/verify.h and include/grub/lib/cmdline.h fails +(at least grub-core/loader/arm64/linux.c. + +Add the necessary include guard. + +Signed-off-by: Leif Lindholm +Reviewed-by: Daniel Kiper +--- + include/grub/verify.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/grub/verify.h b/include/grub/verify.h +index 60c13e7ea8e..ace72d74663 100644 +--- a/include/grub/verify.h ++++ b/include/grub/verify.h +@@ -16,6 +16,9 @@ + * along with GRUB. If not, see . + */ + ++#ifndef GRUB_VERIFY_HEADER ++#define GRUB_VERIFY_HEADER 1 ++ + #include + #include + +@@ -89,3 +92,5 @@ char grub_is_dangerous_module (grub_file_t io); + * Returns the name if one is loaded, otherwise NULL. + */ + const char *grub_dangerous_module_loaded (void); ++ ++#endif /* ! GRUB_VERIFY_HEADER */ diff --git a/SOURCES/0371-util-glue-efi-Fix-incorrect-use-of-a-possibly-negati.patch b/SOURCES/0371-util-glue-efi-Fix-incorrect-use-of-a-possibly-negati.patch deleted file mode 100644 index ad3a0d6..0000000 --- a/SOURCES/0371-util-glue-efi-Fix-incorrect-use-of-a-possibly-negati.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Fri, 4 Dec 2020 15:04:28 +0000 -Subject: [PATCH] util/glue-efi: Fix incorrect use of a possibly negative value - -It is possible for the ftell() function to return a negative value, -although it is fairly unlikely here, we should be checking for -a negative value before we assign it to an unsigned value. - -Fixes: CID 73744 - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - util/glue-efi.c | 14 ++++++++++++-- - 1 file changed, 12 insertions(+), 2 deletions(-) - -diff --git a/util/glue-efi.c b/util/glue-efi.c -index 68f53168b58..de0fa6d33d5 100644 ---- a/util/glue-efi.c -+++ b/util/glue-efi.c -@@ -39,13 +39,23 @@ write_fat (FILE *in32, FILE *in64, FILE *out, const char *out_filename, - struct grub_macho_fat_header head; - struct grub_macho_fat_arch arch32, arch64; - grub_uint32_t size32, size64; -+ long size; - char *buf; - - fseek (in32, 0, SEEK_END); -- size32 = ftell (in32); -+ size = ftell (in32); -+ if (size < 0) -+ grub_util_error ("cannot get end of input file '%s': %s", -+ name32, strerror (errno)); -+ size32 = (grub_uint32_t) size; - fseek (in32, 0, SEEK_SET); -+ - fseek (in64, 0, SEEK_END); -- size64 = ftell (in64); -+ size = ftell (in64); -+ if (size < 0) -+ grub_util_error ("cannot get end of input file '%s': %s", -+ name64, strerror (errno)); -+ size64 = (grub_uint64_t) size; - fseek (in64, 0, SEEK_SET); - - head.magic = grub_cpu_to_le32_compile_time (GRUB_MACHO_FAT_EFI_MAGIC); diff --git a/SOURCES/0372-arm64-xen-Fix-too-few-arguments-to-function-grub_cre.patch b/SOURCES/0372-arm64-xen-Fix-too-few-arguments-to-function-grub_cre.patch new file mode 100644 index 0000000..e472215 --- /dev/null +++ b/SOURCES/0372-arm64-xen-Fix-too-few-arguments-to-function-grub_cre.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lee Jones +Date: Tue, 20 Nov 2018 10:45:04 +0000 +Subject: [PATCH] arm64/xen: Fix too few arguments to function + grub_create_loader_cmdline() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Without this fix, building xen_boot.c omits: + +loader/arm64/xen_boot.c: In function ‘xen_boot_binary_load’: +loader/arm64/xen_boot.c:370:7: error: too few arguments to function ‘grub_create_loader_cmdline’ + grub_create_loader_cmdline (argc - 1, argv + 1, binary->cmdline, + ^~~~~~~~~~~~~~~~~~~~~~~~~~ +In file included from loader/arm64/xen_boot.c:36:0: +../include/grub/lib/cmdline.h:29:12: note: declared here + grub_err_t grub_create_loader_cmdline (int argc, char *argv[], char *buf, + +Signed-off-by: Lee Jones +Reviewed-by: Julien Grall +Reviewed-by: Daniel Kiper +--- + grub-core/loader/arm64/xen_boot.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/grub-core/loader/arm64/xen_boot.c b/grub-core/loader/arm64/xen_boot.c +index 318c833de57..1a337866f08 100644 +--- a/grub-core/loader/arm64/xen_boot.c ++++ b/grub-core/loader/arm64/xen_boot.c +@@ -367,7 +367,8 @@ xen_boot_binary_load (struct xen_boot_binary *binary, grub_file_t file, + return; + } + grub_create_loader_cmdline (argc - 1, argv + 1, binary->cmdline, +- binary->cmdline_size); ++ binary->cmdline_size, ++ GRUB_VERIFY_KERNEL_CMDLINE); + grub_dprintf ("xen_loader", + "Xen_boot cmdline @ %p %s, size: %d\n", + binary->cmdline, binary->cmdline, binary->cmdline_size); diff --git a/SOURCES/0372-script-execute-Fix-NULL-dereference-in-grub_script_e.patch b/SOURCES/0372-script-execute-Fix-NULL-dereference-in-grub_script_e.patch deleted file mode 100644 index 88c7951..0000000 --- a/SOURCES/0372-script-execute-Fix-NULL-dereference-in-grub_script_e.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Fri, 3 Apr 2020 23:05:13 +1100 -Subject: [PATCH] script/execute: Fix NULL dereference in - grub_script_execute_cmdline() - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/script/execute.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c -index a1aadb9ee05..2e47c046741 100644 ---- a/grub-core/script/execute.c -+++ b/grub-core/script/execute.c -@@ -978,7 +978,7 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd) - struct grub_script_argv argv = { 0, 0, 0 }; - - /* Lookup the command. */ -- if (grub_script_arglist_to_argv (cmdline->arglist, &argv) || ! argv.args[0]) -+ if (grub_script_arglist_to_argv (cmdline->arglist, &argv) || ! argv.args || ! argv.args[0]) - return grub_errno; - - for (i = 0; i < argv.argc; i++) { diff --git a/SOURCES/0373-commands-ls-Require-device_name-is-not-NULL-before-p.patch b/SOURCES/0373-commands-ls-Require-device_name-is-not-NULL-before-p.patch deleted file mode 100644 index 349ca39..0000000 --- a/SOURCES/0373-commands-ls-Require-device_name-is-not-NULL-before-p.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Mon, 11 Jan 2021 16:57:37 +1100 -Subject: [PATCH] commands/ls: Require device_name is not NULL before printing - -This can be triggered with: - ls -l (0 0*) -and causes a NULL deref in grub_normal_print_device_info(). - -I'm not sure if there's any implication with the IEEE 1275 platform. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/commands/ls.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/grub-core/commands/ls.c b/grub-core/commands/ls.c -index c25161cc4f2..ed646201035 100644 ---- a/grub-core/commands/ls.c -+++ b/grub-core/commands/ls.c -@@ -196,7 +196,7 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human) - goto fail; - } - -- if (! *path) -+ if (! *path && device_name) - { - if (grub_errno == GRUB_ERR_UNKNOWN_FS) - grub_errno = GRUB_ERR_NONE; diff --git a/SOURCES/0373-kern-Add-lockdown-support.patch b/SOURCES/0373-kern-Add-lockdown-support.patch new file mode 100644 index 0000000..b1d5013 --- /dev/null +++ b/SOURCES/0373-kern-Add-lockdown-support.patch @@ -0,0 +1,440 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Fri, 19 Feb 2021 10:33:54 +0100 +Subject: [PATCH] kern: Add lockdown support + +When the GRUB starts on a secure boot platform, some commands can be +used to subvert the protections provided by the verification mechanism and +could lead to booting untrusted system. + +To prevent that situation, allow GRUB to be locked down. That way the code +may check if GRUB has been locked down and further restrict the commands +that are registered or what subset of their functionality could be used. + +The lockdown support adds the following components: + +* The grub_lockdown() function which can be used to lockdown GRUB if, + e.g., UEFI Secure Boot is enabled. + +* The grub_is_lockdown() function which can be used to check if the GRUB + was locked down. + +* A verifier that flags OS kernels, the GRUB modules, Device Trees and ACPI + tables as GRUB_VERIFY_FLAGS_DEFER_AUTH to defer verification to other + verifiers. These files are only successfully verified if another registered + verifier returns success. Otherwise, the whole verification process fails. + + For example, PE/COFF binaries verification can be done by the shim_lock + verifier which validates the signatures using the shim_lock protocol. + However, the verification is not deferred directly to the shim_lock verifier. + The shim_lock verifier is hooked into the verification process instead. + +* A set of grub_{command,extcmd}_lockdown functions that can be used by + code registering command handlers, to only register unsafe commands if + the GRUB has not been locked down. + +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/Makefile.core.def | 1 + + grub-core/commands/extcmd.c | 23 +++++++++++ + grub-core/kern/command.c | 24 ++++++++++++ + grub-core/kern/lockdown.c | 93 +++++++++++++++++++++++++++++++++++++++++++++ + include/grub/command.h | 5 +++ + include/grub/extcmd.h | 7 ++++ + include/grub/lockdown.h | 44 +++++++++++++++++++++ + conf/Makefile.common | 2 + + docs/grub-dev.texi | 27 +++++++++++++ + docs/grub.texi | 8 ++++ + grub-core/Makefile.am | 5 ++- + 11 files changed, 238 insertions(+), 1 deletion(-) + create mode 100644 grub-core/kern/lockdown.c + create mode 100644 include/grub/lockdown.h + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 8914083d13f..02fbecd4b81 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -197,6 +197,7 @@ kernel = { + efi = term/efi/console.c; + efi = kern/acpi.c; + efi = kern/efi/acpi.c; ++ efi = kern/lockdown.c; + efi = lib/envblk.c; + efi = kern/efi/tpm.c; + i386_coreboot = kern/i386/pc/acpi.c; +diff --git a/grub-core/commands/extcmd.c b/grub-core/commands/extcmd.c +index 69574e2b05b..90a5ca24a64 100644 +--- a/grub-core/commands/extcmd.c ++++ b/grub-core/commands/extcmd.c +@@ -19,6 +19,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -110,6 +111,28 @@ grub_register_extcmd (const char *name, grub_extcmd_func_t func, + summary, description, parser, 1); + } + ++static grub_err_t ++grub_extcmd_lockdown (grub_extcmd_context_t ctxt __attribute__ ((unused)), ++ int argc __attribute__ ((unused)), ++ char **argv __attribute__ ((unused))) ++{ ++ return grub_error (GRUB_ERR_ACCESS_DENIED, ++ N_("%s: the command is not allowed when lockdown is enforced"), ++ ctxt->extcmd->cmd->name); ++} ++ ++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) ++{ ++ if (grub_is_lockdown () == GRUB_LOCKDOWN_ENABLED) ++ func = grub_extcmd_lockdown; ++ ++ return grub_register_extcmd (name, func, flags, summary, description, parser); ++} ++ + void + grub_unregister_extcmd (grub_extcmd_t ext) + { +diff --git a/grub-core/kern/command.c b/grub-core/kern/command.c +index acd72187992..4aabcd4b5f9 100644 +--- a/grub-core/kern/command.c ++++ b/grub-core/kern/command.c +@@ -17,6 +17,7 @@ + * along with GRUB. If not, see . + */ + ++#include + #include + #include + +@@ -77,6 +78,29 @@ grub_register_command_prio (const char *name, + return cmd; + } + ++static grub_err_t ++grub_cmd_lockdown (grub_command_t cmd __attribute__ ((unused)), ++ int argc __attribute__ ((unused)), ++ char **argv __attribute__ ((unused))) ++ ++{ ++ return grub_error (GRUB_ERR_ACCESS_DENIED, ++ N_("%s: the command is not allowed when lockdown is enforced"), ++ cmd->name); ++} ++ ++grub_command_t ++grub_register_command_lockdown (const char *name, ++ grub_command_func_t func, ++ const char *summary, ++ const char *description) ++{ ++ if (grub_is_lockdown () == GRUB_LOCKDOWN_ENABLED) ++ func = grub_cmd_lockdown; ++ ++ return grub_register_command_prio (name, func, summary, description, 0); ++} ++ + void + grub_unregister_command (grub_command_t cmd) + { +diff --git a/grub-core/kern/lockdown.c b/grub-core/kern/lockdown.c +new file mode 100644 +index 00000000000..f87ddaeb1ee +--- /dev/null ++++ b/grub-core/kern/lockdown.c +@@ -0,0 +1,93 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 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 ++ ++/* There is no verifier framework in grub 2.02 */ ++#if 0 ++#include ++#endif ++ ++static int lockdown = GRUB_LOCKDOWN_DISABLED; ++ ++/* There is no verifier framework in grub 2.02 */ ++#if 0 ++static grub_err_t ++lockdown_verifier_init (grub_file_t io __attribute__ ((unused)), ++ enum grub_file_type type, ++ void **context __attribute__ ((unused)), ++ enum grub_verify_flags *flags) ++{ ++ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; ++ ++ switch (type & GRUB_FILE_TYPE_MASK) ++ { ++ case GRUB_FILE_TYPE_GRUB_MODULE: ++ case GRUB_FILE_TYPE_LINUX_KERNEL: ++ case GRUB_FILE_TYPE_MULTIBOOT_KERNEL: ++ case GRUB_FILE_TYPE_XEN_HYPERVISOR: ++ case GRUB_FILE_TYPE_BSD_KERNEL: ++ case GRUB_FILE_TYPE_XNU_KERNEL: ++ case GRUB_FILE_TYPE_PLAN9_KERNEL: ++ case GRUB_FILE_TYPE_NTLDR: ++ case GRUB_FILE_TYPE_TRUECRYPT: ++ case GRUB_FILE_TYPE_FREEDOS: ++ case GRUB_FILE_TYPE_PXECHAINLOADER: ++ case GRUB_FILE_TYPE_PCCHAINLOADER: ++ case GRUB_FILE_TYPE_COREBOOT_CHAINLOADER: ++ case GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE: ++ case GRUB_FILE_TYPE_ACPI_TABLE: ++ case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE: ++ *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH; ++ ++ /* Fall through. */ ++ ++ default: ++ return GRUB_ERR_NONE; ++ } ++} ++ ++struct grub_file_verifier lockdown_verifier = ++ { ++ .name = "lockdown_verifier", ++ .init = lockdown_verifier_init, ++ }; ++#endif ++ ++void ++grub_lockdown (void) ++{ ++ lockdown = GRUB_LOCKDOWN_ENABLED; ++ ++ /* ++ * XXX: The lockdown verifier doesn't make sense until ++ * GRUB has moved to the shim_lock verifier. ++ */ ++#if 0 ++ grub_verifier_register (&lockdown_verifier); ++#endif ++} ++ ++int ++grub_is_lockdown (void) ++{ ++ return lockdown; ++} +diff --git a/include/grub/command.h b/include/grub/command.h +index eee4e847ee4..2a6f7f84697 100644 +--- a/include/grub/command.h ++++ b/include/grub/command.h +@@ -86,6 +86,11 @@ EXPORT_FUNC(grub_register_command_prio) (const char *name, + const char *summary, + const char *description, + int prio); ++grub_command_t ++EXPORT_FUNC(grub_register_command_lockdown) (const char *name, ++ grub_command_func_t func, ++ const char *summary, ++ const char *description); + 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 19fe592669e..fe9248b8bb6 100644 +--- a/include/grub/extcmd.h ++++ b/include/grub/extcmd.h +@@ -62,6 +62,13 @@ grub_extcmd_t EXPORT_FUNC(grub_register_extcmd) (const char *name, + const char *description, + const struct grub_arg_option *parser); + ++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); ++ + grub_extcmd_t EXPORT_FUNC(grub_register_extcmd_prio) (const char *name, + grub_extcmd_func_t func, + grub_command_flags_t flags, +diff --git a/include/grub/lockdown.h b/include/grub/lockdown.h +new file mode 100644 +index 00000000000..40531fa823b +--- /dev/null ++++ b/include/grub/lockdown.h +@@ -0,0 +1,44 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 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_LOCKDOWN_H ++#define GRUB_LOCKDOWN_H 1 ++ ++#include ++ ++#define GRUB_LOCKDOWN_DISABLED 0 ++#define GRUB_LOCKDOWN_ENABLED 1 ++ ++#ifdef GRUB_MACHINE_EFI ++extern void ++EXPORT_FUNC (grub_lockdown) (void); ++extern int ++EXPORT_FUNC (grub_is_lockdown) (void); ++#else ++static inline void ++grub_lockdown (void) ++{ ++} ++ ++static inline int ++grub_is_lockdown (void) ++{ ++ return GRUB_LOCKDOWN_DISABLED; ++} ++#endif ++#endif /* ! GRUB_LOCKDOWN_H */ +diff --git a/conf/Makefile.common b/conf/Makefile.common +index b93879804c0..521cdda1f5a 100644 +--- a/conf/Makefile.common ++++ b/conf/Makefile.common +@@ -85,7 +85,9 @@ CPPFLAGS_PARTTOOL_LIST = -Dgrub_parttool_register=PARTTOOL_LIST_MARKER + CPPFLAGS_TERMINAL_LIST = '-Dgrub_term_register_input(...)=INPUT_TERMINAL_LIST_MARKER(__VA_ARGS__)' + CPPFLAGS_TERMINAL_LIST += '-Dgrub_term_register_output(...)=OUTPUT_TERMINAL_LIST_MARKER(__VA_ARGS__)' + CPPFLAGS_COMMAND_LIST = '-Dgrub_register_command(...)=COMMAND_LIST_MARKER(__VA_ARGS__)' ++CPPFLAGS_COMMAND_LIST += '-Dgrub_register_command_lockdown(...)=COMMAND_LOCKDOWN_LIST_MARKER(__VA_ARGS__)' + CPPFLAGS_COMMAND_LIST += '-Dgrub_register_extcmd(...)=EXTCOMMAND_LIST_MARKER(__VA_ARGS__)' ++CPPFLAGS_COMMAND_LIST += '-Dgrub_register_extcmd_lockdown(...)=EXTCOMMAND_LOCKDOWN_LIST_MARKER(__VA_ARGS__)' + CPPFLAGS_COMMAND_LIST += '-Dgrub_register_command_p1(...)=P1COMMAND_LIST_MARKER(__VA_ARGS__)' + CPPFLAGS_FDT_LIST := '-Dgrub_fdtbus_register(...)=FDT_DRIVER_LIST_MARKER(__VA_ARGS__)' + CPPFLAGS_MARKER = $(CPPFLAGS_FS_LIST) $(CPPFLAGS_VIDEO_LIST) \ +diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi +index 3ce827ab726..421dd410e50 100644 +--- a/docs/grub-dev.texi ++++ b/docs/grub-dev.texi +@@ -84,6 +84,7 @@ This edition documents version @value{VERSION}. + * Video Subsystem:: + * PFF2 Font File Format:: + * Graphical Menu Software Design:: ++* Lockdown framework:: + * Copying This Manual:: Copying This Manual + * Index:: + @end menu +@@ -1949,6 +1950,32 @@ the graphics mode that was in use before @code{grub_video_setup()} was called + might fix some of the problems. + + ++@node Lockdown framework ++@chapter Lockdown framework ++ ++The GRUB can be locked down, which is a restricted mode where some operations ++are not allowed. For instance, some commands cannot be used when the GRUB is ++locked down. ++ ++The function ++@code{grub_lockdown()} is used to lockdown GRUB and the function ++@code{grub_is_lockdown()} function can be used to check whether lockdown is ++enabled or not. When enabled, the function returns @samp{GRUB_LOCKDOWN_ENABLED} ++and @samp{GRUB_LOCKDOWN_DISABLED} when is not enabled. ++ ++The following functions can be used to register the commands that can only be ++used when lockdown is disabled: ++ ++@itemize ++ ++@item @code{grub_cmd_lockdown()} registers command which should not run when the ++GRUB is in lockdown mode. ++ ++@item @code{grub_cmd_lockdown()} registers extended command which should not run ++when the GRUB is in lockdown mode. ++ ++@end itemize ++ + @node Copying This Manual + @appendix Copying This Manual + +diff --git a/docs/grub.texi b/docs/grub.texi +index 97f0f47e082..f957535dbea 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -5687,6 +5687,7 @@ environment variables and commands are listed in the same order. + * Using GPG-style digital signatures:: Booting digitally signed code + * Using appended signatures:: An alternative approach to booting digitally signed code + * Signing GRUB itself:: Ensuring the integrity of the GRUB core image ++* Lockdown:: Lockdown when booting on a secure setup + @end menu + + @node Authentication and authorisation +@@ -5977,6 +5978,13 @@ As with UEFI secure boot, it is necessary to build in the required modules, + or sign them separately. + + ++@node Lockdown ++@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. ++ + @node Platform limitations + @chapter Platform limitations + +diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am +index 4062652506d..a6f1b0dcd06 100644 +--- a/grub-core/Makefile.am ++++ b/grub-core/Makefile.am +@@ -82,6 +82,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fs.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i18n.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/kernel.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/list.h ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lockdown.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/misc.h + if COND_emu + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/compiler-rt-emu.h +@@ -350,8 +351,10 @@ command.lst: $(MARKER_FILES) + b=`basename $$pp .marker`; \ + sed -n \ + -e "/EXTCOMMAND_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/*\1: $$b/;p;}" \ ++ -e "/EXTCOMMAND_LOCKDOWN_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/*\1: $$b/;p;}" \ + -e "/P1COMMAND_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/*\1: $$b/;p;}" \ +- -e "/COMMAND_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/\1: $$b/;p;}" $$pp; \ ++ -e "/COMMAND_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/\1: $$b/;p;}" \ ++ -e "/COMMAND_LOCKDOWN_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/\1: $$b/;p;}" $$pp; \ + done) | sort -u > $@ + platform_DATA += command.lst + CLEANFILES += command.lst diff --git a/SOURCES/0374-kern-lockdown-Set-a-variable-if-the-GRUB-is-locked-d.patch b/SOURCES/0374-kern-lockdown-Set-a-variable-if-the-GRUB-is-locked-d.patch new file mode 100644 index 0000000..cccd213 --- /dev/null +++ b/SOURCES/0374-kern-lockdown-Set-a-variable-if-the-GRUB-is-locked-d.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Tue, 2 Feb 2021 19:59:48 +0100 +Subject: [PATCH] kern/lockdown: Set a variable if the GRUB is locked down + +It may be useful for scripts to determine whether the GRUB is locked +down or not. Add the lockdown variable which is set to "y" when the GRUB +is locked down. + +Suggested-by: Dimitri John Ledkov +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/kern/lockdown.c | 4 ++++ + docs/grub.texi | 3 +++ + 2 files changed, 7 insertions(+) + +diff --git a/grub-core/kern/lockdown.c b/grub-core/kern/lockdown.c +index f87ddaeb1ee..30cba7f5ea2 100644 +--- a/grub-core/kern/lockdown.c ++++ b/grub-core/kern/lockdown.c +@@ -18,6 +18,7 @@ + */ + + #include ++#include + #include + #include + +@@ -84,6 +85,9 @@ grub_lockdown (void) + #if 0 + grub_verifier_register (&lockdown_verifier); + #endif ++ ++ grub_env_set ("lockdown", "y"); ++ grub_env_export ("lockdown"); + } + + int +diff --git a/docs/grub.texi b/docs/grub.texi +index f957535dbea..755de88d7d8 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -5985,6 +5985,9 @@ The GRUB can be locked down when booted on a secure boot environment, for exampl + if the UEFI 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. ++ + @node Platform limitations + @chapter Platform limitations + diff --git a/SOURCES/0374-script-execute-Avoid-crash-when-using-outside-a-func.patch b/SOURCES/0374-script-execute-Avoid-crash-when-using-outside-a-func.patch deleted file mode 100644 index 08fa625..0000000 --- a/SOURCES/0374-script-execute-Avoid-crash-when-using-outside-a-func.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Mon, 11 Jan 2021 17:30:42 +1100 -Subject: [PATCH] script/execute: Avoid crash when using "$#" outside a - function scope - -"$#" represents the number of arguments to a function. It is only -defined in a function scope, where "scope" is non-NULL. Currently, -if we attempt to evaluate "$#" outside a function scope, "scope" will -be NULL and we will crash with a NULL pointer dereference. - -Do not attempt to count arguments for "$#" if "scope" is NULL. This -will result in "$#" being interpreted as an empty string if evaluated -outside a function scope. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/script/execute.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c -index 2e47c046741..17f4dcab2c6 100644 ---- a/grub-core/script/execute.c -+++ b/grub-core/script/execute.c -@@ -519,7 +519,7 @@ gettext_putvar (const char *str, grub_size_t len, - return 0; - - /* Enough for any number. */ -- if (len == 1 && str[0] == '#') -+ if (len == 1 && str[0] == '#' && scope != NULL) - { - grub_snprintf (*ptr, 30, "%u", scope->argv.argc); - *ptr += grub_strlen (*ptr); diff --git a/SOURCES/0375-efi-Lockdown-the-GRUB-when-the-UEFI-Secure-Boot-is-e.patch b/SOURCES/0375-efi-Lockdown-the-GRUB-when-the-UEFI-Secure-Boot-is-e.patch new file mode 100644 index 0000000..d1fb42c --- /dev/null +++ b/SOURCES/0375-efi-Lockdown-the-GRUB-when-the-UEFI-Secure-Boot-is-e.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Mon, 28 Sep 2020 20:08:29 +0200 +Subject: [PATCH] efi: Lockdown the GRUB when the UEFI Secure Boot is enabled + +If the UEFI Secure Boot is enabled then the GRUB must be locked down +to prevent executing code that can potentially be used to subvert its +verification mechanisms. + +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/kern/efi/init.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c +index 79243b364a1..97bf36906a4 100644 +--- a/grub-core/kern/efi/init.c ++++ b/grub-core/kern/efi/init.c +@@ -20,6 +20,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -93,6 +95,23 @@ grub_efi_init (void) + /* Initialize the memory management system. */ + grub_efi_mm_init (); + ++ /* ++ * Lockdown the GRUB and register the shim_lock verifier ++ * if the UEFI Secure Boot is enabled. ++ */ ++ if (grub_efi_secure_boot ()) ++ { ++ grub_lockdown (); ++ ++ /* ++ * TODO: Move GRUB to using the shim_lock verifier and ++ * enable the lockdown verifier. ++ */ ++#if 0 ++ grub_shim_lock_verifier_setup (); ++#endif ++ } ++ + efi_call_4 (grub_efi_system_table->boot_services->set_watchdog_timer, + 0, 0, 0, NULL); + diff --git a/SOURCES/0375-lib-arg-Block-repeated-short-options-that-require-an.patch b/SOURCES/0375-lib-arg-Block-repeated-short-options-that-require-an.patch deleted file mode 100644 index 63cf2af..0000000 --- a/SOURCES/0375-lib-arg-Block-repeated-short-options-that-require-an.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Fri, 22 Jan 2021 16:07:29 +1100 -Subject: [PATCH] lib/arg: Block repeated short options that require an - argument - -Fuzzing found the following crash: - - search -hhhhhhhhhhhhhf - -We didn't allocate enough option space for 13 hints because the -allocation code counts the number of discrete arguments (i.e. argc). -However, the shortopt parsing code will happily keep processing -a combination of short options without checking if those short -options require an argument. This means you can easily end writing -past the allocated option space. - -This fixes a OOB write which can cause heap corruption. - -Fixes: CVE-2021-20225 - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/lib/arg.c | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - -diff --git a/grub-core/lib/arg.c b/grub-core/lib/arg.c -index 3288609a5e1..537c5e94b83 100644 ---- a/grub-core/lib/arg.c -+++ b/grub-core/lib/arg.c -@@ -299,6 +299,19 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv, - it can have an argument value. */ - if (*curshort) - { -+ /* -+ * Only permit further short opts if this one doesn't -+ * require a value. -+ */ -+ if (opt->type != ARG_TYPE_NONE && -+ !(opt->flags & GRUB_ARG_OPTION_OPTIONAL)) -+ { -+ grub_error (GRUB_ERR_BAD_ARGUMENT, -+ N_("missing mandatory option for `%s'"), -+ opt->longarg); -+ goto fail; -+ } -+ - if (parse_option (cmd, opt, 0, usr) || grub_errno) - goto fail; - } diff --git a/SOURCES/0376-efi-Use-grub_is_lockdown-instead-of-hardcoding-a-dis.patch b/SOURCES/0376-efi-Use-grub_is_lockdown-instead-of-hardcoding-a-dis.patch new file mode 100644 index 0000000..a902271 --- /dev/null +++ b/SOURCES/0376-efi-Use-grub_is_lockdown-instead-of-hardcoding-a-dis.patch @@ -0,0 +1,137 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Mon, 28 Sep 2020 20:08:33 +0200 +Subject: [PATCH] efi: Use grub_is_lockdown() instead of hardcoding a disabled + modules list + +Now the GRUB can check if it has been locked down and this can be used to +prevent executing commands that can be utilized to circumvent the UEFI +Secure Boot mechanisms. So, instead of hardcoding a list of modules that +have to be disabled, prevent the usage of commands that can be dangerous. + +This not only allows the commands to be disabled on other platforms, but +also properly separate the concerns. Since the shim_lock verifier logic +should be only about preventing to run untrusted binaries and not about +defining these kind of policies. + +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/commands/iorw.c | 26 ++++++++++---------------- + grub-core/commands/memrw.c | 26 ++++++++++---------------- + 2 files changed, 20 insertions(+), 32 deletions(-) + +diff --git a/grub-core/commands/iorw.c b/grub-core/commands/iorw.c +index 41a7f3f0466..584baec8f91 100644 +--- a/grub-core/commands/iorw.c ++++ b/grub-core/commands/iorw.c +@@ -23,7 +23,7 @@ + #include + #include + #include +-#include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -119,9 +119,6 @@ grub_cmd_write (grub_command_t cmd, int argc, char **argv) + + GRUB_MOD_INIT(memrw) + { +- if (grub_efi_secure_boot()) +- return; +- + cmd_read_byte = + grub_register_extcmd ("inb", grub_cmd_read, 0, + N_("PORT"), N_("Read 8-bit value from PORT."), +@@ -135,24 +132,21 @@ GRUB_MOD_INIT(memrw) + N_("PORT"), N_("Read 32-bit value from PORT."), + options); + cmd_write_byte = +- grub_register_command ("outb", grub_cmd_write, +- N_("PORT VALUE [MASK]"), +- N_("Write 8-bit VALUE to PORT.")); ++ grub_register_command_lockdown ("outb", grub_cmd_write, ++ N_("PORT VALUE [MASK]"), ++ N_("Write 8-bit VALUE to PORT.")); + cmd_write_word = +- grub_register_command ("outw", grub_cmd_write, +- N_("PORT VALUE [MASK]"), +- N_("Write 16-bit VALUE to PORT.")); ++ grub_register_command_lockdown ("outw", grub_cmd_write, ++ N_("PORT VALUE [MASK]"), ++ N_("Write 16-bit VALUE to PORT.")); + cmd_write_dword = +- grub_register_command ("outl", grub_cmd_write, +- N_("ADDR VALUE [MASK]"), +- N_("Write 32-bit VALUE to PORT.")); ++ grub_register_command_lockdown ("outl", grub_cmd_write, ++ N_("ADDR VALUE [MASK]"), ++ N_("Write 32-bit VALUE to PORT.")); + } + + GRUB_MOD_FINI(memrw) + { +- if (grub_efi_secure_boot()) +- return; +- + grub_unregister_extcmd (cmd_read_byte); + grub_unregister_extcmd (cmd_read_word); + grub_unregister_extcmd (cmd_read_dword); +diff --git a/grub-core/commands/memrw.c b/grub-core/commands/memrw.c +index 088cbe9e2bc..d401a6db0ef 100644 +--- a/grub-core/commands/memrw.c ++++ b/grub-core/commands/memrw.c +@@ -22,7 +22,7 @@ + #include + #include + #include +-#include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -121,9 +121,6 @@ grub_cmd_write (grub_command_t cmd, int argc, char **argv) + + GRUB_MOD_INIT(memrw) + { +- if (grub_efi_secure_boot()) +- return; +- + cmd_read_byte = + grub_register_extcmd ("read_byte", grub_cmd_read, 0, + N_("ADDR"), N_("Read 8-bit value from ADDR."), +@@ -137,24 +134,21 @@ GRUB_MOD_INIT(memrw) + N_("ADDR"), N_("Read 32-bit value from ADDR."), + options); + cmd_write_byte = +- grub_register_command ("write_byte", grub_cmd_write, +- N_("ADDR VALUE [MASK]"), +- N_("Write 8-bit VALUE to ADDR.")); ++ grub_register_command_lockdown ("write_byte", grub_cmd_write, ++ N_("ADDR VALUE [MASK]"), ++ N_("Write 8-bit VALUE to ADDR.")); + cmd_write_word = +- grub_register_command ("write_word", grub_cmd_write, +- N_("ADDR VALUE [MASK]"), +- N_("Write 16-bit VALUE to ADDR.")); ++ grub_register_command_lockdown ("write_word", grub_cmd_write, ++ N_("ADDR VALUE [MASK]"), ++ N_("Write 16-bit VALUE to ADDR.")); + cmd_write_dword = +- grub_register_command ("write_dword", grub_cmd_write, +- N_("ADDR VALUE [MASK]"), +- N_("Write 32-bit VALUE to ADDR.")); ++ grub_register_command_lockdown ("write_dword", grub_cmd_write, ++ N_("ADDR VALUE [MASK]"), ++ N_("Write 32-bit VALUE to ADDR.")); + } + + GRUB_MOD_FINI(memrw) + { +- if (grub_efi_secure_boot()) +- return; +- + grub_unregister_extcmd (cmd_read_byte); + grub_unregister_extcmd (cmd_read_word); + grub_unregister_extcmd (cmd_read_dword); diff --git a/SOURCES/0376-script-execute-Don-t-crash-on-a-for-loop-with-no-ite.patch b/SOURCES/0376-script-execute-Don-t-crash-on-a-for-loop-with-no-ite.patch deleted file mode 100644 index 4e61d40..0000000 --- a/SOURCES/0376-script-execute-Don-t-crash-on-a-for-loop-with-no-ite.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Fri, 22 Jan 2021 16:18:26 +1100 -Subject: [PATCH] script/execute: Don't crash on a "for" loop with no items - -The following crashes the parser: - - for x in; do - 0 - done - -This is because grub_script_arglist_to_argv() doesn't consider the -possibility that arglist is NULL. Catch that explicitly. - -This avoids a NULL pointer dereference. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/script/execute.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c -index 17f4dcab2c6..266d99ed337 100644 ---- a/grub-core/script/execute.c -+++ b/grub-core/script/execute.c -@@ -658,6 +658,9 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, - struct grub_script_arg *arg = 0; - struct grub_script_argv result = { 0, 0, 0 }; - -+ if (arglist == NULL) -+ return 1; -+ - for (; arglist && arglist->arg; arglist = arglist->next) - { - if (grub_script_argv_next (&result)) diff --git a/SOURCES/0377-acpi-Don-t-register-the-acpi-command-when-locked-dow.patch b/SOURCES/0377-acpi-Don-t-register-the-acpi-command-when-locked-dow.patch new file mode 100644 index 0000000..603796c --- /dev/null +++ b/SOURCES/0377-acpi-Don-t-register-the-acpi-command-when-locked-dow.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Mon, 28 Sep 2020 20:08:41 +0200 +Subject: [PATCH] acpi: Don't register the acpi command when locked down +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The command is not allowed when lockdown is enforced. Otherwise an +attacker can instruct the GRUB to load an SSDT table to overwrite +the kernel lockdown configuration and later load and execute +unsigned code. + +Fixes: CVE-2020-14372 + +Reported-by: Máté Kukri +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/commands/acpi.c | 15 ++++++++------- + docs/grub.texi | 5 +++++ + 2 files changed, 13 insertions(+), 7 deletions(-) + +diff --git a/grub-core/commands/acpi.c b/grub-core/commands/acpi.c +index 5a1499aa0e3..1215f2a62ef 100644 +--- a/grub-core/commands/acpi.c ++++ b/grub-core/commands/acpi.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + #ifdef GRUB_MACHINE_EFI + #include +@@ -775,13 +776,13 @@ static grub_extcmd_t cmd; + + GRUB_MOD_INIT(acpi) + { +- cmd = grub_register_extcmd ("acpi", grub_cmd_acpi, 0, +- N_("[-1|-2] [--exclude=TABLE1,TABLE2|" +- "--load-only=TABLE1,TABLE2] FILE1" +- " [FILE2] [...]"), +- N_("Load host ACPI tables and tables " +- "specified by arguments."), +- options); ++ cmd = grub_register_extcmd_lockdown ("acpi", grub_cmd_acpi, 0, ++ N_("[-1|-2] [--exclude=TABLE1,TABLE2|" ++ "--load-only=TABLE1,TABLE2] FILE1" ++ " [FILE2] [...]"), ++ N_("Load host ACPI tables and tables " ++ "specified by arguments."), ++ options); + } + + GRUB_MOD_FINI(acpi) +diff --git a/docs/grub.texi b/docs/grub.texi +index 755de88d7d8..01acf672b80 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -4038,6 +4038,11 @@ Normally, this command will replace the Root System Description Pointer + (RSDP) in the Extended BIOS Data Area to point to the new tables. If the + @option{--no-ebda} option is used, the new tables will be known only to + GRUB, but may be used by GRUB's EFI emulation. ++ ++Note: The command is not allowed when lockdown is enforced (@pxref{Lockdown}). ++ Otherwise an attacker can instruct the GRUB to load an SSDT table to ++ overwrite the kernel lockdown configuration and later load and execute ++ unsigned code. + @end deffn + + diff --git a/SOURCES/0377-commands-menuentry-Fix-quoting-in-setparams_prefix.patch b/SOURCES/0377-commands-menuentry-Fix-quoting-in-setparams_prefix.patch deleted file mode 100644 index 523dfb1..0000000 --- a/SOURCES/0377-commands-menuentry-Fix-quoting-in-setparams_prefix.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Fri, 22 Jan 2021 17:10:48 +1100 -Subject: [PATCH] commands/menuentry: Fix quoting in setparams_prefix() - -Commit 9acdcbf32542 (use single quotes in menuentry setparams command) -says that expressing a quoted single quote will require 3 characters. It -actually requires (and always did require!) 4 characters: - - str: a'b => a'\''b - len: 3 => 6 (2 for the letters + 4 for the quote) - -This leads to not allocating enough memory and thus out of bounds writes -that have been observed to cause heap corruption. - -Allocate 4 bytes for each single quote. - -Commit 22e7dbb2bb81 (Fix quoting in legacy parser.) does the same -quoting, but it adds 3 as extra overhead on top of the single byte that -the quote already needs. So it's correct. - -Fixes: CVE-2021-20233 -Fixes: 9acdcbf32542 (use single quotes in menuentry setparams command) - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/commands/menuentry.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c -index 4b5fcf2ce9a..7a533b9741b 100644 ---- a/grub-core/commands/menuentry.c -+++ b/grub-core/commands/menuentry.c -@@ -239,7 +239,7 @@ setparams_prefix (int argc, char **args) - len += 3; /* 3 = 1 space + 2 quotes */ - p = args[i]; - while (*p) -- len += (*p++ == '\'' ? 3 : 1); -+ len += (*p++ == '\'' ? 4 : 1); - } - - result = grub_malloc (len + 2); diff --git a/SOURCES/0378-kern-misc-Always-set-end-in-grub_strtoull.patch b/SOURCES/0378-kern-misc-Always-set-end-in-grub_strtoull.patch deleted file mode 100644 index b3e77ab..0000000 --- a/SOURCES/0378-kern-misc-Always-set-end-in-grub_strtoull.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Wed, 13 Jan 2021 22:19:01 +1100 -Subject: [PATCH] kern/misc: Always set *end in grub_strtoull() - -Currently, if there is an error in grub_strtoull(), *end is not set. -This differs from the usual behavior of strtoull(), and also means that -some callers may use an uninitialized value for *end. - -Set *end unconditionally. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/kern/misc.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c -index c034f49f97c..62b4068e810 100644 ---- a/grub-core/kern/misc.c -+++ b/grub-core/kern/misc.c -@@ -452,6 +452,10 @@ grub_strtoull (const char *str, const char ** const end, int base) - { - grub_error (GRUB_ERR_OUT_OF_RANGE, - N_("overflow is detected")); -+ -+ if (end) -+ *end = (char *) str; -+ - return ~0ULL; - } - -@@ -463,6 +467,10 @@ grub_strtoull (const char *str, const char ** const end, int base) - { - grub_error (GRUB_ERR_BAD_NUMBER, - N_("unrecognized number")); -+ -+ if (end) -+ *end = (char *) str; -+ - return 0; - } - diff --git a/SOURCES/0378-mmap-Don-t-register-cutmem-and-badram-commands-when-.patch b/SOURCES/0378-mmap-Don-t-register-cutmem-and-badram-commands-when-.patch new file mode 100644 index 0000000..2781cd9 --- /dev/null +++ b/SOURCES/0378-mmap-Don-t-register-cutmem-and-badram-commands-when-.patch @@ -0,0 +1,66 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Wed, 14 Oct 2020 16:33:42 +0200 +Subject: [PATCH] mmap: Don't register cutmem and badram commands when lockdown + is enforced + +The cutmem and badram commands can be used to remove EFI memory regions +and potentially disable the UEFI Secure Boot. Prevent the commands to be +registered if the GRUB is locked down. + +Fixes: CVE-2020-27779 + +Reported-by: Teddy Reed +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/mmap/mmap.c | 13 +++++++------ + docs/grub.texi | 4 ++++ + 2 files changed, 11 insertions(+), 6 deletions(-) + +diff --git a/grub-core/mmap/mmap.c b/grub-core/mmap/mmap.c +index 57b4e9a72a9..7ebf32e1e5e 100644 +--- a/grub-core/mmap/mmap.c ++++ b/grub-core/mmap/mmap.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -534,12 +535,12 @@ static grub_command_t cmd, cmd_cut; + + GRUB_MOD_INIT(mmap) + { +- cmd = grub_register_command ("badram", grub_cmd_badram, +- N_("ADDR1,MASK1[,ADDR2,MASK2[,...]]"), +- N_("Declare memory regions as faulty (badram).")); +- cmd_cut = grub_register_command ("cutmem", grub_cmd_cutmem, +- N_("FROM[K|M|G] TO[K|M|G]"), +- N_("Remove any memory regions in specified range.")); ++ cmd = grub_register_command_lockdown ("badram", grub_cmd_badram, ++ N_("ADDR1,MASK1[,ADDR2,MASK2[,...]]"), ++ N_("Declare memory regions as faulty (badram).")); ++ cmd_cut = grub_register_command_lockdown ("cutmem", grub_cmd_cutmem, ++ N_("FROM[K|M|G] TO[K|M|G]"), ++ N_("Remove any memory regions in specified range.")); + + } + +diff --git a/docs/grub.texi b/docs/grub.texi +index 01acf672b80..f1675b6140c 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -4103,6 +4103,10 @@ this page is to be filtered. This syntax makes it easy to represent patterns + that are often result of memory damage, due to physical distribution of memory + cells. + ++Note: The command is not allowed when lockdown is enforced (@pxref{Lockdown}). ++ This prevents removing EFI memory regions to potentially subvert the ++ security mechanisms provided by the UEFI secure boot. ++ + @node blocklist + @subsection blocklist + diff --git a/SOURCES/0379-commands-Restrict-commands-that-can-load-BIOS-or-DT-.patch b/SOURCES/0379-commands-Restrict-commands-that-can-load-BIOS-or-DT-.patch new file mode 100644 index 0000000..ae197cb --- /dev/null +++ b/SOURCES/0379-commands-Restrict-commands-that-can-load-BIOS-or-DT-.patch @@ -0,0 +1,108 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Wed, 24 Feb 2021 09:00:05 +0100 +Subject: [PATCH] commands: Restrict commands that can load BIOS or DT blobs + when locked down + +There are some more commands that should be restricted when the GRUB is +locked down. Following is the list of commands and reasons to restrict: + + * fakebios: creates BIOS-like structures for backward compatibility with + existing OSes. This should not be allowed when locked down. + + * loadbios: reads a BIOS dump from storage and loads it. This action + should not be allowed when locked down. + + * devicetree: loads a Device Tree blob and passes it to the OS. It replaces + any Device Tree provided by the firmware. This also should + not be allowed when locked down. + +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/commands/efi/loadbios.c | 14 +++++++------- + grub-core/loader/arm/linux.c | 6 +++--- + grub-core/loader/efi/fdt.c | 4 ++-- + docs/grub.texi | 6 ++++-- + 4 files changed, 16 insertions(+), 14 deletions(-) + +diff --git a/grub-core/commands/efi/loadbios.c b/grub-core/commands/efi/loadbios.c +index d41d521a4ae..5c7725f8bd8 100644 +--- a/grub-core/commands/efi/loadbios.c ++++ b/grub-core/commands/efi/loadbios.c +@@ -205,14 +205,14 @@ static grub_command_t cmd_fakebios, cmd_loadbios; + + GRUB_MOD_INIT(loadbios) + { +- cmd_fakebios = grub_register_command ("fakebios", grub_cmd_fakebios, +- 0, N_("Create BIOS-like structures for" +- " backward compatibility with" +- " existing OS.")); ++ cmd_fakebios = grub_register_command_lockdown ("fakebios", grub_cmd_fakebios, ++ 0, N_("Create BIOS-like structures for" ++ " backward compatibility with" ++ " existing OS.")); + +- cmd_loadbios = grub_register_command ("loadbios", grub_cmd_loadbios, +- N_("BIOS_DUMP [INT10_DUMP]"), +- N_("Load BIOS dump.")); ++ cmd_loadbios = grub_register_command_lockdown ("loadbios", grub_cmd_loadbios, ++ N_("BIOS_DUMP [INT10_DUMP]"), ++ N_("Load BIOS dump.")); + } + + GRUB_MOD_FINI(loadbios) +diff --git a/grub-core/loader/arm/linux.c b/grub-core/loader/arm/linux.c +index 1e944a2b671..653f2e07692 100644 +--- a/grub-core/loader/arm/linux.c ++++ b/grub-core/loader/arm/linux.c +@@ -493,9 +493,9 @@ GRUB_MOD_INIT (linux) + 0, N_("Load Linux.")); + cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, + 0, N_("Load initrd.")); +- cmd_devicetree = grub_register_command ("devicetree", grub_cmd_devicetree, +- /* TRANSLATORS: DTB stands for device tree blob. */ +- 0, N_("Load DTB file.")); ++ cmd_devicetree = grub_register_command_lockdown ("devicetree", grub_cmd_devicetree, ++ /* TRANSLATORS: DTB stands for device tree blob. */ ++ 0, N_("Load DTB file.")); + my_mod = mod; + current_fdt = (const void *) grub_arm_firmware_get_boot_data (); + machine_type = grub_arm_firmware_get_machine_type (); +diff --git a/grub-core/loader/efi/fdt.c b/grub-core/loader/efi/fdt.c +index e3ee3ad79d6..64c560f5610 100644 +--- a/grub-core/loader/efi/fdt.c ++++ b/grub-core/loader/efi/fdt.c +@@ -167,8 +167,8 @@ static grub_command_t cmd_devicetree; + GRUB_MOD_INIT (fdt) + { + cmd_devicetree = +- grub_register_command ("devicetree", grub_cmd_devicetree, 0, +- N_("Load DTB file.")); ++ grub_register_command_lockdown ("devicetree", grub_cmd_devicetree, 0, ++ N_("Load DTB file.")); + } + + GRUB_MOD_FINI (fdt) +diff --git a/docs/grub.texi b/docs/grub.texi +index f1675b6140c..c55452307dc 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -4281,13 +4281,15 @@ hour, minute, and second unchanged. + + + @node devicetree +-@subsection linux ++@subsection devicetree + + @deffn Command devicetree file + Load a device tree blob (.dtb) from a filesystem, for later use by a Linux + kernel. Does not perform merging with any device tree supplied by firmware, + but rather replaces it completely. +-@ref{GNU/Linux}. ++ ++Note: The command is not allowed when lockdown is enforced (@pxref{Lockdown}). ++ This is done to prevent subverting various security mechanisms. + @end deffn + + @node distrust diff --git a/SOURCES/0379-video-readers-jpeg-Catch-files-with-unsupported-quan.patch b/SOURCES/0379-video-readers-jpeg-Catch-files-with-unsupported-quan.patch deleted file mode 100644 index 93dd5d4..0000000 --- a/SOURCES/0379-video-readers-jpeg-Catch-files-with-unsupported-quan.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Fri, 15 Jan 2021 12:57:04 +1100 -Subject: [PATCH] video/readers/jpeg: Catch files with unsupported quantization - or Huffman tables - -Our decoder only supports 2 quantization tables. If a file asks for -a quantization table with index > 1, reject it. - -Similarly, our decoder only supports 4 Huffman tables. If a file asks -for a Huffman table with index > 3, reject it. - -This fixes some out of bounds reads. It's not clear what degree of control -over subsequent execution could be gained by someone who can carefully -set up the contents of memory before loading an invalid JPEG file. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/video/readers/jpeg.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c -index a4a8269e237..856573996ac 100644 ---- a/grub-core/video/readers/jpeg.c -+++ b/grub-core/video/readers/jpeg.c -@@ -333,7 +333,11 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data) - else if (ss != JPEG_SAMPLING_1x1) - return grub_error (GRUB_ERR_BAD_FILE_TYPE, - "jpeg: sampling method not supported"); -+ - data->comp_index[id][0] = grub_jpeg_get_byte (data); -+ if (data->comp_index[id][0] > 1) -+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, -+ "jpeg: too many quantization tables"); - } - - if (data->file->offset != next_marker) -@@ -602,6 +606,10 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) - ht = grub_jpeg_get_byte (data); - data->comp_index[id][1] = (ht >> 4); - data->comp_index[id][2] = (ht & 0xF) + 2; -+ -+ 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"); - } - - grub_jpeg_get_byte (data); /* Skip 3 unused bytes. */ diff --git a/SOURCES/0380-commands-setpci-Restrict-setpci-command-when-locked-.patch b/SOURCES/0380-commands-setpci-Restrict-setpci-command-when-locked-.patch new file mode 100644 index 0000000..1bb09d4 --- /dev/null +++ b/SOURCES/0380-commands-setpci-Restrict-setpci-command-when-locked-.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Wed, 24 Feb 2021 22:59:59 +0100 +Subject: [PATCH] commands/setpci: Restrict setpci command when locked down + +This command can set PCI devices register values, which makes it dangerous +in a locked down configuration. Restrict it so can't be used on this setup. + +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/commands/setpci.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/grub-core/commands/setpci.c b/grub-core/commands/setpci.c +index d5bc97d60b2..fa2ba7d8919 100644 +--- a/grub-core/commands/setpci.c ++++ b/grub-core/commands/setpci.c +@@ -329,10 +329,10 @@ static grub_extcmd_t cmd; + + GRUB_MOD_INIT(setpci) + { +- cmd = grub_register_extcmd ("setpci", grub_cmd_setpci, 0, +- N_("[-s POSITION] [-d DEVICE] [-v VAR] " +- "REGISTER[=VALUE[:MASK]]"), +- N_("Manipulate PCI devices."), options); ++ cmd = grub_register_extcmd_lockdown ("setpci", grub_cmd_setpci, 0, ++ N_("[-s POSITION] [-d DEVICE] [-v VAR] " ++ "REGISTER[=VALUE[:MASK]]"), ++ N_("Manipulate PCI devices."), options); + } + + GRUB_MOD_FINI(setpci) diff --git a/SOURCES/0380-video-readers-jpeg-Catch-OOB-reads-writes-in-grub_jp.patch b/SOURCES/0380-video-readers-jpeg-Catch-OOB-reads-writes-in-grub_jp.patch deleted file mode 100644 index cc6f84c..0000000 --- a/SOURCES/0380-video-readers-jpeg-Catch-OOB-reads-writes-in-grub_jp.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Fri, 15 Jan 2021 13:29:53 +1100 -Subject: [PATCH] video/readers/jpeg: Catch OOB reads/writes in - grub_jpeg_decode_du() - -The key line is: - - du[jpeg_zigzag_order[pos]] = val * (int) data->quan_table[qt][pos]; - -jpeg_zigzag_order is grub_uint8_t[64]. - -I don't understand JPEG decoders quite well enough to explain what's -going on here. However, I observe sometimes pos=64, which leads to an -OOB read of the jpeg_zigzag_order global then an OOB write to du. -That leads to various unpleasant memory corruption conditions. - -Catch where pos >= ARRAY_SIZE(jpeg_zigzag_order) and bail. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/video/readers/jpeg.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c -index 856573996ac..28c1d62515e 100644 ---- a/grub-core/video/readers/jpeg.c -+++ b/grub-core/video/readers/jpeg.c -@@ -526,6 +526,14 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) - val = grub_jpeg_get_number (data, num & 0xF); - num >>= 4; - pos += num; -+ -+ if (pos >= ARRAY_SIZE (jpeg_zigzag_order)) -+ { -+ grub_error (GRUB_ERR_BAD_FILE_TYPE, -+ "jpeg: invalid position in zigzag order!?"); -+ return; -+ } -+ - du[jpeg_zigzag_order[pos]] = val * (int) data->quan_table[qt][pos]; - pos++; - } diff --git a/SOURCES/0381-commands-hdparm-Restrict-hdparm-command-when-locked-.patch b/SOURCES/0381-commands-hdparm-Restrict-hdparm-command-when-locked-.patch new file mode 100644 index 0000000..04129ca --- /dev/null +++ b/SOURCES/0381-commands-hdparm-Restrict-hdparm-command-when-locked-.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Wed, 24 Feb 2021 12:59:29 +0100 +Subject: [PATCH] commands/hdparm: Restrict hdparm command when locked down + +The command can be used to get/set ATA disk parameters. Some of these can +be dangerous since change the disk behavior. Restrict it when locked down. + +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/commands/hdparm.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/grub-core/commands/hdparm.c b/grub-core/commands/hdparm.c +index d3fa9661e5f..2e2319e645a 100644 +--- a/grub-core/commands/hdparm.c ++++ b/grub-core/commands/hdparm.c +@@ -436,9 +436,9 @@ static grub_extcmd_t cmd; + + GRUB_MOD_INIT(hdparm) + { +- cmd = grub_register_extcmd ("hdparm", grub_cmd_hdparm, 0, +- N_("[OPTIONS] DISK"), +- N_("Get/set ATA disk parameters."), options); ++ cmd = grub_register_extcmd_lockdown ("hdparm", grub_cmd_hdparm, 0, ++ N_("[OPTIONS] DISK"), ++ N_("Get/set ATA disk parameters."), options); + } + + GRUB_MOD_FINI(hdparm) diff --git a/SOURCES/0381-video-readers-jpeg-Don-t-decode-data-before-start-of.patch b/SOURCES/0381-video-readers-jpeg-Don-t-decode-data-before-start-of.patch deleted file mode 100644 index cdb6fe9..0000000 --- a/SOURCES/0381-video-readers-jpeg-Don-t-decode-data-before-start-of.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Fri, 15 Jan 2021 14:06:46 +1100 -Subject: [PATCH] video/readers/jpeg: Don't decode data before start of stream - -When a start of stream marker is encountered, we call grub_jpeg_decode_sos() -which allocates space for a bitmap. - -When a restart marker is encountered, we call grub_jpeg_decode_data() which -then fills in that bitmap. - -If we get a restart marker before the start of stream marker, we will -attempt to write to a bitmap_ptr that hasn't been allocated. Catch this -and bail out. This fixes an attempt to write to NULL. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/video/readers/jpeg.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c -index 28c1d62515e..c48cbd41b48 100644 ---- a/grub-core/video/readers/jpeg.c -+++ b/grub-core/video/readers/jpeg.c -@@ -646,6 +646,10 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data) - nr1 = (data->image_height + vb - 1) >> (3 + data->log_vs); - 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"); -+ - for (; data->r1 < nr1 && (!data->dri || rst); - data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3) - for (c1 = 0; c1 < nc1 && (!data->dri || rst); diff --git a/SOURCES/0382-gdb-Restrict-GDB-access-when-locked-down.patch b/SOURCES/0382-gdb-Restrict-GDB-access-when-locked-down.patch new file mode 100644 index 0000000..b392d22 --- /dev/null +++ b/SOURCES/0382-gdb-Restrict-GDB-access-when-locked-down.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Wed, 24 Feb 2021 15:03:26 +0100 +Subject: [PATCH] gdb: Restrict GDB access when locked down + +The gdbstub* commands allow to start and control a GDB stub running on +local host that can be used to connect from a remote debugger. Restrict +this functionality when the GRUB is locked down. + +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/gdb/gdb.c | 32 ++++++++++++++++++-------------- + 1 file changed, 18 insertions(+), 14 deletions(-) + +diff --git a/grub-core/gdb/gdb.c b/grub-core/gdb/gdb.c +index 847a1e1e36f..1818cb6f8eb 100644 +--- a/grub-core/gdb/gdb.c ++++ b/grub-core/gdb/gdb.c +@@ -75,20 +75,24 @@ static grub_command_t cmd, cmd_stop, cmd_break; + GRUB_MOD_INIT (gdb) + { + grub_gdb_idtinit (); +- cmd = grub_register_command ("gdbstub", grub_cmd_gdbstub, +- N_("PORT"), +- /* TRANSLATORS: GDB stub is a small part of +- GDB functionality running on local host +- which allows remote debugger to +- connect to it. */ +- N_("Start GDB stub on given port")); +- cmd_break = grub_register_command ("gdbstub_break", grub_cmd_gdb_break, +- /* TRANSLATORS: this refers to triggering +- a breakpoint so that the user will land +- into GDB. */ +- 0, N_("Break into GDB")); +- cmd_stop = grub_register_command ("gdbstub_stop", grub_cmd_gdbstop, +- 0, N_("Stop GDB stub")); ++ cmd = grub_register_command_lockdown ("gdbstub", grub_cmd_gdbstub, ++ N_("PORT"), ++ /* ++ * TRANSLATORS: GDB stub is a small part of ++ * GDB functionality running on local host ++ * which allows remote debugger to ++ * connect to it. ++ */ ++ N_("Start GDB stub on given port")); ++ cmd_break = grub_register_command_lockdown ("gdbstub_break", grub_cmd_gdb_break, ++ /* ++ * TRANSLATORS: this refers to triggering ++ * a breakpoint so that the user will land ++ * into GDB. ++ */ ++ 0, N_("Break into GDB")); ++ cmd_stop = grub_register_command_lockdown ("gdbstub_stop", grub_cmd_gdbstop, ++ 0, N_("Stop GDB stub")); + } + + GRUB_MOD_FINI (gdb) diff --git a/SOURCES/0382-term-gfxterm-Don-t-set-up-a-font-with-glyphs-that-ar.patch b/SOURCES/0382-term-gfxterm-Don-t-set-up-a-font-with-glyphs-that-ar.patch deleted file mode 100644 index 533481d..0000000 --- a/SOURCES/0382-term-gfxterm-Don-t-set-up-a-font-with-glyphs-that-ar.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Fri, 15 Jan 2021 20:03:20 +1100 -Subject: [PATCH] term/gfxterm: Don't set up a font with glyphs that are too - big - -Catch the case where we have a font so big that it causes the number of -rows or columns to be 0. Currently we continue and allocate a -virtual_screen.text_buffer of size 0. We then try to use that for glpyhs -and things go badly. - -On the emu platform, malloc() may give us a valid pointer, in which case -we'll access heap memory which we shouldn't. Alternatively, it may give us -NULL, in which case we'll crash. For other platforms, if I understand -grub_memalign() correctly, we will receive a valid but small allocation -that we will very likely later overrun. - -Prevent the creation of a virtual screen that isn't at least 40 cols -by 12 rows. This is arbitrary, but it seems that if your width or height -is half a standard 80x24 terminal, you're probably going to struggle to -read anything anyway. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/term/gfxterm.c | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/grub-core/term/gfxterm.c b/grub-core/term/gfxterm.c -index af7c090a3e7..b40fcce9151 100644 ---- a/grub-core/term/gfxterm.c -+++ b/grub-core/term/gfxterm.c -@@ -232,6 +232,15 @@ grub_virtual_screen_setup (unsigned int x, unsigned int y, - virtual_screen.columns = virtual_screen.width / virtual_screen.normal_char_width; - virtual_screen.rows = virtual_screen.height / virtual_screen.normal_char_height; - -+ /* -+ * There must be a minimum number of rows and columns for the screen to -+ * make sense. Arbitrarily pick half of 80x24. If either dimensions is 0 -+ * we would allocate 0 bytes for the text_buffer. -+ */ -+ if (virtual_screen.columns < 40 || virtual_screen.rows < 12) -+ return grub_error (GRUB_ERR_BAD_FONT, -+ "font: glyphs too large to fit on screen"); -+ - /* Allocate memory for text buffer. */ - virtual_screen.text_buffer = - (struct grub_colored_char *) grub_malloc (virtual_screen.columns diff --git a/SOURCES/0383-fs-fshelp-Catch-impermissibly-large-block-sizes-in-r.patch b/SOURCES/0383-fs-fshelp-Catch-impermissibly-large-block-sizes-in-r.patch deleted file mode 100644 index 67c4b55..0000000 --- a/SOURCES/0383-fs-fshelp-Catch-impermissibly-large-block-sizes-in-r.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Mon, 18 Jan 2021 11:46:39 +1100 -Subject: [PATCH] fs/fshelp: Catch impermissibly large block sizes in read - helper - -A fuzzed HFS+ filesystem had log2blocksize = 22. This gave -log2blocksize + GRUB_DISK_SECTOR_BITS = 31. 1 << 31 = 0x80000000, -which is -1 as an int. This caused some wacky behavior later on in -the function, leading to out-of-bounds writes on the destination buffer. - -Catch log2blocksize + GRUB_DISK_SECTOR_BITS >= 31. We could be stricter, -but this is the minimum that will prevent integer size weirdness. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/fs/fshelp.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/grub-core/fs/fshelp.c b/grub-core/fs/fshelp.c -index 4c902adf381..a2d0d297a52 100644 ---- a/grub-core/fs/fshelp.c -+++ b/grub-core/fs/fshelp.c -@@ -362,6 +362,18 @@ grub_fshelp_read_file (grub_disk_t disk, grub_fshelp_node_t node, - grub_disk_addr_t i, blockcnt; - int blocksize = 1 << (log2blocksize + GRUB_DISK_SECTOR_BITS); - -+ /* -+ * Catch blatantly invalid log2blocksize. We could be a lot stricter, but -+ * this is the most permissive we can be before we start to see integer -+ * overflow/underflow issues. -+ */ -+ if (log2blocksize + GRUB_DISK_SECTOR_BITS >= 31) -+ { -+ grub_error (GRUB_ERR_OUT_OF_RANGE, -+ N_("blocksize too large")); -+ return -1; -+ } -+ - if (pos > filesize) - { - grub_error (GRUB_ERR_OUT_OF_RANGE, diff --git a/SOURCES/0383-loader-xnu-Don-t-allow-loading-extension-and-package.patch b/SOURCES/0383-loader-xnu-Don-t-allow-loading-extension-and-package.patch new file mode 100644 index 0000000..fe39c33 --- /dev/null +++ b/SOURCES/0383-loader-xnu-Don-t-allow-loading-extension-and-package.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Wed, 24 Feb 2021 14:44:38 +0100 +Subject: [PATCH] loader/xnu: Don't allow loading extension and packages when + locked down + +The shim_lock verifier validates the XNU kernels but no its extensions +and packages. Prevent these to be loaded when the GRUB is locked down. + +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/loader/xnu.c | 31 +++++++++++++++++-------------- + 1 file changed, 17 insertions(+), 14 deletions(-) + +diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c +index 5944dc5eafc..b33a384321c 100644 +--- a/grub-core/loader/xnu.c ++++ b/grub-core/loader/xnu.c +@@ -1489,20 +1489,23 @@ GRUB_MOD_INIT(xnu) + N_("Load XNU image.")); + cmd_kernel64 = grub_register_command ("xnu_kernel64", grub_cmd_xnu_kernel64, + 0, N_("Load 64-bit XNU image.")); +- cmd_mkext = grub_register_command ("xnu_mkext", grub_cmd_xnu_mkext, 0, +- N_("Load XNU extension package.")); +- cmd_kext = grub_register_command ("xnu_kext", grub_cmd_xnu_kext, 0, +- N_("Load XNU extension.")); +- cmd_kextdir = grub_register_command ("xnu_kextdir", grub_cmd_xnu_kextdir, +- /* TRANSLATORS: OSBundleRequired is a +- variable name in xnu extensions +- manifests. It behaves mostly like +- GNU/Linux runlevels. +- */ +- N_("DIRECTORY [OSBundleRequired]"), +- /* TRANSLATORS: There are many extensions +- in extension directory. */ +- N_("Load XNU extension directory.")); ++ cmd_mkext = grub_register_command_lockdown ("xnu_mkext", grub_cmd_xnu_mkext, 0, ++ N_("Load XNU extension package.")); ++ cmd_kext = grub_register_command_lockdown ("xnu_kext", grub_cmd_xnu_kext, 0, ++ N_("Load XNU extension.")); ++ cmd_kextdir = grub_register_command_lockdown ("xnu_kextdir", grub_cmd_xnu_kextdir, ++ /* ++ * TRANSLATORS: OSBundleRequired is ++ * a variable name in xnu extensions ++ * manifests. It behaves mostly like ++ * GNU/Linux runlevels. ++ */ ++ N_("DIRECTORY [OSBundleRequired]"), ++ /* ++ * TRANSLATORS: There are many extensions ++ * in extension directory. ++ */ ++ N_("Load XNU extension directory.")); + cmd_ramdisk = grub_register_command ("xnu_ramdisk", grub_cmd_xnu_ramdisk, 0, + /* TRANSLATORS: ramdisk here isn't identifier. It can be translated. */ + N_("Load XNU ramdisk. " diff --git a/SOURCES/0384-docs-Document-the-cutmem-command.patch b/SOURCES/0384-docs-Document-the-cutmem-command.patch new file mode 100644 index 0000000..fd37e8f --- /dev/null +++ b/SOURCES/0384-docs-Document-the-cutmem-command.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Sat, 7 Nov 2020 01:03:18 +0100 +Subject: [PATCH] docs: Document the cutmem command + +The command is not present in the docs/grub.texi user documentation. + +Reported-by: Daniel Kiper +Signed-off-by: Javier Martinez Canillas +Signed-off-by: Daniel Kiper +Reviewed-by: Javier Martinez Canillas +--- + docs/grub.texi | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/docs/grub.texi b/docs/grub.texi +index c55452307dc..314bbeb8471 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -3942,6 +3942,7 @@ you forget a command, you can run the command @command{help} + * cpuid:: Check for CPU features + * crc:: Compute or check CRC32 checksums + * cryptomount:: Mount a crypto device ++* cutmem:: Remove memory regions + * date:: Display or set current date and time + * devicetree:: Load a device tree blob + * distrust:: Remove a pubkey from trusted keys +@@ -4103,6 +4104,8 @@ this page is to be filtered. This syntax makes it easy to represent patterns + that are often result of memory damage, due to physical distribution of memory + cells. + ++The command is similar to @command{cutmem} command. ++ + Note: The command is not allowed when lockdown is enforced (@pxref{Lockdown}). + This prevents removing EFI memory regions to potentially subvert the + security mechanisms provided by the UEFI secure boot. +@@ -4266,6 +4269,24 @@ GRUB suports devices encrypted using LUKS and geli. Note that necessary modules + be used. + @end deffn + ++@node cutmem ++@subsection cutmem ++ ++@deffn Command cutmem from[K|M|G] to[K|M|G] ++Remove any memory regions in specified range. ++@end deffn ++ ++This command notifies the memory manager that specified regions of RAM ought to ++be filtered out. This remains in effect after a payload kernel has been loaded ++by GRUB, as long as the loaded kernel obtains its memory map from GRUB. Kernels ++that support this include Linux, GNU Mach, the kernel of FreeBSD and Multiboot ++kernels in general. ++ ++The command is similar to @command{badram} command. ++ ++Note: The command is not allowed when lockdown is enforced (@pxref{Lockdown}). ++ This prevents removing EFI memory regions to potentially subvert the ++ security mechanisms provided by the UEFI secure boot. + + @node date + @subsection date diff --git a/SOURCES/0384-fs-hfsplus-Don-t-fetch-a-key-beyond-the-end-of-the-n.patch b/SOURCES/0384-fs-hfsplus-Don-t-fetch-a-key-beyond-the-end-of-the-n.patch deleted file mode 100644 index 6d15b85..0000000 --- a/SOURCES/0384-fs-hfsplus-Don-t-fetch-a-key-beyond-the-end-of-the-n.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Fri, 22 Jan 2021 18:13:56 +1100 -Subject: [PATCH] fs/hfsplus: Don't fetch a key beyond the end of the node - -Otherwise you get a wild pointer, leading to a bunch of invalid reads. -Check it falls inside the given node. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/fs/hfsplus.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/grub-core/fs/hfsplus.c b/grub-core/fs/hfsplus.c -index 03a33ea2477..423f4b956ba 100644 ---- a/grub-core/fs/hfsplus.c -+++ b/grub-core/fs/hfsplus.c -@@ -635,6 +635,10 @@ grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree, - pointer = ((char *) currkey - + grub_be_to_cpu16 (currkey->keylen) - + 2); -+ -+ if ((char *) pointer > node + btree->nodesize - 2) -+ return grub_error (GRUB_ERR_BAD_FS, "HFS+ key beyond end of node"); -+ - currnode = grub_be_to_cpu32 (grub_get_unaligned32 (pointer)); - match = 1; - } diff --git a/SOURCES/0385-dl-Only-allow-unloading-modules-that-are-not-depende.patch b/SOURCES/0385-dl-Only-allow-unloading-modules-that-are-not-depende.patch new file mode 100644 index 0000000..b482bba --- /dev/null +++ b/SOURCES/0385-dl-Only-allow-unloading-modules-that-are-not-depende.patch @@ -0,0 +1,83 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Tue, 29 Sep 2020 14:08:55 +0200 +Subject: [PATCH] dl: Only allow unloading modules that are not dependencies + +When a module is attempted to be removed its reference counter is always +decremented. This means that repeated rmmod invocations will cause the +module to be unloaded even if another module depends on it. + +This may lead to a use-after-free scenario allowing an attacker to execute +arbitrary code and by-pass the UEFI Secure Boot protection. + +While being there, add the extern keyword to some function declarations in +that header file. + +Fixes: CVE-2020-25632 + +Reported-by: Chris Coulson +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/commands/minicmd.c | 7 +++++-- + grub-core/kern/dl.c | 9 +++++++++ + include/grub/dl.h | 8 +++++--- + 3 files changed, 19 insertions(+), 5 deletions(-) + +diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c +index 6d66b7c453a..2bd3ac76f2d 100644 +--- a/grub-core/commands/minicmd.c ++++ b/grub-core/commands/minicmd.c +@@ -140,8 +140,11 @@ grub_mini_cmd_rmmod (struct grub_command *cmd __attribute__ ((unused)), + if (grub_dl_is_persistent (mod)) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "cannot unload persistent module"); + +- if (grub_dl_unref (mod) <= 0) +- grub_dl_unload (mod); ++ if (grub_dl_ref_count (mod) > 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "cannot unload referenced module"); ++ ++ grub_dl_unref (mod); ++ grub_dl_unload (mod); + + return 0; + } +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index d7a7c8f97b0..520126beab7 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -621,6 +621,15 @@ grub_dl_unref (grub_dl_t mod) + return --mod->ref_count; + } + ++int ++grub_dl_ref_count (grub_dl_t mod) ++{ ++ if (mod == NULL) ++ return 0; ++ ++ return mod->ref_count; ++} ++ + static void + grub_dl_flush_cache (grub_dl_t mod) + { +diff --git a/include/grub/dl.h b/include/grub/dl.h +index 877821dcb04..6a3e251b455 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -205,9 +205,11 @@ grub_dl_t EXPORT_FUNC(grub_dl_load) (const char *name); + grub_dl_t grub_dl_load_core (void *addr, grub_size_t size); + grub_dl_t EXPORT_FUNC(grub_dl_load_core_noinit) (void *addr, grub_size_t size); + int EXPORT_FUNC(grub_dl_unload) (grub_dl_t mod); +-void grub_dl_unload_unneeded (void); +-int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod); +-int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod); ++extern void grub_dl_unload_unneeded (void); ++extern int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod); ++extern int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod); ++extern int EXPORT_FUNC(grub_dl_ref_count) (grub_dl_t mod); ++ + extern grub_dl_t EXPORT_VAR(grub_dl_head); + + #ifndef GRUB_UTIL diff --git a/SOURCES/0385-fs-hfsplus-Don-t-use-uninitialized-data-on-corrupt-f.patch b/SOURCES/0385-fs-hfsplus-Don-t-use-uninitialized-data-on-corrupt-f.patch deleted file mode 100644 index 6418541..0000000 --- a/SOURCES/0385-fs-hfsplus-Don-t-use-uninitialized-data-on-corrupt-f.patch +++ /dev/null @@ -1,104 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Tue, 2 Feb 2021 16:59:35 +1100 -Subject: [PATCH] fs/hfsplus: Don't use uninitialized data on corrupt - filesystems - -Valgrind identified the following use of uninitialized data: - - ==2782220== Conditional jump or move depends on uninitialised value(s) - ==2782220== at 0x42B364: grub_hfsplus_btree_search (hfsplus.c:566) - ==2782220== by 0x42B21D: grub_hfsplus_read_block (hfsplus.c:185) - ==2782220== by 0x42A693: grub_fshelp_read_file (fshelp.c:386) - ==2782220== by 0x42C598: grub_hfsplus_read_file (hfsplus.c:219) - ==2782220== by 0x42C598: grub_hfsplus_mount (hfsplus.c:330) - ==2782220== by 0x42B8C5: grub_hfsplus_dir (hfsplus.c:958) - ==2782220== by 0x4C1AE6: grub_fs_probe (fs.c:73) - ==2782220== by 0x407C94: grub_ls_list_files (ls.c:186) - ==2782220== by 0x407C94: grub_cmd_ls (ls.c:284) - ==2782220== by 0x4D7130: grub_extcmd_dispatcher (extcmd.c:55) - ==2782220== by 0x4045A6: execute_command (grub-fstest.c:59) - ==2782220== by 0x4045A6: fstest (grub-fstest.c:433) - ==2782220== by 0x4045A6: main (grub-fstest.c:772) - ==2782220== Uninitialised value was created by a heap allocation - ==2782220== at 0x483C7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) - ==2782220== by 0x4C0305: grub_malloc (mm.c:42) - ==2782220== by 0x42C21D: grub_hfsplus_mount (hfsplus.c:239) - ==2782220== by 0x42B8C5: grub_hfsplus_dir (hfsplus.c:958) - ==2782220== by 0x4C1AE6: grub_fs_probe (fs.c:73) - ==2782220== by 0x407C94: grub_ls_list_files (ls.c:186) - ==2782220== by 0x407C94: grub_cmd_ls (ls.c:284) - ==2782220== by 0x4D7130: grub_extcmd_dispatcher (extcmd.c:55) - ==2782220== by 0x4045A6: execute_command (grub-fstest.c:59) - ==2782220== by 0x4045A6: fstest (grub-fstest.c:433) - ==2782220== by 0x4045A6: main (grub-fstest.c:772) - -This happens when the process of reading the catalog file goes sufficiently -wrong that there's an attempt to read the extent overflow file, which has -not yet been loaded. Keep track of when the extent overflow file is -fully loaded and refuse to use it before then. - -The load valgrind doesn't like is btree->nodesize, and that's then used -to allocate a data structure. It looks like there are subsequently a lot -of reads based on that pointer so OOB reads are likely, and indeed crashes -(albeit difficult-to-replicate ones) have been observed in fuzzing. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/fs/hfsplus.c | 14 ++++++++++++++ - include/grub/hfsplus.h | 2 ++ - 2 files changed, 16 insertions(+) - -diff --git a/grub-core/fs/hfsplus.c b/grub-core/fs/hfsplus.c -index 423f4b956ba..8c0c804735d 100644 ---- a/grub-core/fs/hfsplus.c -+++ b/grub-core/fs/hfsplus.c -@@ -177,6 +177,17 @@ grub_hfsplus_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) - break; - } - -+ /* -+ * If the extent overflow tree isn't ready yet, we can't look -+ * in it. This can happen where the catalog file is corrupted. -+ */ -+ if (!node->data->extoverflow_tree_ready) -+ { -+ grub_error (GRUB_ERR_BAD_FS, -+ "attempted to read extent overflow tree before loading"); -+ break; -+ } -+ - /* Set up the key to look for in the extent overflow file. */ - extoverflow.extkey.fileid = node->fileid; - extoverflow.extkey.type = 0; -@@ -241,6 +252,7 @@ grub_hfsplus_mount (grub_disk_t disk) - return 0; - - data->disk = disk; -+ data->extoverflow_tree_ready = 0; - - /* Read the bootblock. */ - grub_disk_read (disk, GRUB_HFSPLUS_SBLOCK, 0, sizeof (volheader), -@@ -357,6 +369,8 @@ grub_hfsplus_mount (grub_disk_t disk) - if (data->extoverflow_tree.nodesize < 2) - goto fail; - -+ data->extoverflow_tree_ready = 1; -+ - if (grub_hfsplus_read_file (&data->attr_tree.file, 0, 0, - sizeof (struct grub_hfsplus_btnode), - sizeof (header), (char *) &header) <= 0) -diff --git a/include/grub/hfsplus.h b/include/grub/hfsplus.h -index 117740ae269..e14dd31ff54 100644 ---- a/include/grub/hfsplus.h -+++ b/include/grub/hfsplus.h -@@ -113,6 +113,8 @@ struct grub_hfsplus_data - struct grub_hfsplus_btree extoverflow_tree; - struct grub_hfsplus_btree attr_tree; - -+ int extoverflow_tree_ready; -+ - struct grub_hfsplus_file dirroot; - struct grub_hfsplus_file opened_file; - diff --git a/SOURCES/0386-fs-hfs-Disable-under-lockdown.patch b/SOURCES/0386-fs-hfs-Disable-under-lockdown.patch deleted file mode 100644 index e2971f0..0000000 --- a/SOURCES/0386-fs-hfs-Disable-under-lockdown.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Mon, 18 Jan 2021 12:19:07 +1100 -Subject: [PATCH] fs/hfs: Disable under lockdown - -HFS has issues such as infinite mutual recursion that are simply too -complex to fix for such a legacy format. So simply do not permit -it to be loaded under lockdown. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/fs/hfs.c | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/grub-core/fs/hfs.c b/grub-core/fs/hfs.c -index 3fd4eec202c..49d1831c808 100644 ---- a/grub-core/fs/hfs.c -+++ b/grub-core/fs/hfs.c -@@ -30,6 +30,7 @@ - #include - #include - #include -+#include - - GRUB_MOD_LICENSE ("GPLv3+"); - -@@ -1433,11 +1434,13 @@ static struct grub_fs grub_hfs_fs = - - GRUB_MOD_INIT(hfs) - { -- grub_fs_register (&grub_hfs_fs); -+ if (!grub_is_lockdown ()) -+ grub_fs_register (&grub_hfs_fs); - my_mod = mod; - } - - GRUB_MOD_FINI(hfs) - { -- grub_fs_unregister (&grub_hfs_fs); -+ if (!grub_is_lockdown()) -+ grub_fs_unregister (&grub_hfs_fs); - } diff --git a/SOURCES/0386-usb-Avoid-possible-out-of-bound-accesses-caused-by-m.patch b/SOURCES/0386-usb-Avoid-possible-out-of-bound-accesses-caused-by-m.patch new file mode 100644 index 0000000..1b04633 --- /dev/null +++ b/SOURCES/0386-usb-Avoid-possible-out-of-bound-accesses-caused-by-m.patch @@ -0,0 +1,112 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Fri, 11 Dec 2020 19:19:21 +0100 +Subject: [PATCH] usb: Avoid possible out-of-bound accesses caused by malicious + devices + +The maximum number of configurations and interfaces are fixed but there is +no out-of-bound checking to prevent a malicious USB device to report large +values for these and cause accesses outside the arrays' memory. + +Fixes: CVE-2020-25647 + +Reported-by: Joseph Tartaro (IOActive) +Reported-by: Ilja Van Sprundel +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/bus/usb/usb.c | 15 ++++++++++++--- + include/grub/usb.h | 10 +++++++--- + 2 files changed, 19 insertions(+), 6 deletions(-) + +diff --git a/grub-core/bus/usb/usb.c b/grub-core/bus/usb/usb.c +index 8da5e4c7491..7cb3cc230b2 100644 +--- a/grub-core/bus/usb/usb.c ++++ b/grub-core/bus/usb/usb.c +@@ -75,6 +75,9 @@ grub_usb_controller_iterate (grub_usb_controller_iterate_hook_t hook, + grub_usb_err_t + grub_usb_clear_halt (grub_usb_device_t dev, int endpoint) + { ++ if (endpoint >= GRUB_USB_MAX_TOGGLE) ++ return GRUB_USB_ERR_BADDEVICE; ++ + dev->toggle[endpoint] = 0; + return grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT + | GRUB_USB_REQTYPE_STANDARD +@@ -134,10 +137,10 @@ grub_usb_device_initialize (grub_usb_device_t dev) + return err; + descdev = &dev->descdev; + +- for (i = 0; i < 8; i++) ++ for (i = 0; i < GRUB_USB_MAX_CONF; i++) + dev->config[i].descconf = NULL; + +- if (descdev->configcnt == 0) ++ if (descdev->configcnt == 0 || descdev->configcnt > GRUB_USB_MAX_CONF) + { + err = GRUB_USB_ERR_BADDEVICE; + goto fail; +@@ -172,6 +175,12 @@ grub_usb_device_initialize (grub_usb_device_t dev) + /* Skip the configuration descriptor. */ + pos = dev->config[i].descconf->length; + ++ if (dev->config[i].descconf->numif > GRUB_USB_MAX_IF) ++ { ++ err = GRUB_USB_ERR_BADDEVICE; ++ goto fail; ++ } ++ + /* Read all interfaces. */ + for (currif = 0; currif < dev->config[i].descconf->numif; currif++) + { +@@ -217,7 +226,7 @@ grub_usb_device_initialize (grub_usb_device_t dev) + + fail: + +- for (i = 0; i < 8; i++) ++ for (i = 0; i < GRUB_USB_MAX_CONF; i++) + grub_free (dev->config[i].descconf); + + return err; +diff --git a/include/grub/usb.h b/include/grub/usb.h +index 512ae1dd0e6..6475c552fc6 100644 +--- a/include/grub/usb.h ++++ b/include/grub/usb.h +@@ -23,6 +23,10 @@ + #include + #include + ++#define GRUB_USB_MAX_CONF 8 ++#define GRUB_USB_MAX_IF 32 ++#define GRUB_USB_MAX_TOGGLE 256 ++ + typedef struct grub_usb_device *grub_usb_device_t; + typedef struct grub_usb_controller *grub_usb_controller_t; + typedef struct grub_usb_controller_dev *grub_usb_controller_dev_t; +@@ -167,7 +171,7 @@ struct grub_usb_configuration + struct grub_usb_desc_config *descconf; + + /* Interfaces associated to this configuration. */ +- struct grub_usb_interface interf[32]; ++ struct grub_usb_interface interf[GRUB_USB_MAX_IF]; + }; + + struct grub_usb_hub_port +@@ -191,7 +195,7 @@ struct grub_usb_device + struct grub_usb_controller controller; + + /* Device configurations (after opening the device). */ +- struct grub_usb_configuration config[8]; ++ struct grub_usb_configuration config[GRUB_USB_MAX_CONF]; + + /* Device address. */ + int addr; +@@ -203,7 +207,7 @@ struct grub_usb_device + int initialized; + + /* Data toggle values (used for bulk transfers only). */ +- int toggle[256]; ++ int toggle[GRUB_USB_MAX_TOGGLE]; + + /* Used by libusb wrapper. Schedulded for removal. */ + void *data; diff --git a/SOURCES/0387-fs-sfs-Fix-over-read-of-root-object-name.patch b/SOURCES/0387-fs-sfs-Fix-over-read-of-root-object-name.patch deleted file mode 100644 index dddbe7f..0000000 --- a/SOURCES/0387-fs-sfs-Fix-over-read-of-root-object-name.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Mon, 18 Jan 2021 14:34:58 +1100 -Subject: [PATCH] fs/sfs: Fix over-read of root object name - -There's a read of the name of the root object that assumes that the name -is nul-terminated within the root block. This isn't guaranteed - it seems -SFS would require you to read multiple blocks to get a full name in general, -but maybe that doesn't apply to the root object. - -Either way, figure out how much space is left in the root block and don't -over-read it. This fixes some OOB reads. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/fs/sfs.c | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/grub-core/fs/sfs.c b/grub-core/fs/sfs.c -index 3ddc6b5e287..61d6c303cb3 100644 ---- a/grub-core/fs/sfs.c -+++ b/grub-core/fs/sfs.c -@@ -373,6 +373,7 @@ grub_sfs_mount (grub_disk_t disk) - struct grub_sfs_objc *rootobjc; - char *rootobjc_data = 0; - grub_uint32_t blk; -+ unsigned int max_len; - - data = grub_malloc (sizeof (*data)); - if (!data) -@@ -421,7 +422,13 @@ grub_sfs_mount (grub_disk_t disk) - data->diropen.data = data; - data->diropen.cache = 0; - data->disk = disk; -- data->label = grub_strdup ((char *) (rootobjc->objects[0].filename)); -+ -+ /* We only read 1 block of data, so truncate the name if needed. */ -+ max_len = ((GRUB_DISK_SECTOR_SIZE << data->log_blocksize) -+ - 24 /* offsetof (struct grub_sfs_objc, objects) */ -+ - 25); /* offsetof (struct grub_sfs_obj, filename) */ -+ data->label = grub_zalloc (max_len + 1); -+ grub_strncpy (data->label, (char *) rootobjc->objects[0].filename, max_len); - - grub_free (rootobjc_data); - return data; diff --git a/SOURCES/0387-mmap-Fix-memory-leak-when-iterating-over-mapped-memo.patch b/SOURCES/0387-mmap-Fix-memory-leak-when-iterating-over-mapped-memo.patch new file mode 100644 index 0000000..66e3744 --- /dev/null +++ b/SOURCES/0387-mmap-Fix-memory-leak-when-iterating-over-mapped-memo.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Thu, 3 Dec 2020 14:39:45 +0000 +Subject: [PATCH] mmap: Fix memory leak when iterating over mapped memory + +When returning from grub_mmap_iterate() the memory allocated to present +is not being released causing it to leak. + +Fixes: CID 96655 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/mmap/mmap.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/grub-core/mmap/mmap.c b/grub-core/mmap/mmap.c +index 7ebf32e1e5e..8bf235f3400 100644 +--- a/grub-core/mmap/mmap.c ++++ b/grub-core/mmap/mmap.c +@@ -270,6 +270,7 @@ grub_mmap_iterate (grub_memory_hook_t hook, void *hook_data) + hook_data)) + { + grub_free (ctx.scanline_events); ++ grub_free (present); + return GRUB_ERR_NONE; + } + +@@ -282,6 +283,7 @@ grub_mmap_iterate (grub_memory_hook_t hook, void *hook_data) + } + + grub_free (ctx.scanline_events); ++ grub_free (present); + return GRUB_ERR_NONE; + } + diff --git a/SOURCES/0388-fs-jfs-Do-not-move-to-leaf-level-if-name-length-is-n.patch b/SOURCES/0388-fs-jfs-Do-not-move-to-leaf-level-if-name-length-is-n.patch deleted file mode 100644 index 7c75a3b..0000000 --- a/SOURCES/0388-fs-jfs-Do-not-move-to-leaf-level-if-name-length-is-n.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Mon, 18 Jan 2021 14:51:11 +1100 -Subject: [PATCH] fs/jfs: Do not move to leaf level if name length is negative - -Fuzzing JFS revealed crashes where a negative number would be passed -to le_to_cpu16_copy(). There it would be cast to a large positive number -and the copy would read and write off the end of the respective buffers. - -Catch this at the top as well as the bottom of the loop. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/fs/jfs.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/grub-core/fs/jfs.c b/grub-core/fs/jfs.c -index aab3e8c7b7d..1819899bdec 100644 ---- a/grub-core/fs/jfs.c -+++ b/grub-core/fs/jfs.c -@@ -563,7 +563,7 @@ grub_jfs_getent (struct grub_jfs_diropen *diro) - - /* Move down to the leaf level. */ - nextent = leaf->next; -- if (leaf->next != 255) -+ if (leaf->next != 255 && len > 0) - do - { - next_leaf = &diro->next_leaf[nextent]; diff --git a/SOURCES/0388-net-net-Fix-possible-dereference-to-of-a-NULL-pointe.patch b/SOURCES/0388-net-net-Fix-possible-dereference-to-of-a-NULL-pointe.patch new file mode 100644 index 0000000..0f50d98 --- /dev/null +++ b/SOURCES/0388-net-net-Fix-possible-dereference-to-of-a-NULL-pointe.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Fri, 27 Nov 2020 15:10:26 +0000 +Subject: [PATCH] net/net: Fix possible dereference to of a NULL pointer + +It is always possible that grub_zalloc() could fail, so we should check for +a NULL return. Otherwise we run the risk of dereferencing a NULL pointer. + +Fixes: CID 296221 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/net/net.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/net.c b/grub-core/net/net.c +index 1fd104aeaf2..a27c53eee1c 100644 +--- a/grub-core/net/net.c ++++ b/grub-core/net/net.c +@@ -89,8 +89,13 @@ grub_net_link_layer_add_address (struct grub_net_card *card, + + /* Add sender to cache table. */ + if (card->link_layer_table == NULL) +- card->link_layer_table = grub_zalloc (LINK_LAYER_CACHE_SIZE +- * sizeof (card->link_layer_table[0])); ++ { ++ card->link_layer_table = grub_zalloc (LINK_LAYER_CACHE_SIZE ++ * sizeof (card->link_layer_table[0])); ++ if (card->link_layer_table == NULL) ++ return; ++ } ++ + entry = &(card->link_layer_table[card->new_ll_entry]); + entry->avail = 1; + grub_memcpy (&entry->ll_address, ll, sizeof (entry->ll_address)); diff --git a/SOURCES/0389-fs-jfs-Limit-the-extents-that-getblk-can-consider.patch b/SOURCES/0389-fs-jfs-Limit-the-extents-that-getblk-can-consider.patch deleted file mode 100644 index 91ab8db..0000000 --- a/SOURCES/0389-fs-jfs-Limit-the-extents-that-getblk-can-consider.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Mon, 18 Jan 2021 14:57:17 +1100 -Subject: [PATCH] fs/jfs: Limit the extents that getblk() can consider - -getblk() implicitly trusts that treehead->count is an accurate count of -the number of extents. However, that value is read from disk and is not -trustworthy, leading to OOB reads and crashes. I am not sure to what -extent the data read from OOB can influence subsequent program execution. - -Require callers to pass in the maximum number of extents for which -they have storage. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/fs/jfs.c | 8 +++++--- - 1 file changed, 5 insertions(+), 3 deletions(-) - -diff --git a/grub-core/fs/jfs.c b/grub-core/fs/jfs.c -index 1819899bdec..6e81f37da6c 100644 ---- a/grub-core/fs/jfs.c -+++ b/grub-core/fs/jfs.c -@@ -261,13 +261,15 @@ static grub_err_t grub_jfs_lookup_symlink (struct grub_jfs_data *data, grub_uint - static grub_int64_t - getblk (struct grub_jfs_treehead *treehead, - struct grub_jfs_tree_extent *extents, -+ int max_extents, - struct grub_jfs_data *data, - grub_uint64_t blk) - { - int found = -1; - int i; - -- for (i = 0; i < grub_le_to_cpu16 (treehead->count) - 2; i++) -+ for (i = 0; i < grub_le_to_cpu16 (treehead->count) - 2 && -+ i < max_extents; i++) - { - if (treehead->flags & GRUB_JFS_TREE_LEAF) - { -@@ -302,7 +304,7 @@ getblk (struct grub_jfs_treehead *treehead, - << (grub_le_to_cpu16 (data->sblock.log2_blksz) - - GRUB_DISK_SECTOR_BITS), 0, - sizeof (*tree), (char *) tree)) -- ret = getblk (&tree->treehead, &tree->extents[0], data, blk); -+ ret = getblk (&tree->treehead, &tree->extents[0], 254, data, blk); - grub_free (tree); - return ret; - } -@@ -316,7 +318,7 @@ static grub_int64_t - grub_jfs_blkno (struct grub_jfs_data *data, struct grub_jfs_inode *inode, - grub_uint64_t blk) - { -- return getblk (&inode->file.tree, &inode->file.extents[0], data, blk); -+ return getblk (&inode->file.tree, &inode->file.extents[0], 16, data, blk); - } - - diff --git a/SOURCES/0389-net-tftp-Fix-dangling-memory-pointer.patch b/SOURCES/0389-net-tftp-Fix-dangling-memory-pointer.patch new file mode 100644 index 0000000..193d893 --- /dev/null +++ b/SOURCES/0389-net-tftp-Fix-dangling-memory-pointer.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Fri, 19 Feb 2021 17:12:23 +0000 +Subject: [PATCH] net/tftp: Fix dangling memory pointer + +The static code analysis tool, Parfait, reported that the valid of +file->data was left referencing memory that was freed by the call to +grub_free(data) where data was initialized from file->data. + +To ensure that there is no unintentional access to this memory +referenced by file->data we should set the pointer to NULL. + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/net/tftp.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c +index b9a4b607a3d..aa0424dcee3 100644 +--- a/grub-core/net/tftp.c ++++ b/grub-core/net/tftp.c +@@ -444,6 +444,7 @@ tftp_close (struct grub_file *file) + grub_net_udp_close (data->sock); + } + grub_free (data); ++ file->data = NULL; + return GRUB_ERR_NONE; + } + diff --git a/SOURCES/0390-fs-jfs-Catch-infinite-recursion.patch b/SOURCES/0390-fs-jfs-Catch-infinite-recursion.patch deleted file mode 100644 index dee5914..0000000 --- a/SOURCES/0390-fs-jfs-Catch-infinite-recursion.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Mon, 18 Jan 2021 15:47:24 +1100 -Subject: [PATCH] fs/jfs: Catch infinite recursion - -It's possible with a fuzzed filesystem for JFS to keep getblk()-ing -the same data over and over again, leading to stack exhaustion. - -Check if we'd be calling the function with exactly the same data as -was passed in, and if so abort. - -I'm not sure what the performance impact of this is and am open to -better ideas. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/fs/jfs.c | 11 ++++++++++- - 1 file changed, 10 insertions(+), 1 deletion(-) - -diff --git a/grub-core/fs/jfs.c b/grub-core/fs/jfs.c -index 6e81f37da6c..20d966abfc0 100644 ---- a/grub-core/fs/jfs.c -+++ b/grub-core/fs/jfs.c -@@ -304,7 +304,16 @@ getblk (struct grub_jfs_treehead *treehead, - << (grub_le_to_cpu16 (data->sblock.log2_blksz) - - GRUB_DISK_SECTOR_BITS), 0, - sizeof (*tree), (char *) tree)) -- ret = getblk (&tree->treehead, &tree->extents[0], 254, data, blk); -+ { -+ if (grub_memcmp (&tree->treehead, treehead, sizeof (struct grub_jfs_treehead)) || -+ grub_memcmp (&tree->extents, extents, 254 * sizeof (struct grub_jfs_tree_extent))) -+ ret = getblk (&tree->treehead, &tree->extents[0], 254, data, blk); -+ else -+ { -+ grub_error (GRUB_ERR_BAD_FS, "jfs: infinite recursion detected"); -+ ret = -1; -+ } -+ } - grub_free (tree); - return ret; - } diff --git a/SOURCES/0390-kern-parser-Fix-resource-leak-if-argc-0.patch b/SOURCES/0390-kern-parser-Fix-resource-leak-if-argc-0.patch new file mode 100644 index 0000000..87d3140 --- /dev/null +++ b/SOURCES/0390-kern-parser-Fix-resource-leak-if-argc-0.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Fri, 22 Jan 2021 12:32:41 +0000 +Subject: [PATCH] kern/parser: Fix resource leak if argc == 0 + +After processing the command-line yet arriving at the point where we are +setting argv, we are allocating memory, even if argc == 0, which makes +no sense since we never put anything into the allocated argv. + +The solution is to simply return that we've successfully processed the +arguments but that argc == 0, and also ensure that argv is NULL when +we're not allocating anything in it. + +There are only 2 callers of this function, and both are handling a zero +value in argc assuming nothing is allocated in argv. + +Fixes: CID 96680 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/kern/parser.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/grub-core/kern/parser.c b/grub-core/kern/parser.c +index 619db3122a0..d1cf061ad68 100644 +--- a/grub-core/kern/parser.c ++++ b/grub-core/kern/parser.c +@@ -146,6 +146,7 @@ grub_parser_split_cmdline (const char *cmdline, + int i; + + *argc = 0; ++ *argv = NULL; + do + { + if (!rd || !*rd) +@@ -207,6 +208,10 @@ grub_parser_split_cmdline (const char *cmdline, + (*argc)++; + } + ++ /* If there are no args, then we're done. */ ++ if (!*argc) ++ return 0; ++ + /* Reserve memory for the return values. */ + args = grub_malloc (bp - buffer); + if (!args) diff --git a/SOURCES/0391-fs-nilfs2-Reject-too-large-keys.patch b/SOURCES/0391-fs-nilfs2-Reject-too-large-keys.patch deleted file mode 100644 index 76c864f..0000000 --- a/SOURCES/0391-fs-nilfs2-Reject-too-large-keys.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Mon, 18 Jan 2021 16:49:09 +1100 -Subject: [PATCH] fs/nilfs2: Reject too-large keys - -NILFS2 has up to 7 keys, per the data structure. Do not permit array -indices in excess of that. - -This catches some OOB reads. I don't know how controllable the invalidly -read data is or if that could be used later in the program. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/fs/nilfs2.c | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/grub-core/fs/nilfs2.c b/grub-core/fs/nilfs2.c -index 598a2a55baf..61e8af9ff7b 100644 ---- a/grub-core/fs/nilfs2.c -+++ b/grub-core/fs/nilfs2.c -@@ -569,6 +569,11 @@ grub_nilfs2_btree_lookup (struct grub_nilfs2_data *data, - static inline grub_uint64_t - grub_nilfs2_direct_lookup (struct grub_nilfs2_inode *inode, grub_uint64_t key) - { -+ if (1 + key > 6) -+ { -+ grub_error (GRUB_ERR_BAD_FS, "key is too large"); -+ return 0xffffffffffffffff; -+ } - return grub_le_to_cpu64 (inode->i_bmap[1 + key]); - } - -@@ -584,7 +589,7 @@ grub_nilfs2_bmap_lookup (struct grub_nilfs2_data *data, - { - grub_uint64_t ptr; - ptr = grub_nilfs2_direct_lookup (inode, key); -- if (need_translate) -+ if (ptr != ((grub_uint64_t) 0xffffffffffffffff) && need_translate) - ptr = grub_nilfs2_dat_translate (data, ptr); - return ptr; - } diff --git a/SOURCES/0391-kern-efi-Fix-memory-leak-on-failure.patch b/SOURCES/0391-kern-efi-Fix-memory-leak-on-failure.patch new file mode 100644 index 0000000..1aa52d6 --- /dev/null +++ b/SOURCES/0391-kern-efi-Fix-memory-leak-on-failure.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Thu, 5 Nov 2020 10:15:25 +0000 +Subject: [PATCH] kern/efi: Fix memory leak on failure + +Free the memory allocated to name before returning on failure. + +Fixes: CID 296222 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/kern/efi/efi.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c +index 5dfcf943322..4b95a400490 100644 +--- a/grub-core/kern/efi/efi.c ++++ b/grub-core/kern/efi/efi.c +@@ -400,6 +400,7 @@ grub_efi_get_filename (grub_efi_device_path_t *dp0) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, + "malformed EFI Device Path node has length=%d", len); ++ grub_free (name); + return NULL; + } + diff --git a/SOURCES/0392-fs-nilfs2-Don-t-search-children-if-provided-number-i.patch b/SOURCES/0392-fs-nilfs2-Don-t-search-children-if-provided-number-i.patch deleted file mode 100644 index a46141a..0000000 --- a/SOURCES/0392-fs-nilfs2-Don-t-search-children-if-provided-number-i.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Mon, 18 Jan 2021 16:49:44 +1100 -Subject: [PATCH] fs/nilfs2: Don't search children if provided number is too - large - -NILFS2 reads the number of children a node has from the node. Unfortunately, -that's not trustworthy. Check if it's beyond what the filesystem permits and -reject it if so. - -This blocks some OOB reads. I'm not sure how controllable the read is and what -could be done with invalidly read data later on. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/fs/nilfs2.c | 38 +++++++++++++++++++++++--------------- - 1 file changed, 23 insertions(+), 15 deletions(-) - -diff --git a/grub-core/fs/nilfs2.c b/grub-core/fs/nilfs2.c -index 61e8af9ff7b..054ad3dc18a 100644 ---- a/grub-core/fs/nilfs2.c -+++ b/grub-core/fs/nilfs2.c -@@ -416,14 +416,34 @@ grub_nilfs2_btree_node_get_key (struct grub_nilfs2_btree_node *node, - } - - static inline int --grub_nilfs2_btree_node_lookup (struct grub_nilfs2_btree_node *node, -+grub_nilfs2_btree_node_nchildren_max (struct grub_nilfs2_data *data, -+ struct grub_nilfs2_btree_node *node) -+{ -+ int node_children_max = ((NILFS2_BLOCK_SIZE (data) - -+ sizeof (struct grub_nilfs2_btree_node) - -+ NILFS_BTREE_NODE_EXTRA_PAD_SIZE) / -+ (sizeof (grub_uint64_t) + sizeof (grub_uint64_t))); -+ -+ return (node->bn_flags & NILFS_BTREE_NODE_ROOT) ? 3 : node_children_max; -+} -+ -+static inline int -+grub_nilfs2_btree_node_lookup (struct grub_nilfs2_data *data, -+ struct grub_nilfs2_btree_node *node, - grub_uint64_t key, int *indexp) - { - grub_uint64_t nkey; - int index, low, high, s; - - low = 0; -+ - high = grub_le_to_cpu16 (node->bn_nchildren) - 1; -+ if (high >= grub_nilfs2_btree_node_nchildren_max (data, node)) -+ { -+ grub_error (GRUB_ERR_BAD_FS, "too many children"); -+ return 0; -+ } -+ - index = 0; - s = 0; - while (low <= high) -@@ -459,18 +479,6 @@ grub_nilfs2_btree_node_lookup (struct grub_nilfs2_btree_node *node, - return s == 0; - } - --static inline int --grub_nilfs2_btree_node_nchildren_max (struct grub_nilfs2_data *data, -- struct grub_nilfs2_btree_node *node) --{ -- int node_children_max = ((NILFS2_BLOCK_SIZE (data) - -- sizeof (struct grub_nilfs2_btree_node) - -- NILFS_BTREE_NODE_EXTRA_PAD_SIZE) / -- (sizeof (grub_uint64_t) + sizeof (grub_uint64_t))); -- -- return (node->bn_flags & NILFS_BTREE_NODE_ROOT) ? 3 : node_children_max; --} -- - static inline grub_uint64_t * - grub_nilfs2_btree_node_dptrs (struct grub_nilfs2_data *data, - struct grub_nilfs2_btree_node *node) -@@ -517,7 +525,7 @@ grub_nilfs2_btree_lookup (struct grub_nilfs2_data *data, - node = grub_nilfs2_btree_get_root (inode); - level = grub_nilfs2_btree_get_level (node); - -- found = grub_nilfs2_btree_node_lookup (node, key, &index); -+ found = grub_nilfs2_btree_node_lookup (data, node, key, &index); - ptr = grub_nilfs2_btree_node_get_ptr (data, node, index); - if (need_translate) - ptr = grub_nilfs2_dat_translate (data, ptr); -@@ -538,7 +546,7 @@ grub_nilfs2_btree_lookup (struct grub_nilfs2_data *data, - } - - if (!found) -- found = grub_nilfs2_btree_node_lookup (node, key, &index); -+ found = grub_nilfs2_btree_node_lookup (data, node, key, &index); - else - index = 0; - diff --git a/SOURCES/0392-kern-efi-mm-Fix-possible-NULL-pointer-dereference.patch b/SOURCES/0392-kern-efi-mm-Fix-possible-NULL-pointer-dereference.patch new file mode 100644 index 0000000..5fb25a3 --- /dev/null +++ b/SOURCES/0392-kern-efi-mm-Fix-possible-NULL-pointer-dereference.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Fri, 11 Dec 2020 15:03:13 +0000 +Subject: [PATCH] kern/efi/mm: Fix possible NULL pointer dereference + +The model of grub_efi_get_memory_map() is that if memory_map is NULL, +then the purpose is to discover how much memory should be allocated to +it for the subsequent call. + +The problem here is that with grub_efi_is_finished set to 1, there is no +check at all that the function is being called with a non-NULL memory_map. + +While this MAY be true, we shouldn't assume it. + +The solution to this is to behave as expected, and if memory_map is NULL, +then don't try to use it and allow memory_map_size to be filled in, and +return 0 as is done later in the code if the buffer is too small (or NULL). + +Additionally, drop unneeded ret = 1. + +Fixes: CID 96632 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/kern/efi/mm.c | 23 ++++++++++++++++------- + 1 file changed, 16 insertions(+), 7 deletions(-) + +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index 306924f73a4..2d9c9032b2a 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -372,16 +372,25 @@ grub_efi_get_memory_map (grub_efi_uintn_t *memory_map_size, + if (grub_efi_is_finished) + { + int ret = 1; +- if (*memory_map_size < finish_mmap_size) ++ ++ if (memory_map != NULL) + { +- grub_memcpy (memory_map, finish_mmap_buf, *memory_map_size); ++ if (*memory_map_size < finish_mmap_size) ++ { ++ grub_memcpy (memory_map, finish_mmap_buf, *memory_map_size); ++ ret = 0; ++ } ++ else ++ grub_memcpy (memory_map, finish_mmap_buf, finish_mmap_size); ++ } ++ else ++ { ++ /* ++ * Incomplete, no buffer to copy into, same as ++ * GRUB_EFI_BUFFER_TOO_SMALL below. ++ */ + ret = 0; + } +- else +- { +- grub_memcpy (memory_map, finish_mmap_buf, finish_mmap_size); +- ret = 1; +- } + *memory_map_size = finish_mmap_size; + if (map_key) + *map_key = finish_key; diff --git a/SOURCES/0393-fs-nilfs2-Properly-bail-on-errors-in-grub_nilfs2_btr.patch b/SOURCES/0393-fs-nilfs2-Properly-bail-on-errors-in-grub_nilfs2_btr.patch deleted file mode 100644 index 4f90e76..0000000 --- a/SOURCES/0393-fs-nilfs2-Properly-bail-on-errors-in-grub_nilfs2_btr.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Mon, 18 Jan 2021 17:06:19 +1100 -Subject: [PATCH] fs/nilfs2: Properly bail on errors in - grub_nilfs2_btree_node_lookup() - -We just introduced an error return in grub_nilfs2_btree_node_lookup(). -Make sure the callers catch it. - -At the same time, make sure that grub_nilfs2_btree_node_lookup() always -inits the index pointer passed to it. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/fs/nilfs2.c | 11 ++++++++--- - 1 file changed, 8 insertions(+), 3 deletions(-) - -diff --git a/grub-core/fs/nilfs2.c b/grub-core/fs/nilfs2.c -index 054ad3dc18a..c4c4610bec0 100644 ---- a/grub-core/fs/nilfs2.c -+++ b/grub-core/fs/nilfs2.c -@@ -433,7 +433,7 @@ grub_nilfs2_btree_node_lookup (struct grub_nilfs2_data *data, - grub_uint64_t key, int *indexp) - { - grub_uint64_t nkey; -- int index, low, high, s; -+ int index = 0, low, high, s; - - low = 0; - -@@ -441,10 +441,10 @@ grub_nilfs2_btree_node_lookup (struct grub_nilfs2_data *data, - if (high >= grub_nilfs2_btree_node_nchildren_max (data, node)) - { - grub_error (GRUB_ERR_BAD_FS, "too many children"); -+ *indexp = index; - return 0; - } - -- index = 0; - s = 0; - while (low <= high) - { -@@ -526,6 +526,10 @@ grub_nilfs2_btree_lookup (struct grub_nilfs2_data *data, - level = grub_nilfs2_btree_get_level (node); - - found = grub_nilfs2_btree_node_lookup (data, node, key, &index); -+ -+ if (grub_errno != GRUB_ERR_NONE) -+ goto fail; -+ - ptr = grub_nilfs2_btree_node_get_ptr (data, node, index); - if (need_translate) - ptr = grub_nilfs2_dat_translate (data, ptr); -@@ -550,7 +554,8 @@ grub_nilfs2_btree_lookup (struct grub_nilfs2_data *data, - else - index = 0; - -- if (index < grub_nilfs2_btree_node_nchildren_max (data, node)) -+ if (index < grub_nilfs2_btree_node_nchildren_max (data, node) && -+ grub_errno == GRUB_ERR_NONE) - { - ptr = grub_nilfs2_btree_node_get_ptr (data, node, index); - if (need_translate) diff --git a/SOURCES/0393-gnulib-regexec-Resolve-unused-variable.patch b/SOURCES/0393-gnulib-regexec-Resolve-unused-variable.patch new file mode 100644 index 0000000..226abc8 --- /dev/null +++ b/SOURCES/0393-gnulib-regexec-Resolve-unused-variable.patch @@ -0,0 +1,73 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Wed, 21 Oct 2020 14:41:27 +0000 +Subject: [PATCH] gnulib/regexec: Resolve unused variable + +This is a really minor issue where a variable is being assigned to but +not checked before it is overwritten again. + +The reason for this issue is that we are not building with DEBUG set and +this in turn means that the assert() that reads the value of the +variable match_last is being processed out. + +The solution, move the assignment to match_last in to an ifdef DEBUG too. + +Fixes: CID 292459 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/gnulib/regexec.c | 4 ++++ + conf/Makefile.extra-dist | 1 + + grub-core/gnulib-fix-unused-value.patch | 14 ++++++++++++++ + 3 files changed, 19 insertions(+) + create mode 100644 grub-core/gnulib-fix-unused-value.patch + +diff --git a/grub-core/gnulib/regexec.c b/grub-core/gnulib/regexec.c +index a7776f088f2..9264f262893 100644 +--- a/grub-core/gnulib/regexec.c ++++ b/grub-core/gnulib/regexec.c +@@ -879,7 +879,11 @@ re_search_internal (const regex_t *preg, + break; + if (BE (err != REG_NOMATCH, 0)) + goto free_return; ++#ifdef DEBUG ++ /* Only used for assertion below when DEBUG is set, otherwise ++ it will be over-written when we loop around. */ + match_last = REG_MISSING; ++#endif + } + else + break; /* We found a match. */ +diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist +index 5946ec24a65..b53fe6dfdcc 100644 +--- a/conf/Makefile.extra-dist ++++ b/conf/Makefile.extra-dist +@@ -31,6 +31,7 @@ EXTRA_DIST += grub-core/genemuinit.sh + EXTRA_DIST += grub-core/genemuinitheader.sh + + EXTRA_DIST += grub-core/gnulib-fix-null-deref.diff ++EXTRA_DIST += grub-core/gnulib-fix-unused-value.patch + EXTRA_DIST += grub-core/gnulib-fix-width.diff + EXTRA_DIST += grub-core/gnulib-no-abort.diff + EXTRA_DIST += grub-core/gnulib-no-gets.diff +diff --git a/grub-core/gnulib-fix-unused-value.patch b/grub-core/gnulib-fix-unused-value.patch +new file mode 100644 +index 00000000000..452a8732922 +--- /dev/null ++++ b/grub-core/gnulib-fix-unused-value.patch +@@ -0,0 +1,14 @@ ++--- grub-core/gnulib/regexec.c 2020-10-21 14:25:35.310195912 +0000 +++++ grub-core/gnulib/regexec.c 2020-10-21 14:32:07.961765604 +0000 ++@@ -828,7 +828,11 @@ ++ break; ++ if (BE (err != REG_NOMATCH, 0)) ++ goto free_return; +++#ifdef DEBUG +++ /* Only used for assertion below when DEBUG is set, otherwise +++ it will be over-written when we loop around. */ ++ match_last = REG_MISSING; +++#endif ++ } ++ else ++ break; /* We found a match. */ diff --git a/SOURCES/0394-gnulib-regcomp-Fix-uninitialized-token-structure.patch b/SOURCES/0394-gnulib-regcomp-Fix-uninitialized-token-structure.patch new file mode 100644 index 0000000..b18be72 --- /dev/null +++ b/SOURCES/0394-gnulib-regcomp-Fix-uninitialized-token-structure.patch @@ -0,0 +1,64 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Thu, 22 Oct 2020 13:54:06 +0000 +Subject: [PATCH] gnulib/regcomp: Fix uninitialized token structure + +The code is assuming that the value of br_token.constraint was +initialized to zero when it wasn't. + +While some compilers will ensure that, not all do, so it is better to +fix this explicitly than leave it to chance. + +Fixes: CID 73749 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/gnulib/regcomp.c | 2 +- + conf/Makefile.extra-dist | 1 + + grub-core/gnulib-fix-uninit-structure.patch | 11 +++++++++++ + 3 files changed, 13 insertions(+), 1 deletion(-) + create mode 100644 grub-core/gnulib-fix-uninit-structure.patch + +diff --git a/grub-core/gnulib/regcomp.c b/grub-core/gnulib/regcomp.c +index 596e0cf3ef7..de9f622088f 100644 +--- a/grub-core/gnulib/regcomp.c ++++ b/grub-core/gnulib/regcomp.c +@@ -3641,7 +3641,7 @@ build_charclass_op (re_dfa_t *dfa, RE_TRANSLATE_TYPE trans, + Idx alloc = 0; + #endif /* not RE_ENABLE_I18N */ + reg_errcode_t ret; +- re_token_t br_token; ++ re_token_t br_token = {0}; + bin_tree_t *tree; + + sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); +diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist +index b53fe6dfdcc..883baba56d5 100644 +--- a/conf/Makefile.extra-dist ++++ b/conf/Makefile.extra-dist +@@ -31,6 +31,7 @@ EXTRA_DIST += grub-core/genemuinit.sh + EXTRA_DIST += grub-core/genemuinitheader.sh + + EXTRA_DIST += grub-core/gnulib-fix-null-deref.diff ++EXTRA_DIST += grub-core/gnulib-fix-uninit-structure.patch + EXTRA_DIST += grub-core/gnulib-fix-unused-value.patch + EXTRA_DIST += grub-core/gnulib-fix-width.diff + EXTRA_DIST += grub-core/gnulib-no-abort.diff +diff --git a/grub-core/gnulib-fix-uninit-structure.patch b/grub-core/gnulib-fix-uninit-structure.patch +new file mode 100644 +index 00000000000..7b4d9f67af4 +--- /dev/null ++++ b/grub-core/gnulib-fix-uninit-structure.patch +@@ -0,0 +1,11 @@ ++--- a/lib/regcomp.c 2020-10-22 13:49:06.770168928 +0000 +++++ b/lib/regcomp.c 2020-10-22 13:50:37.026528298 +0000 ++@@ -3662,7 +3662,7 @@ ++ Idx alloc = 0; ++ #endif /* not RE_ENABLE_I18N */ ++ reg_errcode_t ret; ++- re_token_t br_token; +++ re_token_t br_token = {0}; ++ bin_tree_t *tree; ++ ++ sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); diff --git a/SOURCES/0394-io-gzio-Bail-if-gzio-tl-td-is-NULL.patch b/SOURCES/0394-io-gzio-Bail-if-gzio-tl-td-is-NULL.patch deleted file mode 100644 index 43e798d..0000000 --- a/SOURCES/0394-io-gzio-Bail-if-gzio-tl-td-is-NULL.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Wed, 13 Jan 2021 20:59:09 +1100 -Subject: [PATCH] io/gzio: Bail if gzio->tl/td is NULL - -This is an ugly fix that doesn't address why gzio->tl comes to be NULL. -However, it seems to be sufficient to patch up a bunch of NULL derefs. - -It would be good to revisit this in future and see if we can have -a cleaner solution that addresses some of the causes of the unexpected -NULL pointers. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/io/gzio.c | 20 ++++++++++++++++++++ - 1 file changed, 20 insertions(+) - -diff --git a/grub-core/io/gzio.c b/grub-core/io/gzio.c -index 7024cda84ea..b9a93c471b7 100644 ---- a/grub-core/io/gzio.c -+++ b/grub-core/io/gzio.c -@@ -669,6 +669,13 @@ inflate_codes_in_window (grub_gzio_t gzio) - { - if (! gzio->code_state) - { -+ -+ if (gzio->tl == NULL) -+ { -+ grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "NULL gzio->tl"); -+ return 1; -+ } -+ - NEEDBITS ((unsigned) gzio->bl); - if ((e = (t = gzio->tl + ((unsigned) b & ml))->e) > 16) - do -@@ -707,6 +714,12 @@ inflate_codes_in_window (grub_gzio_t gzio) - n = t->v.n + ((unsigned) b & mask_bits[e]); - DUMPBITS (e); - -+ if (gzio->td == NULL) -+ { -+ grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "NULL gzio->td"); -+ return 1; -+ } -+ - /* decode distance of block to copy */ - NEEDBITS ((unsigned) gzio->bd); - if ((e = (t = gzio->td + ((unsigned) b & md))->e) > 16) -@@ -917,6 +930,13 @@ init_dynamic_block (grub_gzio_t gzio) - n = nl + nd; - m = mask_bits[gzio->bl]; - i = l = 0; -+ -+ if (gzio->tl == NULL) -+ { -+ grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "NULL gzio->tl"); -+ return; -+ } -+ - while ((unsigned) i < n) - { - NEEDBITS ((unsigned) gzio->bl); diff --git a/SOURCES/0395-gnulib-argp-help-Fix-dereference-of-a-possibly-NULL-.patch b/SOURCES/0395-gnulib-argp-help-Fix-dereference-of-a-possibly-NULL-.patch new file mode 100644 index 0000000..97f127c --- /dev/null +++ b/SOURCES/0395-gnulib-argp-help-Fix-dereference-of-a-possibly-NULL-.patch @@ -0,0 +1,64 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Wed, 28 Oct 2020 14:43:01 +0000 +Subject: [PATCH] gnulib/argp-help: Fix dereference of a possibly NULL state + +All other instances of call to __argp_failure() where there is +a dgettext() call is first checking whether state is NULL before +attempting to dereference it to get the root_argp->argp_domain. + +Fixes: CID 292436 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/gnulib/argp-help.c | 3 ++- + conf/Makefile.extra-dist | 1 + + grub-core/gnulib-fix-null-state-deref.patch | 12 ++++++++++++ + 3 files changed, 15 insertions(+), 1 deletion(-) + create mode 100644 grub-core/gnulib-fix-null-state-deref.patch + +diff --git a/grub-core/gnulib/argp-help.c b/grub-core/gnulib/argp-help.c +index b9be63f40d2..8af8be07341 100644 +--- a/grub-core/gnulib/argp-help.c ++++ b/grub-core/gnulib/argp-help.c +@@ -145,7 +145,8 @@ validate_uparams (const struct argp_state *state, struct uparams *upptr) + if (*(int *)((char *)upptr + up->uparams_offs) >= upptr->rmargin) + { + __argp_failure (state, 0, 0, +- dgettext (state->root_argp->argp_domain, ++ dgettext (state == NULL ? NULL ++ : state->root_argp->argp_domain, + "\ + ARGP_HELP_FMT: %s value is less than or equal to %s"), + "rmargin", up->name); +diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist +index 883baba56d5..06606de8d19 100644 +--- a/conf/Makefile.extra-dist ++++ b/conf/Makefile.extra-dist +@@ -31,6 +31,7 @@ EXTRA_DIST += grub-core/genemuinit.sh + EXTRA_DIST += grub-core/genemuinitheader.sh + + EXTRA_DIST += grub-core/gnulib-fix-null-deref.diff ++EXTRA_DIST += grub-core/gnulib-fix-null-state-deref.patch + EXTRA_DIST += grub-core/gnulib-fix-uninit-structure.patch + EXTRA_DIST += grub-core/gnulib-fix-unused-value.patch + EXTRA_DIST += grub-core/gnulib-fix-width.diff +diff --git a/grub-core/gnulib-fix-null-state-deref.patch b/grub-core/gnulib-fix-null-state-deref.patch +new file mode 100644 +index 00000000000..813ec09c8a1 +--- /dev/null ++++ b/grub-core/gnulib-fix-null-state-deref.patch +@@ -0,0 +1,12 @@ ++--- a/lib/argp-help.c 2020-10-28 14:32:19.189215988 +0000 +++++ b/lib/argp-help.c 2020-10-28 14:38:21.204673940 +0000 ++@@ -145,7 +145,8 @@ ++ if (*(int *)((char *)upptr + up->uparams_offs) >= upptr->rmargin) ++ { ++ __argp_failure (state, 0, 0, ++- dgettext (state->root_argp->argp_domain, +++ dgettext (state == NULL ? NULL +++ : state->root_argp->argp_domain, ++ "\ ++ ARGP_HELP_FMT: %s value is less than or equal to %s"), ++ "rmargin", up->name); diff --git a/SOURCES/0395-io-gzio-Add-init_dynamic_block-clean-up-if-unpacking.patch b/SOURCES/0395-io-gzio-Add-init_dynamic_block-clean-up-if-unpacking.patch deleted file mode 100644 index 71cfb66..0000000 --- a/SOURCES/0395-io-gzio-Add-init_dynamic_block-clean-up-if-unpacking.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Thu, 21 Jan 2021 00:05:58 +1100 -Subject: [PATCH] io/gzio: Add init_dynamic_block() clean up if unpacking codes - fails - -init_dynamic_block() didn't clean up gzio->tl and td in some error -paths. This left td pointing to part of tl. Then in grub_gzio_close(), -when tl was freed the storage for td would also be freed. The code then -attempts to free td explicitly, performing a UAF and then a double free. - -Explicitly clean up tl and td in the error paths. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/io/gzio.c | 12 +++++++++--- - 1 file changed, 9 insertions(+), 3 deletions(-) - -diff --git a/grub-core/io/gzio.c b/grub-core/io/gzio.c -index b9a93c471b7..389fd345488 100644 ---- a/grub-core/io/gzio.c -+++ b/grub-core/io/gzio.c -@@ -953,7 +953,7 @@ init_dynamic_block (grub_gzio_t gzio) - if ((unsigned) i + j > n) - { - grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "too many codes found"); -- return; -+ goto fail; - } - while (j--) - ll[i++] = l; -@@ -966,7 +966,7 @@ init_dynamic_block (grub_gzio_t gzio) - if ((unsigned) i + j > n) - { - grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "too many codes found"); -- return; -+ goto fail; - } - while (j--) - ll[i++] = 0; -@@ -981,7 +981,7 @@ init_dynamic_block (grub_gzio_t gzio) - if ((unsigned) i + j > n) - { - grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "too many codes found"); -- return; -+ goto fail; - } - while (j--) - ll[i++] = 0; -@@ -1019,6 +1019,12 @@ init_dynamic_block (grub_gzio_t gzio) - /* indicate we're now working on a block */ - gzio->code_state = 0; - gzio->block_len++; -+ return; -+ -+ fail: -+ huft_free (gzio->tl); -+ gzio->td = NULL; -+ gzio->tl = NULL; - } - - diff --git a/SOURCES/0396-gnulib-regexec-Fix-possible-null-dereference.patch b/SOURCES/0396-gnulib-regexec-Fix-possible-null-dereference.patch new file mode 100644 index 0000000..78ae2b9 --- /dev/null +++ b/SOURCES/0396-gnulib-regexec-Fix-possible-null-dereference.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Thu, 5 Nov 2020 10:57:14 +0000 +Subject: [PATCH] gnulib/regexec: Fix possible null-dereference + +It appears to be possible that the mctx->state_log field may be NULL, +and the name of this function, clean_state_log_if_needed(), suggests +that it should be checking that it is valid to be cleaned before +assuming that it does. + +Fixes: CID 86720 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/gnulib/regexec.c | 3 +++ + conf/Makefile.extra-dist | 1 + + grub-core/gnulib-fix-regexec-null-deref.patch | 12 ++++++++++++ + 3 files changed, 16 insertions(+) + create mode 100644 grub-core/gnulib-fix-regexec-null-deref.patch + +diff --git a/grub-core/gnulib/regexec.c b/grub-core/gnulib/regexec.c +index 9264f262893..fdacff12ce3 100644 +--- a/grub-core/gnulib/regexec.c ++++ b/grub-core/gnulib/regexec.c +@@ -1754,6 +1754,9 @@ clean_state_log_if_needed (re_match_context_t *mctx, Idx next_state_log_idx) + { + Idx top = mctx->state_log_top; + ++ if (mctx->state_log == NULL) ++ return REG_NOERROR; ++ + if ((next_state_log_idx >= mctx->input.bufs_len + && mctx->input.bufs_len < mctx->input.len) + || (next_state_log_idx >= mctx->input.valid_len +diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist +index 06606de8d19..edbe7846eb1 100644 +--- a/conf/Makefile.extra-dist ++++ b/conf/Makefile.extra-dist +@@ -32,6 +32,7 @@ EXTRA_DIST += grub-core/genemuinitheader.sh + + EXTRA_DIST += grub-core/gnulib-fix-null-deref.diff + EXTRA_DIST += grub-core/gnulib-fix-null-state-deref.patch ++EXTRA_DIST += grub-core/gnulib-fix-regexec-null-deref.patch + EXTRA_DIST += grub-core/gnulib-fix-uninit-structure.patch + EXTRA_DIST += grub-core/gnulib-fix-unused-value.patch + EXTRA_DIST += grub-core/gnulib-fix-width.diff +diff --git a/grub-core/gnulib-fix-regexec-null-deref.patch b/grub-core/gnulib-fix-regexec-null-deref.patch +new file mode 100644 +index 00000000000..db6dac9c9e3 +--- /dev/null ++++ b/grub-core/gnulib-fix-regexec-null-deref.patch +@@ -0,0 +1,12 @@ ++--- a/lib/regexec.c 2020-10-21 14:25:35.310195912 +0000 +++++ b/lib/regexec.c 2020-11-05 10:55:09.621542984 +0000 ++@@ -1692,6 +1692,9 @@ ++ { ++ Idx top = mctx->state_log_top; ++ +++ if (mctx->state_log == NULL) +++ return REG_NOERROR; +++ ++ if ((next_state_log_idx >= mctx->input.bufs_len ++ && mctx->input.bufs_len < mctx->input.len) ++ || (next_state_log_idx >= mctx->input.valid_len diff --git a/SOURCES/0396-io-gzio-Catch-missing-values-in-huft_build-and-bail.patch b/SOURCES/0396-io-gzio-Catch-missing-values-in-huft_build-and-bail.patch deleted file mode 100644 index 4f523d8..0000000 --- a/SOURCES/0396-io-gzio-Catch-missing-values-in-huft_build-and-bail.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Thu, 21 Jan 2021 12:20:49 +1100 -Subject: [PATCH] io/gzio: Catch missing values in huft_build() and bail - -In huft_build(), "v" is a table of values in order of bit length. -The code later (when setting up table entries in "r") assumes that all -elements of this array corresponding to a code are initialized and less -than N_MAX. However, it doesn't enforce this. - -With sufficiently manipulated inputs (e.g. from fuzzing), there can be -elements of "v" that are not filled. Therefore a lookup into "e" or "d" -will use an uninitialized value. This can lead to an invalid/OOB read on -those values, often leading to a crash. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/io/gzio.c | 10 +++++++++- - 1 file changed, 9 insertions(+), 1 deletion(-) - -diff --git a/grub-core/io/gzio.c b/grub-core/io/gzio.c -index 389fd345488..fa7d9990b84 100644 ---- a/grub-core/io/gzio.c -+++ b/grub-core/io/gzio.c -@@ -507,6 +507,7 @@ huft_build (unsigned *b, /* code lengths in bits (all assumed <= BMAX) */ - } - - /* Make a table of values in order of bit lengths */ -+ grub_memset (v, N_MAX, ARRAY_SIZE (v)); - p = b; - i = 0; - do -@@ -588,11 +589,18 @@ huft_build (unsigned *b, /* code lengths in bits (all assumed <= BMAX) */ - r.v.n = (ush) (*p); /* simple code is just the value */ - p++; /* one compiler does not like *p++ */ - } -- else -+ else if (*p < N_MAX) - { - r.e = (uch) e[*p - s]; /* non-simple--look up in lists */ - r.v.n = d[*p++ - s]; - } -+ else -+ { -+ /* Detected an uninitialised value, abort. */ -+ if (h) -+ huft_free (u[0]); -+ return 2; -+ } - - /* fill code-like entries with r */ - f = 1 << (k - w); diff --git a/SOURCES/0397-gnulib-regcomp-Fix-uninitialized-re_token.patch b/SOURCES/0397-gnulib-regcomp-Fix-uninitialized-re_token.patch new file mode 100644 index 0000000..342a020 --- /dev/null +++ b/SOURCES/0397-gnulib-regcomp-Fix-uninitialized-re_token.patch @@ -0,0 +1,64 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Tue, 24 Nov 2020 18:04:22 +0000 +Subject: [PATCH] gnulib/regcomp: Fix uninitialized re_token + +This issue has been fixed in the latest version of gnulib, so to +maintain consistency, I've backported that change rather than doing +something different. + +Fixes: CID 73828 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/gnulib/regcomp.c | 3 +-- + conf/Makefile.extra-dist | 1 + + grub-core/gnulib-fix-regcomp-uninit-token.patch | 12 ++++++++++++ + 3 files changed, 14 insertions(+), 2 deletions(-) + create mode 100644 grub-core/gnulib-fix-regcomp-uninit-token.patch + +diff --git a/grub-core/gnulib/regcomp.c b/grub-core/gnulib/regcomp.c +index de9f622088f..6d0830ac691 100644 +--- a/grub-core/gnulib/regcomp.c ++++ b/grub-core/gnulib/regcomp.c +@@ -3790,8 +3790,7 @@ static bin_tree_t * + create_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, + re_token_type_t type) + { +- re_token_t t; +- t.type = type; ++ re_token_t t = { .type = type }; + return create_token_tree (dfa, left, right, &t); + } + +diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist +index edbe7846eb1..ee276a87764 100644 +--- a/conf/Makefile.extra-dist ++++ b/conf/Makefile.extra-dist +@@ -32,6 +32,7 @@ EXTRA_DIST += grub-core/genemuinitheader.sh + + EXTRA_DIST += grub-core/gnulib-fix-null-deref.diff + EXTRA_DIST += grub-core/gnulib-fix-null-state-deref.patch ++EXTRA_DIST += grub-core/gnulib-fix-regcomp-uninit-token.patch + EXTRA_DIST += grub-core/gnulib-fix-regexec-null-deref.patch + EXTRA_DIST += grub-core/gnulib-fix-uninit-structure.patch + EXTRA_DIST += grub-core/gnulib-fix-unused-value.patch +diff --git a/grub-core/gnulib-fix-regcomp-uninit-token.patch b/grub-core/gnulib-fix-regcomp-uninit-token.patch +new file mode 100644 +index 00000000000..d615745221b +--- /dev/null ++++ b/grub-core/gnulib-fix-regcomp-uninit-token.patch +@@ -0,0 +1,12 @@ ++--- grub-core/gnulib/regcomp.c +++++ grub-core/gnulib/regcomp.c ++@@ -3808,8 +3808,7 @@ static bin_tree_t * ++ create_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, ++ re_token_type_t type) ++ { ++- re_token_t t; ++- t.type = type; +++ re_token_t t = { .type = type }; ++ return create_token_tree (dfa, left, right, &t); ++ } ++ diff --git a/SOURCES/0397-io-gzio-Zero-gzio-tl-td-in-init_dynamic_block-if-huf.patch b/SOURCES/0397-io-gzio-Zero-gzio-tl-td-in-init_dynamic_block-if-huf.patch deleted file mode 100644 index a2a2efc..0000000 --- a/SOURCES/0397-io-gzio-Zero-gzio-tl-td-in-init_dynamic_block-if-huf.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Thu, 21 Jan 2021 12:22:28 +1100 -Subject: [PATCH] io/gzio: Zero gzio->tl/td in init_dynamic_block() if - huft_build() fails - -If huft_build() fails, gzio->tl or gzio->td could contain pointers that -are no longer valid. Zero them out. - -This prevents a double free when grub_gzio_close() comes through and -attempts to free them again. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/io/gzio.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/grub-core/io/gzio.c b/grub-core/io/gzio.c -index fa7d9990b84..81d658818be 100644 ---- a/grub-core/io/gzio.c -+++ b/grub-core/io/gzio.c -@@ -1010,6 +1010,7 @@ init_dynamic_block (grub_gzio_t gzio) - gzio->bl = lbits; - if (huft_build (ll, nl, 257, cplens, cplext, &gzio->tl, &gzio->bl) != 0) - { -+ gzio->tl = 0; - grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, - "failed in building a Huffman code table"); - return; -@@ -1019,6 +1020,7 @@ init_dynamic_block (grub_gzio_t gzio) - { - huft_free (gzio->tl); - gzio->tl = 0; -+ gzio->td = 0; - grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, - "failed in building a Huffman code table"); - return; diff --git a/SOURCES/0398-disk-lvm-Don-t-go-beyond-the-end-of-the-data-we-read.patch b/SOURCES/0398-disk-lvm-Don-t-go-beyond-the-end-of-the-data-we-read.patch deleted file mode 100644 index 3a8cb85..0000000 --- a/SOURCES/0398-disk-lvm-Don-t-go-beyond-the-end-of-the-data-we-read.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Thu, 21 Jan 2021 17:59:14 +1100 -Subject: [PATCH] disk/lvm: Don't go beyond the end of the data we read from - disk - -We unconditionally trusted offset_xl from the LVM label header, even if -it told us that the PV header/disk locations were way off past the end -of the data we read from disk. - -Require that the offset be sane, fixing an OOB read and crash. - -Fixes: CID 314367, CID 314371 - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/disk/lvm.c | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - -diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c -index 4fbb3eac0ea..0f466040a55 100644 ---- a/grub-core/disk/lvm.c -+++ b/grub-core/disk/lvm.c -@@ -142,6 +142,20 @@ grub_lvm_detect (grub_disk_t disk, - goto fail; - } - -+ /* -+ * We read a grub_lvm_pv_header and then 2 grub_lvm_disk_locns that -+ * immediately follow the PV header. Make sure we have space for both. -+ */ -+ if (grub_le_to_cpu32 (lh->offset_xl) >= -+ GRUB_LVM_LABEL_SIZE - sizeof (struct grub_lvm_pv_header) - -+ 2 * sizeof (struct grub_lvm_disk_locn)) -+ { -+#ifdef GRUB_UTIL -+ grub_util_info ("LVM PV header/disk locations are beyond the end of the block"); -+#endif -+ goto fail; -+ } -+ - pvh = (struct grub_lvm_pv_header *) (buf + grub_le_to_cpu32(lh->offset_xl)); - - for (i = 0, j = 0; i < GRUB_LVM_ID_LEN; i++) diff --git a/SOURCES/0398-io-lzopio-Resolve-unnecessary-self-assignment-errors.patch b/SOURCES/0398-io-lzopio-Resolve-unnecessary-self-assignment-errors.patch new file mode 100644 index 0000000..d7affbd --- /dev/null +++ b/SOURCES/0398-io-lzopio-Resolve-unnecessary-self-assignment-errors.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Wed, 21 Oct 2020 14:44:10 +0000 +Subject: [PATCH] io/lzopio: Resolve unnecessary self-assignment errors + +These 2 assignments are unnecessary since they are just assigning +to themselves. + +Fixes: CID 73643 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/io/lzopio.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/grub-core/io/lzopio.c b/grub-core/io/lzopio.c +index 84edf6dd2dc..6bf14daf474 100644 +--- a/grub-core/io/lzopio.c ++++ b/grub-core/io/lzopio.c +@@ -125,8 +125,6 @@ read_block_header (struct grub_lzopio *lzopio) + sizeof (lzopio->block.ucheck)) != + sizeof (lzopio->block.ucheck)) + return -1; +- +- lzopio->block.ucheck = lzopio->block.ucheck; + } + + /* Read checksum of compressed data. */ +@@ -143,8 +141,6 @@ read_block_header (struct grub_lzopio *lzopio) + sizeof (lzopio->block.ccheck)) != + sizeof (lzopio->block.ccheck)) + return -1; +- +- lzopio->block.ccheck = lzopio->block.ccheck; + } + } + diff --git a/SOURCES/0399-disk-lvm-Don-t-blast-past-the-end-of-the-circular-me.patch b/SOURCES/0399-disk-lvm-Don-t-blast-past-the-end-of-the-circular-me.patch deleted file mode 100644 index 8793efc..0000000 --- a/SOURCES/0399-disk-lvm-Don-t-blast-past-the-end-of-the-circular-me.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Thu, 21 Jan 2021 18:19:51 +1100 -Subject: [PATCH] disk/lvm: Don't blast past the end of the circular metadata - buffer - -This catches at least some OOB reads, and it's possible I suppose that -if 2 * mda_size is less than GRUB_LVM_MDA_HEADER_SIZE it might catch some -OOB writes too (although that hasn't showed up as a crash in fuzzing yet). - -It's a bit ugly and I'd appreciate better suggestions. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/disk/lvm.c | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c -index 0f466040a55..ec3545e164b 100644 ---- a/grub-core/disk/lvm.c -+++ b/grub-core/disk/lvm.c -@@ -215,6 +215,16 @@ grub_lvm_detect (grub_disk_t disk, - if (grub_le_to_cpu64 (rlocn->offset) + grub_le_to_cpu64 (rlocn->size) > - grub_le_to_cpu64 (mdah->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; -+ } -+ - /* Metadata is circular. Copy the wrap in place. */ - grub_memcpy (metadatabuf + mda_size, - metadatabuf + GRUB_LVM_MDA_HEADER_SIZE, diff --git a/SOURCES/0399-kern-partition-Check-for-NULL-before-dereferencing-i.patch b/SOURCES/0399-kern-partition-Check-for-NULL-before-dereferencing-i.patch new file mode 100644 index 0000000..35c4c01 --- /dev/null +++ b/SOURCES/0399-kern-partition-Check-for-NULL-before-dereferencing-i.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Fri, 23 Oct 2020 09:49:59 +0000 +Subject: [PATCH] kern/partition: Check for NULL before dereferencing input + string + +There is the possibility that the value of str comes from an external +source and continuing to use it before ever checking its validity is +wrong. So, needs fixing. + +Additionally, drop unneeded part initialization. + +Fixes: CID 292444 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/kern/partition.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/grub-core/kern/partition.c b/grub-core/kern/partition.c +index 2c401b866c4..3068c4dcac0 100644 +--- a/grub-core/kern/partition.c ++++ b/grub-core/kern/partition.c +@@ -109,11 +109,14 @@ grub_partition_map_probe (const grub_partition_map_t partmap, + grub_partition_t + grub_partition_probe (struct grub_disk *disk, const char *str) + { +- grub_partition_t part = 0; ++ grub_partition_t part; + grub_partition_t curpart = 0; + grub_partition_t tail; + const char *ptr; + ++ if (str == NULL) ++ return 0; ++ + part = tail = disk->partition; + + for (ptr = str; *ptr;) diff --git a/SOURCES/0400-disk-ldm-Make-sure-comp-data-is-freed-before-exiting.patch b/SOURCES/0400-disk-ldm-Make-sure-comp-data-is-freed-before-exiting.patch new file mode 100644 index 0000000..7d4ea0e --- /dev/null +++ b/SOURCES/0400-disk-ldm-Make-sure-comp-data-is-freed-before-exiting.patch @@ -0,0 +1,125 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Marco A Benatto +Date: Mon, 7 Dec 2020 11:53:03 -0300 +Subject: [PATCH] disk/ldm: Make sure comp data is freed before exiting from + make_vg() + +Several error handling paths in make_vg() do not free comp data before +jumping to fail2 label and returning from the function. This will leak +memory. So, let's fix all issues of that kind. + +Fixes: CID 73804 + +Signed-off-by: Marco A Benatto +Reviewed-by: Daniel Kiper +--- + grub-core/disk/ldm.c | 51 ++++++++++++++++++++++++++++++++++++++++++++------- + 1 file changed, 44 insertions(+), 7 deletions(-) + +diff --git a/grub-core/disk/ldm.c b/grub-core/disk/ldm.c +index 58f8a53e1ab..428415fac24 100644 +--- a/grub-core/disk/ldm.c ++++ b/grub-core/disk/ldm.c +@@ -554,7 +554,11 @@ make_vg (grub_disk_t disk, + comp->segments = grub_calloc (comp->segment_alloc, + sizeof (*comp->segments)); + if (!comp->segments) +- goto fail2; ++ { ++ grub_free (comp->internal_id); ++ grub_free (comp); ++ goto fail2; ++ } + } + else + { +@@ -562,7 +566,11 @@ make_vg (grub_disk_t disk, + comp->segment_count = 1; + comp->segments = grub_malloc (sizeof (*comp->segments)); + if (!comp->segments) +- goto fail2; ++ { ++ grub_free (comp->internal_id); ++ grub_free (comp); ++ goto fail2; ++ } + comp->segments->start_extent = 0; + comp->segments->extent_count = lv->size; + comp->segments->layout = 0; +@@ -574,15 +582,26 @@ make_vg (grub_disk_t disk, + comp->segments->layout = GRUB_RAID_LAYOUT_SYMMETRIC_MASK; + } + else +- goto fail2; ++ { ++ grub_free (comp->segments); ++ grub_free (comp->internal_id); ++ grub_free (comp); ++ goto fail2; ++ } + ptr += *ptr + 1; + ptr++; + if (!(vblk[i].flags & 0x10)) +- goto fail2; ++ { ++ grub_free (comp->segments); ++ grub_free (comp->internal_id); ++ grub_free (comp); ++ goto fail2; ++ } + if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic) + || ptr + *ptr + 1 >= vblk[i].dynamic + + sizeof (vblk[i].dynamic)) + { ++ grub_free (comp->segments); + grub_free (comp->internal_id); + grub_free (comp); + goto fail2; +@@ -592,6 +611,7 @@ make_vg (grub_disk_t disk, + if (ptr + *ptr + 1 >= vblk[i].dynamic + + sizeof (vblk[i].dynamic)) + { ++ grub_free (comp->segments); + grub_free (comp->internal_id); + grub_free (comp); + goto fail2; +@@ -601,7 +621,12 @@ make_vg (grub_disk_t disk, + comp->segments->nodes = grub_calloc (comp->segments->node_alloc, + sizeof (*comp->segments->nodes)); + if (!lv->segments->nodes) +- goto fail2; ++ { ++ grub_free (comp->segments); ++ grub_free (comp->internal_id); ++ grub_free (comp); ++ goto fail2; ++ } + } + + if (lv->segments->node_alloc == lv->segments->node_count) +@@ -611,11 +636,23 @@ make_vg (grub_disk_t disk, + + if (grub_mul (lv->segments->node_alloc, 2, &lv->segments->node_alloc) || + grub_mul (lv->segments->node_alloc, sizeof (*lv->segments->nodes), &sz)) +- goto fail2; ++ { ++ grub_free (comp->segments->nodes); ++ grub_free (comp->segments); ++ grub_free (comp->internal_id); ++ grub_free (comp); ++ goto fail2; ++ } + + t = grub_realloc (lv->segments->nodes, sz); + if (!t) +- goto fail2; ++ { ++ grub_free (comp->segments->nodes); ++ grub_free (comp->segments); ++ grub_free (comp->internal_id); ++ grub_free (comp); ++ goto fail2; ++ } + lv->segments->nodes = t; + } + lv->segments->nodes[lv->segments->node_count].pv = 0; diff --git a/SOURCES/0400-disk-lvm-Bail-on-missing-PV-list.patch b/SOURCES/0400-disk-lvm-Bail-on-missing-PV-list.patch deleted file mode 100644 index 621266b..0000000 --- a/SOURCES/0400-disk-lvm-Bail-on-missing-PV-list.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Thu, 21 Jan 2021 18:54:29 +1100 -Subject: [PATCH] disk/lvm: Bail on missing PV list - -There's an if block for the presence of "physical_volumes {", but if -that block is absent, then p remains NULL and a NULL-deref will result -when looking for logical volumes. - -It doesn't seem like LVM makes sense without physical volumes, so error -out rather than crashing. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/disk/lvm.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c -index ec3545e164b..1e80137c452 100644 ---- a/grub-core/disk/lvm.c -+++ b/grub-core/disk/lvm.c -@@ -371,6 +371,8 @@ error_parsing_metadata: - goto fail4; - } - } -+ else -+ goto fail4; - - p = grub_strstr (p, "logical_volumes {"); - if (p) diff --git a/SOURCES/0401-disk-ldm-If-failed-then-free-vg-variable-too.patch b/SOURCES/0401-disk-ldm-If-failed-then-free-vg-variable-too.patch new file mode 100644 index 0000000..6b8903a --- /dev/null +++ b/SOURCES/0401-disk-ldm-If-failed-then-free-vg-variable-too.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paulo Flabiano Smorigo +Date: Mon, 7 Dec 2020 10:07:47 -0300 +Subject: [PATCH] disk/ldm: If failed then free vg variable too + +Fixes: CID 73809 + +Signed-off-by: Paulo Flabiano Smorigo +Reviewed-by: Daniel Kiper +--- + grub-core/disk/ldm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/grub-core/disk/ldm.c b/grub-core/disk/ldm.c +index 428415fac24..54713f45a12 100644 +--- a/grub-core/disk/ldm.c ++++ b/grub-core/disk/ldm.c +@@ -199,6 +199,7 @@ make_vg (grub_disk_t disk, + { + grub_free (vg->uuid); + grub_free (vg->name); ++ grub_free (vg); + return NULL; + } + grub_memcpy (vg->uuid, label->group_guid, LDM_GUID_STRLEN); diff --git a/SOURCES/0401-disk-lvm-Do-not-crash-if-an-expected-string-is-not-f.patch b/SOURCES/0401-disk-lvm-Do-not-crash-if-an-expected-string-is-not-f.patch deleted file mode 100644 index 2ca0659..0000000 --- a/SOURCES/0401-disk-lvm-Do-not-crash-if-an-expected-string-is-not-f.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Thu, 21 Jan 2021 18:35:22 +1100 -Subject: [PATCH] disk/lvm: Do not crash if an expected string is not found - -Clean up a bunch of cases where we could have strstr() fail and lead to -us dereferencing NULL. - -We'll still leak memory in some cases (loops don't clean up allocations -from earlier iterations if a later iteration fails) but at least we're -not crashing. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/disk/lvm.c | 22 +++++++++++++++++----- - 1 file changed, 17 insertions(+), 5 deletions(-) - -diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c -index 1e80137c452..03587e744dc 100644 ---- a/grub-core/disk/lvm.c -+++ b/grub-core/disk/lvm.c -@@ -541,7 +541,16 @@ error_parsing_metadata: - } - - if (seg->node_count != 1) -- seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = "); -+ { -+ seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = "); -+ if (p == NULL) -+ { -+#ifdef GRUB_UTIL -+ grub_util_info ("unknown stripe_size"); -+#endif -+ goto lvs_segment_fail; -+ } -+ } - - seg->nodes = grub_calloc (seg->node_count, - sizeof (*stripe)); -@@ -561,7 +570,7 @@ error_parsing_metadata: - { - p = grub_strchr (p, '"'); - if (p == NULL) -- continue; -+ goto lvs_segment_fail2; - q = ++p; - while (*q != '"') - q++; -@@ -580,7 +589,10 @@ error_parsing_metadata: - stripe->start = grub_lvm_getvalue (&p, ",") - * vg->extent_size; - if (p == NULL) -- continue; -+ { -+ grub_free (stripe->name); -+ goto lvs_segment_fail2; -+ } - - stripe++; - } -@@ -617,7 +629,7 @@ error_parsing_metadata: - - p = grub_strchr (p, '"'); - if (p == NULL) -- continue; -+ goto lvs_segment_fail2; - q = ++p; - while (*q != '"') - q++; -@@ -705,7 +717,7 @@ error_parsing_metadata: - p = p ? grub_strchr (p + 1, '"') : 0; - p = p ? grub_strchr (p + 1, '"') : 0; - if (p == NULL) -- continue; -+ goto lvs_segment_fail2; - q = ++p; - while (*q != '"') - q++; diff --git a/SOURCES/0402-disk-ldm-Fix-memory-leak-on-uninserted-lv-references.patch b/SOURCES/0402-disk-ldm-Fix-memory-leak-on-uninserted-lv-references.patch new file mode 100644 index 0000000..3b0add6 --- /dev/null +++ b/SOURCES/0402-disk-ldm-Fix-memory-leak-on-uninserted-lv-references.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Tue, 8 Dec 2020 10:00:51 +0000 +Subject: [PATCH] disk/ldm: Fix memory leak on uninserted lv references + +The problem here is that the memory allocated to the variable lv is not +yet inserted into the list that is being processed at the label fail2. + +As we can already see at line 342, which correctly frees lv before going +to fail2, we should also be doing that at these earlier jumps to fail2. + +Fixes: CID 73824 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/disk/ldm.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/grub-core/disk/ldm.c b/grub-core/disk/ldm.c +index 54713f45a12..e82e9899f96 100644 +--- a/grub-core/disk/ldm.c ++++ b/grub-core/disk/ldm.c +@@ -321,7 +321,10 @@ make_vg (grub_disk_t disk, + lv->visible = 1; + lv->segments = grub_zalloc (sizeof (*lv->segments)); + if (!lv->segments) +- goto fail2; ++ { ++ grub_free (lv); ++ goto fail2; ++ } + lv->segments->start_extent = 0; + lv->segments->type = GRUB_DISKFILTER_MIRROR; + lv->segments->node_count = 0; +@@ -329,7 +332,10 @@ make_vg (grub_disk_t disk, + lv->segments->nodes = grub_calloc (lv->segments->node_alloc, + sizeof (*lv->segments->nodes)); + if (!lv->segments->nodes) +- goto fail2; ++ { ++ grub_free (lv); ++ goto fail2; ++ } + ptr = vblk[i].dynamic; + if (ptr + *ptr + 1 >= vblk[i].dynamic + + sizeof (vblk[i].dynamic)) diff --git a/SOURCES/0402-disk-lvm-Do-not-overread-metadata.patch b/SOURCES/0402-disk-lvm-Do-not-overread-metadata.patch deleted file mode 100644 index 2138f6c..0000000 --- a/SOURCES/0402-disk-lvm-Do-not-overread-metadata.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Thu, 21 Jan 2021 18:35:22 +1100 -Subject: [PATCH] disk/lvm: Do not overread metadata - -We could reach the end of valid metadata and not realize, leading to -some buffer overreads. Check if we have reached the end and bail. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/disk/lvm.c | 31 +++++++++++++++++++++++++------ - 1 file changed, 25 insertions(+), 6 deletions(-) - -diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c -index 03587e744dc..267be7b9536 100644 ---- a/grub-core/disk/lvm.c -+++ b/grub-core/disk/lvm.c -@@ -314,17 +314,23 @@ error_parsing_metadata: - while (1) - { - grub_ssize_t s; -- while (grub_isspace (*p)) -+ while (grub_isspace (*p) && p < mda_end) - p++; - -+ if (p == mda_end) -+ goto fail4; -+ - if (*p == '}') - break; - - pv = grub_zalloc (sizeof (*pv)); - q = p; -- while (*q != ' ') -+ while (*q != ' ' && q < mda_end) - q++; - -+ if (q == mda_end) -+ goto pvs_fail_noname; -+ - s = q - p; - pv->name = grub_malloc (s + 1); - grub_memcpy (pv->name, p, s); -@@ -367,6 +373,7 @@ error_parsing_metadata: - continue; - pvs_fail: - grub_free (pv->name); -+ pvs_fail_noname: - grub_free (pv); - goto fail4; - } -@@ -388,18 +395,24 @@ error_parsing_metadata: - struct grub_diskfilter_segment *seg; - int is_pvmove; - -- while (grub_isspace (*p)) -+ while (grub_isspace (*p) && p < mda_end) - p++; - -+ if (p == mda_end) -+ goto fail4; -+ - if (*p == '}') - break; - - lv = grub_zalloc (sizeof (*lv)); - - q = p; -- while (*q != ' ') -+ while (*q != ' ' && q < mda_end) - q++; - -+ if (q == mda_end) -+ goto lvs_fail; -+ - s = q - p; - lv->name = grub_strndup (p, s); - if (!lv->name) -@@ -572,9 +585,12 @@ error_parsing_metadata: - if (p == NULL) - goto lvs_segment_fail2; - q = ++p; -- while (*q != '"') -+ while (q < mda_end && *q != '"') - q++; - -+ if (q == mda_end) -+ goto lvs_segment_fail2; -+ - s = q - p; - - stripe->name = grub_malloc (s + 1); -@@ -631,9 +647,12 @@ error_parsing_metadata: - if (p == NULL) - goto lvs_segment_fail2; - q = ++p; -- while (*q != '"') -+ while (q < mda_end && *q != '"') - q++; - -+ if (q == mda_end) -+ goto lvs_segment_fail2; -+ - s = q - p; - - lvname = grub_malloc (s + 1); diff --git a/SOURCES/0403-disk-cryptodisk-Fix-potential-integer-overflow.patch b/SOURCES/0403-disk-cryptodisk-Fix-potential-integer-overflow.patch new file mode 100644 index 0000000..2470dc5 --- /dev/null +++ b/SOURCES/0403-disk-cryptodisk-Fix-potential-integer-overflow.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Thu, 21 Jan 2021 11:38:31 +0000 +Subject: [PATCH] disk/cryptodisk: Fix potential integer overflow + +The encrypt and decrypt functions expect a grub_size_t. So, we need to +ensure that the constant bit shift is using grub_size_t rather than +unsigned int when it is performing the shift. + +Fixes: CID 307788 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index bd60a66b384..78a902515e9 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -311,10 +311,10 @@ grub_cryptodisk_endecrypt (struct grub_cryptodisk *dev, + case GRUB_CRYPTODISK_MODE_CBC: + if (do_encrypt) + err = grub_crypto_cbc_encrypt (dev->cipher, data + i, data + i, +- (1U << dev->log_sector_size), iv); ++ ((grub_size_t) 1 << dev->log_sector_size), iv); + else + err = grub_crypto_cbc_decrypt (dev->cipher, data + i, data + i, +- (1U << dev->log_sector_size), iv); ++ ((grub_size_t) 1 << dev->log_sector_size), iv); + if (err) + return err; + break; +@@ -322,10 +322,10 @@ grub_cryptodisk_endecrypt (struct grub_cryptodisk *dev, + case GRUB_CRYPTODISK_MODE_PCBC: + if (do_encrypt) + err = grub_crypto_pcbc_encrypt (dev->cipher, data + i, data + i, +- (1U << dev->log_sector_size), iv); ++ ((grub_size_t) 1 << dev->log_sector_size), iv); + else + err = grub_crypto_pcbc_decrypt (dev->cipher, data + i, data + i, +- (1U << dev->log_sector_size), iv); ++ ((grub_size_t) 1 << dev->log_sector_size), iv); + if (err) + return err; + break; diff --git a/SOURCES/0403-disk-lvm-Sanitize-rlocn-offset-to-prevent-wild-read.patch b/SOURCES/0403-disk-lvm-Sanitize-rlocn-offset-to-prevent-wild-read.patch deleted file mode 100644 index 412873f..0000000 --- a/SOURCES/0403-disk-lvm-Sanitize-rlocn-offset-to-prevent-wild-read.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Fri, 22 Jan 2021 14:43:58 +1100 -Subject: [PATCH] disk/lvm: Sanitize rlocn->offset to prevent wild read - -rlocn->offset is read directly from disk and added to the metadatabuf -pointer to create a pointer to a block of metadata. It's a 64-bit -quantity so as long as you don't overflow you can set subsequent -pointers to point anywhere in memory. - -Require that rlocn->offset fits within the metadata buffer size. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/disk/lvm.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c -index 267be7b9536..9eda28d852c 100644 ---- a/grub-core/disk/lvm.c -+++ b/grub-core/disk/lvm.c -@@ -212,6 +212,14 @@ grub_lvm_detect (grub_disk_t disk, - } - - rlocn = mdah->raw_locns; -+ if (grub_le_to_cpu64 (rlocn->offset) >= grub_le_to_cpu64 (mda_size)) -+ { -+#ifdef GRUB_UTIL -+ grub_util_info ("metadata offset is beyond end of metadata area"); -+#endif -+ goto fail2; -+ } -+ - if (grub_le_to_cpu64 (rlocn->offset) + grub_le_to_cpu64 (rlocn->size) > - grub_le_to_cpu64 (mdah->size)) - { diff --git a/SOURCES/0404-disk-lvm-Do-not-allow-a-LV-to-be-it-s-own-segment-s-.patch b/SOURCES/0404-disk-lvm-Do-not-allow-a-LV-to-be-it-s-own-segment-s-.patch deleted file mode 100644 index 99e32f2..0000000 --- a/SOURCES/0404-disk-lvm-Do-not-allow-a-LV-to-be-it-s-own-segment-s-.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Fri, 22 Jan 2021 14:42:21 +1100 -Subject: [PATCH] disk/lvm: Do not allow a LV to be it's own segment's node's - LV - -This prevents infinite recursion in the diskfilter verification code. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper ---- - grub-core/disk/lvm.c | 10 +++++++--- - 1 file changed, 7 insertions(+), 3 deletions(-) - -diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c -index 9eda28d852c..7e86bb7df4f 100644 ---- a/grub-core/disk/lvm.c -+++ b/grub-core/disk/lvm.c -@@ -840,9 +840,13 @@ error_parsing_metadata: - } - if (lv1->segments[i].nodes[j].pv == NULL) - for (lv2 = vg->lvs; lv2; lv2 = lv2->next) -- if (grub_strcmp (lv2->name, -- lv1->segments[i].nodes[j].name) == 0) -- lv1->segments[i].nodes[j].lv = lv2; -+ { -+ if (lv1 == lv2) -+ continue; -+ if (grub_strcmp (lv2->name, -+ lv1->segments[i].nodes[j].name) == 0) -+ lv1->segments[i].nodes[j].lv = lv2; -+ } - } - - } diff --git a/SOURCES/0404-hfsplus-Check-that-the-volume-name-length-is-valid.patch b/SOURCES/0404-hfsplus-Check-that-the-volume-name-length-is-valid.patch new file mode 100644 index 0000000..c32f6e8 --- /dev/null +++ b/SOURCES/0404-hfsplus-Check-that-the-volume-name-length-is-valid.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Fri, 23 Oct 2020 17:09:31 +0000 +Subject: [PATCH] hfsplus: Check that the volume name length is valid + +HFS+ documentation suggests that the maximum filename and volume name is +255 Unicode characters in length. + +So, when converting from big-endian to little-endian, we should ensure +that the name of the volume has a length that is between 0 and 255, +inclusive. + +Fixes: CID 73641 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/fs/hfsplus.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/grub-core/fs/hfsplus.c b/grub-core/fs/hfsplus.c +index e06bcbb9ba3..03a33ea2477 100644 +--- a/grub-core/fs/hfsplus.c ++++ b/grub-core/fs/hfsplus.c +@@ -1012,6 +1012,15 @@ grub_hfsplus_label (grub_device_t device, char **label) + grub_hfsplus_btree_recptr (&data->catalog_tree, node, ptr); + + label_len = grub_be_to_cpu16 (catkey->namelen); ++ ++ /* Ensure that the length is >= 0. */ ++ if (label_len < 0) ++ label_len = 0; ++ ++ /* Ensure label length is at most 255 Unicode characters. */ ++ if (label_len > 255) ++ label_len = 255; ++ + label_name = grub_calloc (label_len, sizeof (*label_name)); + if (!label_name) + { diff --git a/SOURCES/0405-kern-parser-Fix-a-memory-leak.patch b/SOURCES/0405-kern-parser-Fix-a-memory-leak.patch deleted file mode 100644 index 42d42b3..0000000 --- a/SOURCES/0405-kern-parser-Fix-a-memory-leak.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Chris Coulson -Date: Wed, 18 Nov 2020 00:59:24 +0000 -Subject: [PATCH] kern/parser: Fix a memory leak - -The getline() function supplied to grub_parser_split_cmdline() returns -a newly allocated buffer and can be called multiple times, but the -returned buffer is never freed. - -Signed-off-by: Chris Coulson -Reviewed-by: Daniel Kiper ---- - grub-core/kern/parser.c | 20 ++++++++++++++++---- - 1 file changed, 16 insertions(+), 4 deletions(-) - -diff --git a/grub-core/kern/parser.c b/grub-core/kern/parser.c -index d1cf061ad68..39e4df65b86 100644 ---- a/grub-core/kern/parser.c -+++ b/grub-core/kern/parser.c -@@ -140,6 +140,7 @@ grub_parser_split_cmdline (const char *cmdline, - char buffer[1024]; - char *bp = buffer; - char *rd = (char *) cmdline; -+ char *rp = rd; - char varname[200]; - char *vp = varname; - char *args; -@@ -149,10 +150,18 @@ grub_parser_split_cmdline (const char *cmdline, - *argv = NULL; - do - { -- if (!rd || !*rd) -+ if (rp == NULL || *rp == '\0') - { -+ if (rd != cmdline) -+ { -+ grub_free (rd); -+ rd = rp = NULL; -+ } - if (getline) -- getline (&rd, 1, getline_data); -+ { -+ getline (&rd, 1, getline_data); -+ rp = rd; -+ } - else - break; - } -@@ -160,12 +169,12 @@ grub_parser_split_cmdline (const char *cmdline, - if (!rd) - break; - -- for (; *rd; rd++) -+ for (; *rp != '\0'; rp++) - { - grub_parser_state_t newstate; - char use; - -- newstate = grub_parser_cmdline_state (state, *rd, &use); -+ newstate = grub_parser_cmdline_state (state, *rp, &use); - - /* If a variable was being processed and this character does - not describe the variable anymore, write the variable to -@@ -198,6 +207,9 @@ grub_parser_split_cmdline (const char *cmdline, - } - while (state != GRUB_PARSER_STATE_TEXT && !check_varstate (state)); - -+ if (rd != cmdline) -+ grub_free (rd); -+ - /* A special case for when the last character was part of a - variable. */ - add_var (varname, &bp, &vp, state, GRUB_PARSER_STATE_TEXT); diff --git a/SOURCES/0405-zfs-Fix-possible-negative-shift-operation.patch b/SOURCES/0405-zfs-Fix-possible-negative-shift-operation.patch new file mode 100644 index 0000000..dd9d90f --- /dev/null +++ b/SOURCES/0405-zfs-Fix-possible-negative-shift-operation.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Tue, 24 Nov 2020 16:41:49 +0000 +Subject: [PATCH] zfs: Fix possible negative shift operation + +While it is possible for the return value from zfs_log2() to be zero +(0), it is quite unlikely, given that the previous assignment to blksz +is shifted up by SPA_MINBLOCKSHIFT (9) before 9 is subtracted at the +assignment to epbs. + +But, while unlikely during a normal operation, it may be that a carefully +crafted ZFS filesystem could result in a zero (0) value to the +dn_datalbkszsec field, which means that the shift left does nothing +and assigns zero (0) to blksz, resulting in a negative epbs value. + +Fixes: CID 73608 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/fs/zfs/zfs.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c +index c6204367e78..3dfde080750 100644 +--- a/grub-core/fs/zfs/zfs.c ++++ b/grub-core/fs/zfs/zfs.c +@@ -2667,6 +2667,11 @@ dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type, + blksz = grub_zfs_to_cpu16 (mdn->dn.dn_datablkszsec, + mdn->endian) << SPA_MINBLOCKSHIFT; + epbs = zfs_log2 (blksz) - DNODE_SHIFT; ++ ++ /* While this should never happen, we should check that epbs is not negative. */ ++ if (epbs < 0) ++ epbs = 0; ++ + blkid = objnum >> epbs; + idx = objnum & ((1 << epbs) - 1); + diff --git a/SOURCES/0406-kern-parser-Introduce-process_char-helper.patch b/SOURCES/0406-kern-parser-Introduce-process_char-helper.patch deleted file mode 100644 index c67dc9e..0000000 --- a/SOURCES/0406-kern-parser-Introduce-process_char-helper.patch +++ /dev/null @@ -1,116 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Chris Coulson -Date: Tue, 5 Jan 2021 22:17:28 +0000 -Subject: [PATCH] kern/parser: Introduce process_char() helper - -grub_parser_split_cmdline() iterates over each command line character. -In order to add error checking and to simplify the subsequent error -handling, split the character processing in to a separate function. - -Signed-off-by: Chris Coulson -Reviewed-by: Daniel Kiper ---- - grub-core/kern/parser.c | 74 ++++++++++++++++++++++++++++++------------------- - 1 file changed, 46 insertions(+), 28 deletions(-) - -diff --git a/grub-core/kern/parser.c b/grub-core/kern/parser.c -index 39e4df65b86..0d3582bd874 100644 ---- a/grub-core/kern/parser.c -+++ b/grub-core/kern/parser.c -@@ -1,7 +1,7 @@ - /* parser.c - the part of the parser that can return partial tokens */ - /* - * GRUB -- GRand Unified Bootloader -- * Copyright (C) 2005,2007,2009 Free Software Foundation, Inc. -+ * Copyright (C) 2005,2007,2009,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 -@@ -129,6 +129,46 @@ add_var (char *varname, char **bp, char **vp, - *((*bp)++) = *val; - } - -+static grub_err_t -+process_char (char c, char *buffer, char **bp, char *varname, char **vp, -+ grub_parser_state_t state, int *argc, -+ grub_parser_state_t *newstate) -+{ -+ char use; -+ -+ *newstate = grub_parser_cmdline_state (state, c, &use); -+ -+ /* -+ * If a variable was being processed and this character does -+ * not describe the variable anymore, write the variable to -+ * the buffer. -+ */ -+ add_var (varname, bp, vp, state, *newstate); -+ -+ if (check_varstate (*newstate)) -+ { -+ if (use) -+ *((*vp)++) = use; -+ } -+ else if (*newstate == GRUB_PARSER_STATE_TEXT && -+ state != GRUB_PARSER_STATE_ESC && grub_isspace (use)) -+ { -+ /* -+ * Don't add more than one argument if multiple -+ * spaces are used. -+ */ -+ if (*bp != buffer && *((*bp) - 1) != '\0') -+ { -+ *((*bp)++) = '\0'; -+ (*argc)++; -+ } -+ } -+ else if (use) -+ *((*bp)++) = use; -+ -+ return GRUB_ERR_NONE; -+} -+ - grub_err_t - grub_parser_split_cmdline (const char *cmdline, - grub_reader_getline_t getline, void *getline_data, -@@ -172,35 +212,13 @@ grub_parser_split_cmdline (const char *cmdline, - for (; *rp != '\0'; rp++) - { - grub_parser_state_t newstate; -- char use; - -- newstate = grub_parser_cmdline_state (state, *rp, &use); -- -- /* If a variable was being processed and this character does -- not describe the variable anymore, write the variable to -- the buffer. */ -- add_var (varname, &bp, &vp, state, newstate); -- -- if (check_varstate (newstate)) -- { -- if (use) -- *(vp++) = use; -- } -- else -+ if (process_char (*rp, buffer, &bp, varname, &vp, state, argc, -+ &newstate) != GRUB_ERR_NONE) - { -- if (newstate == GRUB_PARSER_STATE_TEXT -- && state != GRUB_PARSER_STATE_ESC && grub_isspace (use)) -- { -- /* Don't add more than one argument if multiple -- spaces are used. */ -- if (bp != buffer && *(bp - 1)) -- { -- *(bp++) = '\0'; -- (*argc)++; -- } -- } -- else if (use) -- *(bp++) = use; -+ if (rd != cmdline) -+ grub_free (rd); -+ return grub_errno; - } - state = newstate; - } diff --git a/SOURCES/0406-zfs-Fix-resource-leaks-while-constructing-path.patch b/SOURCES/0406-zfs-Fix-resource-leaks-while-constructing-path.patch new file mode 100644 index 0000000..3c37522 --- /dev/null +++ b/SOURCES/0406-zfs-Fix-resource-leaks-while-constructing-path.patch @@ -0,0 +1,118 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paulo Flabiano Smorigo +Date: Mon, 14 Dec 2020 18:54:49 -0300 +Subject: [PATCH] zfs: Fix resource leaks while constructing path + +There are several exit points in dnode_get_path() that are causing possible +memory leaks. + +In the while(1) the correct exit mechanism should not be to do a direct return, +but to instead break out of the loop, setting err first if it is not already set. + +The reason behind this is that the dnode_path is a linked list, and while doing +through this loop, it is being allocated and built up - the only way to +correctly unravel it is to traverse it, which is what is being done at the end +of the function outside of the loop. + +Several of the existing exit points correctly did a break, but not all so this +change makes that more consistent and should resolve the leaking of memory as +found by Coverity. + +Fixes: CID 73741 + +Signed-off-by: Paulo Flabiano Smorigo +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/fs/zfs/zfs.c | 30 +++++++++++++++++++++--------- + 1 file changed, 21 insertions(+), 9 deletions(-) + +diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c +index 3dfde080750..44d8bde6b33 100644 +--- a/grub-core/fs/zfs/zfs.c ++++ b/grub-core/fs/zfs/zfs.c +@@ -2836,8 +2836,8 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + + if (dnode_path->dn.dn.dn_type != DMU_OT_DIRECTORY_CONTENTS) + { +- grub_free (path_buf); +- return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory")); ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory")); ++ break; + } + err = zap_lookup (&(dnode_path->dn), cname, &objnum, + data, subvol->case_insensitive); +@@ -2879,11 +2879,18 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + << SPA_MINBLOCKSHIFT); + + if (blksz == 0) +- return grub_error(GRUB_ERR_BAD_FS, "0-sized block"); ++ { ++ err = grub_error (GRUB_ERR_BAD_FS, "0-sized block"); ++ break; ++ } + + sym_value = grub_malloc (sym_sz); + if (!sym_value) +- return grub_errno; ++ { ++ err = grub_errno; ++ break; ++ } ++ + for (block = 0; block < (sym_sz + blksz - 1) / blksz; block++) + { + void *t; +@@ -2893,7 +2900,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + if (err) + { + grub_free (sym_value); +- return err; ++ break; + } + + movesize = sym_sz - block * blksz; +@@ -2903,6 +2910,8 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + grub_memcpy (sym_value + block * blksz, t, movesize); + grub_free (t); + } ++ if (err) ++ break; + free_symval = 1; + } + path = path_buf = grub_malloc (sym_sz + grub_strlen (oldpath) + 1); +@@ -2911,7 +2920,8 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + grub_free (oldpathbuf); + if (free_symval) + grub_free (sym_value); +- return grub_errno; ++ err = grub_errno; ++ break; + } + grub_memcpy (path, sym_value, sym_sz); + if (free_symval) +@@ -2949,11 +2959,12 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + + err = zio_read (bp, dnode_path->dn.endian, &sahdrp, NULL, data); + if (err) +- return err; ++ break; + } + else + { +- return grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt"); ++ err = grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt"); ++ break; + } + + hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp)); +@@ -2974,7 +2985,8 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + if (!path_buf) + { + grub_free (oldpathbuf); +- return grub_errno; ++ err = grub_errno; ++ break; + } + grub_memcpy (path, sym_value, sym_sz); + path [sym_sz] = 0; diff --git a/SOURCES/0407-kern-parser-Introduce-terminate_arg-helper.patch b/SOURCES/0407-kern-parser-Introduce-terminate_arg-helper.patch deleted file mode 100644 index 4192ec5..0000000 --- a/SOURCES/0407-kern-parser-Introduce-terminate_arg-helper.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Chris Coulson -Date: Thu, 7 Jan 2021 19:53:55 +0000 -Subject: [PATCH] kern/parser: Introduce terminate_arg() helper - -process_char() and grub_parser_split_cmdline() use similar code for -terminating the most recent argument. Add a helper function for this. - -Signed-off-by: Chris Coulson -Reviewed-by: Daniel Kiper ---- - grub-core/kern/parser.c | 23 +++++++++++++---------- - 1 file changed, 13 insertions(+), 10 deletions(-) - -diff --git a/grub-core/kern/parser.c b/grub-core/kern/parser.c -index 0d3582bd874..572c67089f3 100644 ---- a/grub-core/kern/parser.c -+++ b/grub-core/kern/parser.c -@@ -129,6 +129,16 @@ add_var (char *varname, char **bp, char **vp, - *((*bp)++) = *val; - } - -+static void -+terminate_arg (char *buffer, char **bp, int *argc) -+{ -+ if (*bp != buffer && *((*bp) - 1) != '\0') -+ { -+ *((*bp)++) = '\0'; -+ (*argc)++; -+ } -+} -+ - static grub_err_t - process_char (char c, char *buffer, char **bp, char *varname, char **vp, - grub_parser_state_t state, int *argc, -@@ -157,11 +167,7 @@ process_char (char c, char *buffer, char **bp, char *varname, char **vp, - * Don't add more than one argument if multiple - * spaces are used. - */ -- if (*bp != buffer && *((*bp) - 1) != '\0') -- { -- *((*bp)++) = '\0'; -- (*argc)++; -- } -+ terminate_arg (buffer, bp, argc); - } - else if (use) - *((*bp)++) = use; -@@ -232,11 +238,8 @@ grub_parser_split_cmdline (const char *cmdline, - variable. */ - add_var (varname, &bp, &vp, state, GRUB_PARSER_STATE_TEXT); - -- if (bp != buffer && *(bp - 1)) -- { -- *(bp++) = '\0'; -- (*argc)++; -- } -+ /* Ensure that the last argument is terminated. */ -+ terminate_arg (buffer, &bp, argc); - - /* If there are no args, then we're done. */ - if (!*argc) diff --git a/SOURCES/0407-zfs-Fix-possible-integer-overflows.patch b/SOURCES/0407-zfs-Fix-possible-integer-overflows.patch new file mode 100644 index 0000000..1017056 --- /dev/null +++ b/SOURCES/0407-zfs-Fix-possible-integer-overflows.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Tue, 8 Dec 2020 22:17:04 +0000 +Subject: [PATCH] zfs: Fix possible integer overflows + +In all cases the problem is that the value being acted upon by +a left-shift is a 32-bit number which is then being used in the +context of a 64-bit number. + +To avoid overflow we ensure that the number being shifted is 64-bit +before the shift is done. + +Fixes: CID 73684, CID 73695, CID 73764 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/fs/zfs/zfs.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c +index 44d8bde6b33..0d8c08eec92 100644 +--- a/grub-core/fs/zfs/zfs.c ++++ b/grub-core/fs/zfs/zfs.c +@@ -564,7 +564,7 @@ find_bestub (uberblock_phys_t * ub_array, + ubptr = (uberblock_phys_t *) ((grub_properly_aligned_t *) ub_array + + ((i << ub_shift) + / sizeof (grub_properly_aligned_t))); +- err = uberblock_verify (ubptr, offset, 1 << ub_shift); ++ err = uberblock_verify (ubptr, offset, (grub_size_t) 1 << ub_shift); + if (err) + { + grub_errno = GRUB_ERR_NONE; +@@ -1543,7 +1543,7 @@ read_device (grub_uint64_t offset, struct grub_zfs_device_desc *desc, + + high = grub_divmod64 ((offset >> desc->ashift) + c, + desc->n_children, &devn); +- csize = bsize << desc->ashift; ++ csize = (grub_size_t) bsize << desc->ashift; + if (csize > len) + csize = len; + +@@ -1635,8 +1635,8 @@ read_device (grub_uint64_t offset, struct grub_zfs_device_desc *desc, + + while (len > 0) + { +- grub_size_t csize; +- csize = ((s / (desc->n_children - desc->nparity)) ++ grub_size_t csize = s; ++ csize = ((csize / (desc->n_children - desc->nparity)) + << desc->ashift); + if (csize > len) + csize = len; diff --git a/SOURCES/0408-kern-parser-Refactor-grub_parser_split_cmdline-clean.patch b/SOURCES/0408-kern-parser-Refactor-grub_parser_split_cmdline-clean.patch deleted file mode 100644 index c6a0c49..0000000 --- a/SOURCES/0408-kern-parser-Refactor-grub_parser_split_cmdline-clean.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Chris Coulson -Date: Wed, 6 Jan 2021 13:54:26 +0000 -Subject: [PATCH] kern/parser: Refactor grub_parser_split_cmdline() cleanup - -Introduce a common function epilogue used for cleaning up on all -return paths, which will simplify additional error handling to be -introduced in a subsequent commit. - -Signed-off-by: Chris Coulson -Reviewed-by: Daniel Kiper ---- - grub-core/kern/parser.c | 35 ++++++++++++++++++++--------------- - 1 file changed, 20 insertions(+), 15 deletions(-) - -diff --git a/grub-core/kern/parser.c b/grub-core/kern/parser.c -index 572c67089f3..e010eaa1fa1 100644 ---- a/grub-core/kern/parser.c -+++ b/grub-core/kern/parser.c -@@ -221,19 +221,13 @@ grub_parser_split_cmdline (const char *cmdline, - - if (process_char (*rp, buffer, &bp, varname, &vp, state, argc, - &newstate) != GRUB_ERR_NONE) -- { -- if (rd != cmdline) -- grub_free (rd); -- return grub_errno; -- } -+ goto fail; -+ - state = newstate; - } - } - while (state != GRUB_PARSER_STATE_TEXT && !check_varstate (state)); - -- if (rd != cmdline) -- grub_free (rd); -- - /* A special case for when the last character was part of a - variable. */ - add_var (varname, &bp, &vp, state, GRUB_PARSER_STATE_TEXT); -@@ -243,20 +237,20 @@ grub_parser_split_cmdline (const char *cmdline, - - /* If there are no args, then we're done. */ - if (!*argc) -- return 0; -+ { -+ grub_errno = GRUB_ERR_NONE; -+ goto out; -+ } - - /* Reserve memory for the return values. */ - args = grub_malloc (bp - buffer); - if (!args) -- return grub_errno; -+ goto fail; - grub_memcpy (args, buffer, bp - buffer); - - *argv = grub_calloc (*argc + 1, sizeof (char *)); - if (!*argv) -- { -- grub_free (args); -- return grub_errno; -- } -+ goto fail; - - /* The arguments are separated with 0's, setup argv so it points to - the right values. */ -@@ -269,7 +263,18 @@ grub_parser_split_cmdline (const char *cmdline, - bp++; - } - -- return 0; -+ grub_errno = GRUB_ERR_NONE; -+ -+ out: -+ if (rd != cmdline) -+ grub_free (rd); -+ -+ return grub_errno; -+ -+ fail: -+ grub_free (*argv); -+ grub_free (args); -+ goto out; - } - - /* Helper for grub_parser_execute. */ diff --git a/SOURCES/0408-zfsinfo-Correct-a-check-for-error-allocating-memory.patch b/SOURCES/0408-zfsinfo-Correct-a-check-for-error-allocating-memory.patch new file mode 100644 index 0000000..4951204 --- /dev/null +++ b/SOURCES/0408-zfsinfo-Correct-a-check-for-error-allocating-memory.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Thu, 26 Nov 2020 10:56:45 +0000 +Subject: [PATCH] zfsinfo: Correct a check for error allocating memory + +While arguably the check for grub_errno is correct, we should really be +checking the return value from the function since it is always possible +that grub_errno was set elsewhere, making this code behave incorrectly. + +Fixes: CID 73668 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/fs/zfs/zfsinfo.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/fs/zfs/zfsinfo.c b/grub-core/fs/zfs/zfsinfo.c +index c8a28acf52b..bf2918018e7 100644 +--- a/grub-core/fs/zfs/zfsinfo.c ++++ b/grub-core/fs/zfs/zfsinfo.c +@@ -358,8 +358,8 @@ grub_cmd_zfs_bootfs (grub_command_t cmd __attribute__ ((unused)), int argc, + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); + + devname = grub_file_get_device_name (args[0]); +- if (grub_errno) +- return grub_errno; ++ if (devname == NULL) ++ return GRUB_ERR_OUT_OF_MEMORY; + + dev = grub_device_open (devname); + grub_free (devname); diff --git a/SOURCES/0409-affs-Fix-memory-leaks.patch b/SOURCES/0409-affs-Fix-memory-leaks.patch new file mode 100644 index 0000000..57c42a0 --- /dev/null +++ b/SOURCES/0409-affs-Fix-memory-leaks.patch @@ -0,0 +1,79 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Thu, 26 Nov 2020 12:48:07 +0000 +Subject: [PATCH] affs: Fix memory leaks + +The node structure reference is being allocated but not freed if it +reaches the end of the function. If any of the hooks had returned +a non-zero value, then node would have been copied in to the context +reference, but otherwise node is not stored and should be freed. + +Similarly, the call to grub_affs_create_node() replaces the allocated +memory in node with a newly allocated structure, leaking the existing +memory pointed by node. + +Finally, when dir->parent is set, then we again replace node with newly +allocated memory, which seems unnecessary when we copy in the values +from dir->parent immediately after. + +Fixes: CID 73759 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/fs/affs.c | 18 ++++++++---------- + 1 file changed, 8 insertions(+), 10 deletions(-) + +diff --git a/grub-core/fs/affs.c b/grub-core/fs/affs.c +index 91073795f90..e4615c74381 100644 +--- a/grub-core/fs/affs.c ++++ b/grub-core/fs/affs.c +@@ -400,12 +400,12 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir, + { + unsigned int i; + struct grub_affs_file file; +- struct grub_fshelp_node *node = 0; ++ struct grub_fshelp_node *node, *orig_node; + struct grub_affs_data *data = dir->data; + grub_uint32_t *hashtable; + + /* Create the directory entries for `.' and `..'. */ +- node = grub_zalloc (sizeof (*node)); ++ node = orig_node = grub_zalloc (sizeof (*node)); + if (!node) + return 1; + +@@ -414,9 +414,6 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir, + return 1; + if (dir->parent) + { +- node = grub_zalloc (sizeof (*node)); +- if (!node) +- return 1; + *node = *dir->parent; + if (hook ("..", GRUB_FSHELP_DIR, node, hook_data)) + return 1; +@@ -456,17 +453,18 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir, + + if (grub_affs_create_node (dir, hook, hook_data, &node, &hashtable, + next, &file)) +- return 1; ++ { ++ /* Node has been replaced in function. */ ++ grub_free (orig_node); ++ return 1; ++ } + + next = grub_be_to_cpu32 (file.next); + } + } + +- grub_free (hashtable); +- return 0; +- + fail: +- grub_free (node); ++ grub_free (orig_node); + grub_free (hashtable); + return 0; + } diff --git a/SOURCES/0409-kern-buffer-Add-variable-sized-heap-buffer.patch b/SOURCES/0409-kern-buffer-Add-variable-sized-heap-buffer.patch deleted file mode 100644 index c1aaa00..0000000 --- a/SOURCES/0409-kern-buffer-Add-variable-sized-heap-buffer.patch +++ /dev/null @@ -1,304 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Chris Coulson -Date: Thu, 7 Jan 2021 15:15:43 +0000 -Subject: [PATCH] kern/buffer: Add variable sized heap buffer - -Add a new variable sized heap buffer type (grub_buffer_t) with simple -operations for appending data, accessing the data and maintaining -a read cursor. - -Signed-off-by: Chris Coulson -Reviewed-by: Daniel Kiper ---- - grub-core/Makefile.core.def | 1 + - grub-core/kern/buffer.c | 117 +++++++++++++++++++++++++++++++++++ - include/grub/buffer.h | 144 ++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 262 insertions(+) - create mode 100644 grub-core/kern/buffer.c - create mode 100644 include/grub/buffer.h - -diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def -index 0eb7f312b29..6c25cf3e26a 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -112,6 +112,7 @@ kernel = { - arm_efi_startup = kern/arm/efi/startup.S; - arm64_efi_startup = kern/arm64/efi/startup.S; - -+ common = kern/buffer.c; - common = kern/command.c; - common = kern/corecmd.c; - common = kern/device.c; -diff --git a/grub-core/kern/buffer.c b/grub-core/kern/buffer.c -new file mode 100644 -index 00000000000..9f5f8b86705 ---- /dev/null -+++ b/grub-core/kern/buffer.c -@@ -0,0 +1,117 @@ -+/* -+ * 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 . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+grub_buffer_t -+grub_buffer_new (grub_size_t sz) -+{ -+ struct grub_buffer *ret; -+ -+ ret = (struct grub_buffer *) grub_malloc (sizeof (*ret)); -+ if (ret == NULL) -+ return NULL; -+ -+ ret->data = (grub_uint8_t *) grub_malloc (sz); -+ if (ret->data == NULL) -+ { -+ grub_free (ret); -+ return NULL; -+ } -+ -+ ret->sz = sz; -+ ret->pos = 0; -+ ret->used = 0; -+ -+ return ret; -+} -+ -+void -+grub_buffer_free (grub_buffer_t buf) -+{ -+ grub_free (buf->data); -+ grub_free (buf); -+} -+ -+grub_err_t -+grub_buffer_ensure_space (grub_buffer_t buf, grub_size_t req) -+{ -+ grub_uint8_t *d; -+ grub_size_t newsz = 1; -+ -+ /* Is the current buffer size adequate? */ -+ if (buf->sz >= req) -+ return GRUB_ERR_NONE; -+ -+ /* Find the smallest power-of-2 size that satisfies the request. */ -+ while (newsz < req) -+ { -+ if (newsz == 0) -+ return grub_error (GRUB_ERR_OUT_OF_RANGE, -+ N_("requested buffer size is too large")); -+ newsz <<= 1; -+ } -+ -+ d = (grub_uint8_t *) grub_realloc (buf->data, newsz); -+ if (d == NULL) -+ return grub_errno; -+ -+ buf->data = d; -+ buf->sz = newsz; -+ -+ return GRUB_ERR_NONE; -+} -+ -+void * -+grub_buffer_take_data (grub_buffer_t buf) -+{ -+ void *data = buf->data; -+ -+ buf->data = NULL; -+ buf->sz = buf->pos = buf->used = 0; -+ -+ return data; -+} -+ -+void -+grub_buffer_reset (grub_buffer_t buf) -+{ -+ buf->pos = buf->used = 0; -+} -+ -+grub_err_t -+grub_buffer_advance_read_pos (grub_buffer_t buf, grub_size_t n) -+{ -+ grub_size_t newpos; -+ -+ if (grub_add (buf->pos, n, &newpos)) -+ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); -+ -+ if (newpos > buf->used) -+ return grub_error (GRUB_ERR_OUT_OF_RANGE, -+ N_("new read is position beyond the end of the written data")); -+ -+ buf->pos = newpos; -+ -+ return GRUB_ERR_NONE; -+} -diff --git a/include/grub/buffer.h b/include/grub/buffer.h -new file mode 100644 -index 00000000000..f4b10cf2810 ---- /dev/null -+++ b/include/grub/buffer.h -@@ -0,0 +1,144 @@ -+/* -+ * 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 . -+ */ -+ -+#ifndef GRUB_BUFFER_H -+#define GRUB_BUFFER_H 1 -+ -+#include -+#include -+#include -+#include -+#include -+ -+struct grub_buffer -+{ -+ grub_uint8_t *data; -+ grub_size_t sz; -+ grub_size_t pos; -+ grub_size_t used; -+}; -+ -+/* -+ * grub_buffer_t represents a simple variable sized byte buffer with -+ * read and write cursors. It currently only implements -+ * functionality required by the only user in GRUB (append byte[s], -+ * peeking data at a specified position and updating the read cursor. -+ * Some things that this doesn't do yet are: -+ * - Reading a portion of the buffer by copying data from the current -+ * read position in to a caller supplied destination buffer and then -+ * automatically updating the read cursor. -+ * - Dropping the read part at the start of the buffer when an append -+ * requires more space. -+ */ -+typedef struct grub_buffer *grub_buffer_t; -+ -+/* Allocate a new buffer with the specified initial size. */ -+extern grub_buffer_t grub_buffer_new (grub_size_t sz); -+ -+/* Free the buffer and its resources. */ -+extern void grub_buffer_free (grub_buffer_t buf); -+ -+/* Return the number of unread bytes in this buffer. */ -+static inline grub_size_t -+grub_buffer_get_unread_bytes (grub_buffer_t buf) -+{ -+ return buf->used - buf->pos; -+} -+ -+/* -+ * Ensure that the buffer size is at least the requested -+ * number of bytes. -+ */ -+extern grub_err_t grub_buffer_ensure_space (grub_buffer_t buf, grub_size_t req); -+ -+/* -+ * Append the specified number of bytes from the supplied -+ * data to the buffer. -+ */ -+static inline grub_err_t -+grub_buffer_append_data (grub_buffer_t buf, const void *data, grub_size_t len) -+{ -+ grub_size_t req; -+ -+ if (grub_add (buf->used, len, &req)) -+ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); -+ -+ if (grub_buffer_ensure_space (buf, req) != GRUB_ERR_NONE) -+ return grub_errno; -+ -+ grub_memcpy (&buf->data[buf->used], data, len); -+ buf->used = req; -+ -+ return GRUB_ERR_NONE; -+} -+ -+/* Append the supplied character to the buffer. */ -+static inline grub_err_t -+grub_buffer_append_char (grub_buffer_t buf, char c) -+{ -+ return grub_buffer_append_data (buf, &c, 1); -+} -+ -+/* -+ * Forget and return the underlying data buffer. The caller -+ * becomes the owner of this buffer, and must free it when it -+ * is no longer required. -+ */ -+extern void *grub_buffer_take_data (grub_buffer_t buf); -+ -+/* Reset this buffer. Note that this does not deallocate any resources. */ -+void grub_buffer_reset (grub_buffer_t buf); -+ -+/* -+ * Return a pointer to the underlying data buffer at the specified -+ * offset from the current read position. Note that this pointer may -+ * become invalid if the buffer is mutated further. -+ */ -+static inline void * -+grub_buffer_peek_data_at (grub_buffer_t buf, grub_size_t off) -+{ -+ if (grub_add (buf->pos, off, &off)) -+ { -+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected.")); -+ return NULL; -+ } -+ -+ if (off >= buf->used) -+ { -+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("peek out of range")); -+ return NULL; -+ } -+ -+ return &buf->data[off]; -+} -+ -+/* -+ * Return a pointer to the underlying data buffer at the current -+ * read position. Note that this pointer may become invalid if the -+ * buffer is mutated further. -+ */ -+static inline void * -+grub_buffer_peek_data (grub_buffer_t buf) -+{ -+ return grub_buffer_peek_data_at (buf, 0); -+} -+ -+/* Advance the read position by the specified number of bytes. */ -+extern grub_err_t grub_buffer_advance_read_pos (grub_buffer_t buf, grub_size_t n); -+ -+#endif /* GRUB_BUFFER_H */ diff --git a/SOURCES/0410-kern-parser-Fix-a-stack-buffer-overflow.patch b/SOURCES/0410-kern-parser-Fix-a-stack-buffer-overflow.patch deleted file mode 100644 index 7a30d03..0000000 --- a/SOURCES/0410-kern-parser-Fix-a-stack-buffer-overflow.patch +++ /dev/null @@ -1,244 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Chris Coulson -Date: Thu, 7 Jan 2021 19:21:03 +0000 -Subject: [PATCH] kern/parser: Fix a stack buffer overflow - -grub_parser_split_cmdline() expands variable names present in the supplied -command line in to their corresponding variable contents and uses a 1 kiB -stack buffer for temporary storage without sufficient bounds checking. If -the function is called with a command line that references a variable with -a sufficiently large payload, it is possible to overflow the stack -buffer via tab completion, corrupt the stack frame and potentially -control execution. - -Fixes: CVE-2020-27749 - -Reported-by: Chris Coulson -Signed-off-by: Chris Coulson -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper ---- - grub-core/kern/parser.c | 110 +++++++++++++++++++++++++++++------------------- - 1 file changed, 67 insertions(+), 43 deletions(-) - -diff --git a/grub-core/kern/parser.c b/grub-core/kern/parser.c -index e010eaa1fa1..6ab7aa427cc 100644 ---- a/grub-core/kern/parser.c -+++ b/grub-core/kern/parser.c -@@ -18,6 +18,7 @@ - */ - - #include -+#include - #include - #include - #include -@@ -107,8 +108,8 @@ check_varstate (grub_parser_state_t s) - } - - --static void --add_var (char *varname, char **bp, char **vp, -+static grub_err_t -+add_var (grub_buffer_t varname, grub_buffer_t buf, - grub_parser_state_t state, grub_parser_state_t newstate) - { - const char *val; -@@ -116,31 +117,41 @@ add_var (char *varname, char **bp, char **vp, - /* Check if a variable was being read in and the end of the name - was reached. */ - if (!(check_varstate (state) && !check_varstate (newstate))) -- return; -+ return GRUB_ERR_NONE; - -- *((*vp)++) = '\0'; -- val = grub_env_get (varname); -- *vp = varname; -+ if (grub_buffer_append_char (varname, '\0') != GRUB_ERR_NONE) -+ return grub_errno; -+ -+ val = grub_env_get ((const char *) grub_buffer_peek_data (varname)); -+ grub_buffer_reset (varname); - if (!val) -- return; -+ return GRUB_ERR_NONE; - - /* Insert the contents of the variable in the buffer. */ -- for (; *val; val++) -- *((*bp)++) = *val; -+ return grub_buffer_append_data (buf, val, grub_strlen (val)); - } - --static void --terminate_arg (char *buffer, char **bp, int *argc) -+static grub_err_t -+terminate_arg (grub_buffer_t buffer, int *argc) - { -- if (*bp != buffer && *((*bp) - 1) != '\0') -- { -- *((*bp)++) = '\0'; -- (*argc)++; -- } -+ grub_size_t unread = grub_buffer_get_unread_bytes (buffer); -+ -+ if (unread == 0) -+ return GRUB_ERR_NONE; -+ -+ if (*(const char *) grub_buffer_peek_data_at (buffer, unread - 1) == '\0') -+ return GRUB_ERR_NONE; -+ -+ if (grub_buffer_append_char (buffer, '\0') != GRUB_ERR_NONE) -+ return grub_errno; -+ -+ (*argc)++; -+ -+ return GRUB_ERR_NONE; - } - - static grub_err_t --process_char (char c, char *buffer, char **bp, char *varname, char **vp, -+process_char (char c, grub_buffer_t buffer, grub_buffer_t varname, - grub_parser_state_t state, int *argc, - grub_parser_state_t *newstate) - { -@@ -153,12 +164,13 @@ process_char (char c, char *buffer, char **bp, char *varname, char **vp, - * not describe the variable anymore, write the variable to - * the buffer. - */ -- add_var (varname, bp, vp, state, *newstate); -+ if (add_var (varname, buffer, state, *newstate) != GRUB_ERR_NONE) -+ return grub_errno; - - if (check_varstate (*newstate)) - { - if (use) -- *((*vp)++) = use; -+ return grub_buffer_append_char (varname, use); - } - else if (*newstate == GRUB_PARSER_STATE_TEXT && - state != GRUB_PARSER_STATE_ESC && grub_isspace (use)) -@@ -167,10 +179,10 @@ process_char (char c, char *buffer, char **bp, char *varname, char **vp, - * Don't add more than one argument if multiple - * spaces are used. - */ -- terminate_arg (buffer, bp, argc); -+ return terminate_arg (buffer, argc); - } - else if (use) -- *((*bp)++) = use; -+ return grub_buffer_append_char (buffer, use); - - return GRUB_ERR_NONE; - } -@@ -181,19 +193,22 @@ grub_parser_split_cmdline (const char *cmdline, - int *argc, char ***argv) - { - grub_parser_state_t state = GRUB_PARSER_STATE_TEXT; -- /* XXX: Fixed size buffer, perhaps this buffer should be dynamically -- allocated. */ -- char buffer[1024]; -- char *bp = buffer; -+ grub_buffer_t buffer, varname; - char *rd = (char *) cmdline; - char *rp = rd; -- char varname[200]; -- char *vp = varname; -- char *args; - int i; - - *argc = 0; - *argv = NULL; -+ -+ buffer = grub_buffer_new (1024); -+ if (buffer == NULL) -+ return grub_errno; -+ -+ varname = grub_buffer_new (200); -+ if (varname == NULL) -+ goto fail; -+ - do - { - if (rp == NULL || *rp == '\0') -@@ -219,7 +234,7 @@ grub_parser_split_cmdline (const char *cmdline, - { - grub_parser_state_t newstate; - -- if (process_char (*rp, buffer, &bp, varname, &vp, state, argc, -+ if (process_char (*rp, buffer, varname, state, argc, - &newstate) != GRUB_ERR_NONE) - goto fail; - -@@ -230,10 +245,12 @@ grub_parser_split_cmdline (const char *cmdline, - - /* A special case for when the last character was part of a - variable. */ -- add_var (varname, &bp, &vp, state, GRUB_PARSER_STATE_TEXT); -+ if (add_var (varname, buffer, state, GRUB_PARSER_STATE_TEXT) != GRUB_ERR_NONE) -+ goto fail; - - /* Ensure that the last argument is terminated. */ -- terminate_arg (buffer, &bp, argc); -+ if (terminate_arg (buffer, argc) != GRUB_ERR_NONE) -+ goto fail; - - /* If there are no args, then we're done. */ - if (!*argc) -@@ -242,38 +259,45 @@ grub_parser_split_cmdline (const char *cmdline, - goto out; - } - -- /* Reserve memory for the return values. */ -- args = grub_malloc (bp - buffer); -- if (!args) -- goto fail; -- grub_memcpy (args, buffer, bp - buffer); -- - *argv = grub_calloc (*argc + 1, sizeof (char *)); - if (!*argv) - goto fail; - - /* The arguments are separated with 0's, setup argv so it points to - the right values. */ -- bp = args; - for (i = 0; i < *argc; i++) - { -- (*argv)[i] = bp; -- while (*bp) -- bp++; -- bp++; -+ char *arg; -+ -+ if (i > 0) -+ { -+ if (grub_buffer_advance_read_pos (buffer, 1) != GRUB_ERR_NONE) -+ goto fail; -+ } -+ -+ arg = (char *) grub_buffer_peek_data (buffer); -+ if (arg == NULL || -+ grub_buffer_advance_read_pos (buffer, grub_strlen (arg)) != GRUB_ERR_NONE) -+ goto fail; -+ -+ (*argv)[i] = arg; - } - -+ /* Keep memory for the return values. */ -+ grub_buffer_take_data (buffer); -+ - grub_errno = GRUB_ERR_NONE; - - out: - if (rd != cmdline) - grub_free (rd); -+ grub_buffer_free (buffer); -+ grub_buffer_free (varname); - - return grub_errno; - - fail: - grub_free (*argv); -- grub_free (args); - goto out; - } - diff --git a/SOURCES/0410-libgcrypt-mpi-Fix-possible-unintended-sign-extension.patch b/SOURCES/0410-libgcrypt-mpi-Fix-possible-unintended-sign-extension.patch new file mode 100644 index 0000000..c9f3a35 --- /dev/null +++ b/SOURCES/0410-libgcrypt-mpi-Fix-possible-unintended-sign-extension.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Tue, 3 Nov 2020 16:43:37 +0000 +Subject: [PATCH] libgcrypt/mpi: Fix possible unintended sign extension + +The array of unsigned char gets promoted to a signed 32-bit int before +it is finally promoted to a size_t. There is the possibility that this +may result in the signed-bit being set for the intermediate signed +32-bit int. We should ensure that the promotion is to the correct type +before we bitwise-OR the values. + +Fixes: CID 96697 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/lib/libgcrypt/mpi/mpicoder.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/lib/libgcrypt/mpi/mpicoder.c b/grub-core/lib/libgcrypt/mpi/mpicoder.c +index a3435ed142a..7ecad27b23a 100644 +--- a/grub-core/lib/libgcrypt/mpi/mpicoder.c ++++ b/grub-core/lib/libgcrypt/mpi/mpicoder.c +@@ -458,7 +458,7 @@ gcry_mpi_scan (struct gcry_mpi **ret_mpi, enum gcry_mpi_format format, + if (len && len < 4) + return gcry_error (GPG_ERR_TOO_SHORT); + +- n = (s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]); ++ n = ((size_t)s[0] << 24 | (size_t)s[1] << 16 | (size_t)s[2] << 8 | (size_t)s[3]); + s += 4; + if (len) + len -= 4; diff --git a/SOURCES/0411-kern-efi-Add-initial-stack-protector-implementation.patch b/SOURCES/0411-kern-efi-Add-initial-stack-protector-implementation.patch deleted file mode 100644 index 0032577..0000000 --- a/SOURCES/0411-kern-efi-Add-initial-stack-protector-implementation.patch +++ /dev/null @@ -1,298 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Chris Coulson -Date: Fri, 19 Feb 2021 13:53:45 +0100 -Subject: [PATCH] kern/efi: Add initial stack protector implementation - -It works only on UEFI platforms but can be quite easily extended to -others architectures and platforms if needed. - -Signed-off-by: Chris Coulson -Signed-off-by: Daniel Kiper -Reviewed-by: Marco A Benatto -Reviewed-by: Javier Martinez Canillas ---- - configure.ac | 44 ++++++++++++++++++++++++++++++---- - grub-core/kern/efi/init.c | 54 ++++++++++++++++++++++++++++++++++++++++++ - include/grub/efi/api.h | 19 +++++++++++++++ - include/grub/stack_protector.h | 30 +++++++++++++++++++++++ - acinclude.m4 | 38 +++++++++++++++++++++++++++-- - grub-core/Makefile.am | 1 + - 6 files changed, 179 insertions(+), 7 deletions(-) - create mode 100644 include/grub/stack_protector.h - -diff --git a/configure.ac b/configure.ac -index 9323c125469..f335874cb9d 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1330,12 +1330,41 @@ fi] - - CFLAGS="$TARGET_CFLAGS" - --# Smashing stack protector. -+# Stack smashing protector. - grub_CHECK_STACK_PROTECTOR --# Need that, because some distributions ship compilers that include --# `-fstack-protector' in the default specs. --if test "x$ssp_possible" = xyes; then -- TARGET_CFLAGS="$TARGET_CFLAGS -fno-stack-protector" -+AC_ARG_ENABLE([stack-protector], -+ AS_HELP_STRING([--enable-stack-protector], -+ [enable the stack protector]), -+ [], -+ [enable_stack_protector=no]) -+if test "x$enable_stack_protector" = xno; then -+ if test "x$ssp_possible" = xyes; then -+ # Need that, because some distributions ship compilers that include -+ # `-fstack-protector' in the default specs. -+ TARGET_CFLAGS="$TARGET_CFLAGS -fno-stack-protector" -+ fi -+elif test "x$platform" != xefi; then -+ AC_MSG_ERROR([--enable-stack-protector is only supported on EFI platforms]) -+elif test "x$ssp_global_possible" != xyes; then -+ AC_MSG_ERROR([--enable-stack-protector is not supported (compiler doesn't support -mstack-protector-guard=global)]) -+else -+ TARGET_CFLAGS="$TARGET_CFLAGS -mstack-protector-guard=global" -+ if test "x$enable_stack_protector" = xyes; then -+ if test "x$ssp_possible" != xyes; then -+ AC_MSG_ERROR([--enable-stack-protector is not supported (compiler doesn't support -fstack-protector)]) -+ fi -+ TARGET_CFLAGS="$TARGET_CFLAGS -fstack-protector" -+ elif test "x$enable_stack_protector" = xstrong; then -+ if test "x$ssp_strong_possible" != xyes; then -+ AC_MSG_ERROR([--enable-stack-protector=strong is not supported (compiler doesn't support -fstack-protector-strong)]) -+ fi -+ TARGET_CFLAGS="$TARGET_CFLAGS -fstack-protector-strong" -+ else -+ # Note, -fstack-protector-all requires that the protector is disabled for -+ # functions that appear in the call stack when the canary is initialized. -+ AC_MSG_ERROR([invalid value $enable_stack_protector for --enable-stack-protector]) -+ fi -+ TARGET_CPPFLAGS="$TARGET_CPPFLAGS -DGRUB_STACK_PROTECTOR=1" - fi - - CFLAGS="$TARGET_CFLAGS" -@@ -2229,5 +2258,10 @@ echo "Without liblzma (no support for XZ-compressed mips images) ($liblzma_excus - else - echo "With liblzma from $LIBLZMA (support for XZ-compressed mips images)" - fi -+if test "x$enable_stack_protector" != xno; then -+echo "With stack smashing protector: Yes" -+else -+echo "With stack smashing protector: No" -+fi - echo "*******************************************************" - ] -diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c -index 97bf36906a4..501608f743e 100644 ---- a/grub-core/kern/efi/init.c -+++ b/grub-core/kern/efi/init.c -@@ -28,6 +28,58 @@ - #include - #include - #include -+#include -+ -+#ifdef GRUB_STACK_PROTECTOR -+ -+static grub_efi_guid_t rng_protocol_guid = GRUB_EFI_RNG_PROTOCOL_GUID; -+ -+/* -+ * Don't put this on grub_efi_init()'s local stack to avoid it -+ * getting a stack check. -+ */ -+static grub_efi_uint8_t stack_chk_guard_buf[32]; -+ -+grub_addr_t __stack_chk_guard; -+ -+void __attribute__ ((noreturn)) -+__stack_chk_fail (void) -+{ -+ /* -+ * Assume it's not safe to call into EFI Boot Services. Sorry, that -+ * means no console message here. -+ */ -+ do -+ { -+ /* Do not optimize out the loop. */ -+ asm volatile (""); -+ } -+ while (1); -+} -+ -+static void -+stack_protector_init (void) -+{ -+ grub_efi_rng_protocol_t *rng; -+ -+ /* Set up the stack canary. Make errors here non-fatal for now. */ -+ rng = grub_efi_locate_protocol (&rng_protocol_guid, NULL); -+ if (rng != NULL) -+ { -+ grub_efi_status_t status; -+ -+ status = efi_call_4 (rng->get_rng, rng, NULL, sizeof (stack_chk_guard_buf), -+ stack_chk_guard_buf); -+ if (status == GRUB_EFI_SUCCESS) -+ grub_memcpy (&__stack_chk_guard, stack_chk_guard_buf, sizeof (__stack_chk_guard)); -+ } -+} -+#else -+static void -+stack_protector_init (void) -+{ -+} -+#endif - - grub_addr_t grub_modbase; - -@@ -92,6 +144,8 @@ grub_efi_init (void) - messages. */ - grub_console_init (); - -+ stack_protector_init (); -+ - /* Initialize the memory management system. */ - grub_efi_mm_init (); - -diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h -index a092fddb629..37e7b162874 100644 ---- a/include/grub/efi/api.h -+++ b/include/grub/efi/api.h -@@ -344,6 +344,11 @@ - { 0x89, 0x29, 0x48, 0xbc, 0xd9, 0x0a, 0xd3, 0x1a } \ - } - -+#define GRUB_EFI_RNG_PROTOCOL_GUID \ -+ { 0x3152bca5, 0xeade, 0x433d, \ -+ { 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44 } \ -+ } -+ - struct grub_efi_sal_system_table - { - grub_uint32_t signature; -@@ -2067,6 +2072,20 @@ struct grub_efi_ip6_config_manual_address { - }; - typedef struct grub_efi_ip6_config_manual_address grub_efi_ip6_config_manual_address_t; - -+typedef grub_efi_guid_t grub_efi_rng_algorithm_t; -+ -+struct grub_efi_rng_protocol -+{ -+ grub_efi_status_t (*get_info) (struct grub_efi_rng_protocol *this, -+ grub_efi_uintn_t *rng_algorithm_list_size, -+ grub_efi_rng_algorithm_t *rng_algorithm_list); -+ grub_efi_status_t (*get_rng) (struct grub_efi_rng_protocol *this, -+ grub_efi_rng_algorithm_t *rng_algorithm, -+ grub_efi_uintn_t rng_value_length, -+ grub_efi_uint8_t *rng_value); -+}; -+typedef struct grub_efi_rng_protocol grub_efi_rng_protocol_t; -+ - #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \ - || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) - -diff --git a/include/grub/stack_protector.h b/include/grub/stack_protector.h -new file mode 100644 -index 00000000000..c88dc00b5f9 ---- /dev/null -+++ b/include/grub/stack_protector.h -@@ -0,0 +1,30 @@ -+/* -+ * 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 . -+ */ -+ -+#ifndef GRUB_STACK_PROTECTOR_H -+#define GRUB_STACK_PROTECTOR_H 1 -+ -+#include -+#include -+ -+#ifdef GRUB_STACK_PROTECTOR -+extern grub_addr_t EXPORT_VAR (__stack_chk_guard); -+extern void __attribute__ ((noreturn)) EXPORT_FUNC (__stack_chk_fail) (void); -+#endif -+ -+#endif /* GRUB_STACK_PROTECTOR_H */ -diff --git a/acinclude.m4 b/acinclude.m4 -index 242e829ff23..21238fcfd03 100644 ---- a/acinclude.m4 -+++ b/acinclude.m4 -@@ -324,9 +324,9 @@ fi - ]) - - --dnl Check if the C compiler supports `-fstack-protector'. -+dnl Check if the C compiler supports the stack protector - AC_DEFUN([grub_CHECK_STACK_PROTECTOR],[ --[# Smashing stack protector. -+[# Stack smashing protector. - ssp_possible=yes] - AC_MSG_CHECKING([whether `$CC' accepts `-fstack-protector']) - # Is this a reliable test case? -@@ -343,6 +343,40 @@ else - ssp_possible=no] - AC_MSG_RESULT([no]) - [fi] -+[# Strong stack smashing protector. -+ssp_strong_possible=yes] -+AC_MSG_CHECKING([whether `$CC' accepts `-fstack-protector-strong']) -+# Is this a reliable test case? -+AC_LANG_CONFTEST([AC_LANG_SOURCE([[ -+void foo (void) { volatile char a[8]; a[3]; } -+]])]) -+[# `$CC -c -o ...' might not be portable. But, oh, well... Is calling -+# `ac_compile' like this correct, after all? -+if eval "$ac_compile -S -fstack-protector-strong -o conftest.s" 2> /dev/null; then] -+ AC_MSG_RESULT([yes]) -+ [# Should we clear up other files as well, having called `AC_LANG_CONFTEST'? -+ rm -f conftest.s -+else -+ ssp_strong_possible=no] -+ AC_MSG_RESULT([no]) -+[fi] -+[# Global stack smashing protector. -+ssp_global_possible=yes] -+AC_MSG_CHECKING([whether `$CC' accepts `-mstack-protector-guard=global']) -+# Is this a reliable test case? -+AC_LANG_CONFTEST([AC_LANG_SOURCE([[ -+void foo (void) { volatile char a[8]; a[3]; } -+]])]) -+[# `$CC -c -o ...' might not be portable. But, oh, well... Is calling -+# `ac_compile' like this correct, after all? -+if eval "$ac_compile -S -fstack-protector -mstack-protector-guard=global -o conftest.s" 2> /dev/null; then] -+ AC_MSG_RESULT([yes]) -+ [# Should we clear up other files as well, having called `AC_LANG_CONFTEST'? -+ rm -f conftest.s -+else -+ ssp_global_possible=no] -+ AC_MSG_RESULT([no]) -+[fi] - ]) - - dnl Check if the C compiler supports `-mstack-arg-probe' (Cygwin). -diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am -index a6f1b0dcd06..308ad8850c9 100644 ---- a/grub-core/Makefile.am -+++ b/grub-core/Makefile.am -@@ -92,6 +92,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/stack_protector.h - KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/term.h - KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/time.h - KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/mm_private.h diff --git a/SOURCES/0411-libgcrypt-mpi-Fix-possible-NULL-dereference.patch b/SOURCES/0411-libgcrypt-mpi-Fix-possible-NULL-dereference.patch new file mode 100644 index 0000000..89257f5 --- /dev/null +++ b/SOURCES/0411-libgcrypt-mpi-Fix-possible-NULL-dereference.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Thu, 26 Nov 2020 10:41:54 +0000 +Subject: [PATCH] libgcrypt/mpi: Fix possible NULL dereference + +The code in gcry_mpi_scan() assumes that buffer is not NULL, but there +is no explicit check for that, so we add one. + +Fixes: CID 73757 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/lib/libgcrypt/mpi/mpicoder.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/lib/libgcrypt/mpi/mpicoder.c b/grub-core/lib/libgcrypt/mpi/mpicoder.c +index 7ecad27b23a..6fe38916532 100644 +--- a/grub-core/lib/libgcrypt/mpi/mpicoder.c ++++ b/grub-core/lib/libgcrypt/mpi/mpicoder.c +@@ -379,6 +379,9 @@ gcry_mpi_scan (struct gcry_mpi **ret_mpi, enum gcry_mpi_format format, + unsigned int len; + int secure = (buffer && gcry_is_secure (buffer)); + ++ if (!buffer) ++ return gcry_error (GPG_ERR_INV_ARG); ++ + if (format == GCRYMPI_FMT_SSH) + len = 0; + else diff --git a/SOURCES/0412-syslinux-Fix-memory-leak-while-parsing.patch b/SOURCES/0412-syslinux-Fix-memory-leak-while-parsing.patch new file mode 100644 index 0000000..f85cc51 --- /dev/null +++ b/SOURCES/0412-syslinux-Fix-memory-leak-while-parsing.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Thu, 26 Nov 2020 15:31:53 +0000 +Subject: [PATCH] syslinux: Fix memory leak while parsing + +In syslinux_parse_real() the 2 points where return is being called +didn't release the memory stored in buf which is no longer required. + +Fixes: CID 176634 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/lib/syslinux_parse.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/grub-core/lib/syslinux_parse.c b/grub-core/lib/syslinux_parse.c +index 83e7bdb9161..f477feff1c3 100644 +--- a/grub-core/lib/syslinux_parse.c ++++ b/grub-core/lib/syslinux_parse.c +@@ -737,7 +737,10 @@ syslinux_parse_real (struct syslinux_menu *menu) + && grub_strncasecmp ("help", ptr3, ptr4 - ptr3) == 0)) + { + if (helptext (ptr5, file, menu)) +- return 1; ++ { ++ grub_free (buf); ++ return 1; ++ } + continue; + } + +@@ -757,6 +760,7 @@ syslinux_parse_real (struct syslinux_menu *menu) + } + fail: + grub_file_close (file); ++ grub_free (buf); + return err; + } + diff --git a/SOURCES/0412-util-mkimage-Remove-unused-code-to-add-BSS-section.patch b/SOURCES/0412-util-mkimage-Remove-unused-code-to-add-BSS-section.patch deleted file mode 100644 index fc30054..0000000 --- a/SOURCES/0412-util-mkimage-Remove-unused-code-to-add-BSS-section.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Thu, 11 Feb 2021 17:06:49 +0100 -Subject: [PATCH] util/mkimage: Remove unused code to add BSS section - -The code is compiled out so there is no reason to keep it. - -Additionally, don't set bss_size field since we do not add a BSS section. - -Signed-off-by: Javier Martinez Canillas -Reviewed-by: Daniel Kiper ---- - util/mkimage.c | 17 ----------------- - 1 file changed, 17 deletions(-) - -diff --git a/util/mkimage.c b/util/mkimage.c -index e22d82afa61..7dbd504ec5b 100644 ---- a/util/mkimage.c -+++ b/util/mkimage.c -@@ -1257,7 +1257,6 @@ grub_install_generate_image (const char *dir, const char *prefix, - o->code_size = grub_host_to_target32 (layout.exec_size); - o->data_size = grub_cpu_to_le32 (reloc_addr - layout.exec_size - - header_size); -- o->bss_size = grub_cpu_to_le32 (layout.bss_size); - o->entry_addr = grub_cpu_to_le32 (layout.start_address); - o->code_base = grub_cpu_to_le32 (header_size); - -@@ -1295,7 +1294,6 @@ grub_install_generate_image (const char *dir, const char *prefix, - o->code_size = grub_host_to_target32 (layout.exec_size); - o->data_size = grub_cpu_to_le32 (reloc_addr - layout.exec_size - - header_size); -- o->bss_size = grub_cpu_to_le32 (layout.bss_size); - o->entry_addr = grub_cpu_to_le32 (layout.start_address); - o->code_base = grub_cpu_to_le32 (header_size); - o->image_base = 0; -@@ -1340,21 +1338,6 @@ grub_install_generate_image (const char *dir, const char *prefix, - = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA - | GRUB_PE32_SCN_MEM_READ - | GRUB_PE32_SCN_MEM_WRITE); -- --#if 0 -- bss_section = data_section + 1; -- strcpy (bss_section->name, ".bss"); -- bss_section->virtual_size = grub_cpu_to_le32 (layout.bss_size); -- bss_section->virtual_address = grub_cpu_to_le32 (header_size + layout.kernel_size); -- bss_section->raw_data_size = 0; -- bss_section->raw_data_offset = 0; -- bss_section->characteristics -- = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_MEM_READ -- | GRUB_PE32_SCN_MEM_WRITE -- | GRUB_PE32_SCN_ALIGN_64BYTES -- | GRUB_PE32_SCN_CNT_INITIALIZED_DATA -- | 0x80); --#endif - - mods_section = data_section + 1; - strcpy (mods_section->name, "mods"); diff --git a/SOURCES/0413-normal-completion-Fix-leaking-of-memory-when-process.patch b/SOURCES/0413-normal-completion-Fix-leaking-of-memory-when-process.patch new file mode 100644 index 0000000..984c608 --- /dev/null +++ b/SOURCES/0413-normal-completion-Fix-leaking-of-memory-when-process.patch @@ -0,0 +1,49 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Fri, 4 Dec 2020 18:56:48 +0000 +Subject: [PATCH] normal/completion: Fix leaking of memory when processing a + completion + +It is possible for the code to reach the end of the function without +freeing the memory allocated to argv and argc still to be 0. + +We should always call grub_free(argv). The grub_free() will handle +a NULL argument correctly if it reaches that code without the memory +being allocated. + +Fixes: CID 96672 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/normal/completion.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/grub-core/normal/completion.c b/grub-core/normal/completion.c +index 93aa0d8eda8..5036bcf2d98 100644 +--- a/grub-core/normal/completion.c ++++ b/grub-core/normal/completion.c +@@ -401,8 +401,8 @@ char * + grub_normal_do_completion (char *buf, int *restore, + void (*hook) (const char *, grub_completion_type_t, int)) + { +- int argc; +- char **argv; ++ int argc = 0; ++ char **argv = NULL; + + /* Initialize variables. */ + match = 0; +@@ -517,10 +517,8 @@ grub_normal_do_completion (char *buf, int *restore, + + fail: + if (argc != 0) +- { +- grub_free (argv[0]); +- grub_free (argv); +- } ++ grub_free (argv[0]); ++ grub_free (argv); + grub_free (match); + grub_errno = GRUB_ERR_NONE; + diff --git a/SOURCES/0413-util-mkimage-Use-grub_host_to_target32-instead-of-gr.patch b/SOURCES/0413-util-mkimage-Use-grub_host_to_target32-instead-of-gr.patch deleted file mode 100644 index 8135069..0000000 --- a/SOURCES/0413-util-mkimage-Use-grub_host_to_target32-instead-of-gr.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Mon, 15 Feb 2021 13:59:21 +0100 -Subject: [PATCH] util/mkimage: Use grub_host_to_target32() instead of - grub_cpu_to_le32() - -The latter doesn't take into account the target image endianness. There is -a grub_cpu_to_le32_compile_time() but no compile time variant for function -grub_host_to_target32(). So, let's keep using the other one for this case. - -Signed-off-by: Peter Jones -Signed-off-by: Javier Martinez Canillas -Reviewed-by: Daniel Kiper ---- - util/mkimage.c | 44 ++++++++++++++++++++++---------------------- - 1 file changed, 22 insertions(+), 22 deletions(-) - -diff --git a/util/mkimage.c b/util/mkimage.c -index 7dbd504ec5b..131f3ec75e2 100644 ---- a/util/mkimage.c -+++ b/util/mkimage.c -@@ -1255,10 +1255,10 @@ grub_install_generate_image (const char *dir, const char *prefix, - + sizeof (struct grub_pe32_coff_header)); - o->magic = grub_host_to_target16 (GRUB_PE32_PE32_MAGIC); - o->code_size = grub_host_to_target32 (layout.exec_size); -- o->data_size = grub_cpu_to_le32 (reloc_addr - layout.exec_size -+ o->data_size = grub_host_to_target32 (reloc_addr - layout.exec_size - - header_size); -- o->entry_addr = grub_cpu_to_le32 (layout.start_address); -- o->code_base = grub_cpu_to_le32 (header_size); -+ o->entry_addr = grub_host_to_target32 (layout.start_address); -+ o->code_base = grub_host_to_target32 (header_size); - - o->data_base = grub_host_to_target32 (header_size + layout.exec_size); - -@@ -1292,10 +1292,10 @@ grub_install_generate_image (const char *dir, const char *prefix, - + sizeof (struct grub_pe32_coff_header)); - o->magic = grub_host_to_target16 (GRUB_PE32_PE64_MAGIC); - o->code_size = grub_host_to_target32 (layout.exec_size); -- o->data_size = grub_cpu_to_le32 (reloc_addr - layout.exec_size -+ o->data_size = grub_host_to_target32 (reloc_addr - layout.exec_size - - header_size); -- o->entry_addr = grub_cpu_to_le32 (layout.start_address); -- o->code_base = grub_cpu_to_le32 (header_size); -+ o->entry_addr = grub_host_to_target32 (layout.start_address); -+ o->code_base = grub_host_to_target32 (header_size); - o->image_base = 0; - o->section_alignment = grub_host_to_target32 (image_target->section_align); - o->file_alignment = grub_host_to_target32 (image_target->section_align); -@@ -1319,10 +1319,10 @@ grub_install_generate_image (const char *dir, const char *prefix, - /* The sections. */ - text_section = sections; - strcpy (text_section->name, ".text"); -- text_section->virtual_size = grub_cpu_to_le32 (layout.exec_size); -- text_section->virtual_address = grub_cpu_to_le32 (header_size); -- text_section->raw_data_size = grub_cpu_to_le32 (layout.exec_size); -- text_section->raw_data_offset = grub_cpu_to_le32 (header_size); -+ text_section->virtual_size = grub_host_to_target32 (layout.exec_size); -+ text_section->virtual_address = grub_host_to_target32 (header_size); -+ text_section->raw_data_size = grub_host_to_target32 (layout.exec_size); -+ text_section->raw_data_offset = grub_host_to_target32 (header_size); - text_section->characteristics = grub_cpu_to_le32_compile_time ( - GRUB_PE32_SCN_CNT_CODE - | GRUB_PE32_SCN_MEM_EXECUTE -@@ -1330,10 +1330,10 @@ grub_install_generate_image (const char *dir, const char *prefix, - - data_section = text_section + 1; - strcpy (data_section->name, ".data"); -- data_section->virtual_size = grub_cpu_to_le32 (layout.kernel_size - layout.exec_size); -- data_section->virtual_address = grub_cpu_to_le32 (header_size + layout.exec_size); -- data_section->raw_data_size = grub_cpu_to_le32 (layout.kernel_size - layout.exec_size); -- data_section->raw_data_offset = grub_cpu_to_le32 (header_size + layout.exec_size); -+ data_section->virtual_size = grub_host_to_target32 (layout.kernel_size - layout.exec_size); -+ data_section->virtual_address = grub_host_to_target32 (header_size + layout.exec_size); -+ data_section->raw_data_size = grub_host_to_target32 (layout.kernel_size - layout.exec_size); -+ data_section->raw_data_offset = grub_host_to_target32 (header_size + layout.exec_size); - data_section->characteristics - = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA - | GRUB_PE32_SCN_MEM_READ -@@ -1341,10 +1341,10 @@ grub_install_generate_image (const char *dir, const char *prefix, - - mods_section = data_section + 1; - strcpy (mods_section->name, "mods"); -- mods_section->virtual_size = grub_cpu_to_le32 (reloc_addr - layout.kernel_size - header_size); -- mods_section->virtual_address = grub_cpu_to_le32 (header_size + layout.kernel_size + layout.bss_size); -- mods_section->raw_data_size = grub_cpu_to_le32 (reloc_addr - layout.kernel_size - header_size); -- mods_section->raw_data_offset = grub_cpu_to_le32 (header_size + layout.kernel_size); -+ mods_section->virtual_size = grub_host_to_target32 (reloc_addr - layout.kernel_size - header_size); -+ mods_section->virtual_address = grub_host_to_target32 (header_size + layout.kernel_size + layout.bss_size); -+ mods_section->raw_data_size = grub_host_to_target32 (reloc_addr - layout.kernel_size - header_size); -+ mods_section->raw_data_offset = grub_host_to_target32 (header_size + layout.kernel_size); - mods_section->characteristics - = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA - | GRUB_PE32_SCN_MEM_READ -@@ -1352,10 +1352,10 @@ grub_install_generate_image (const char *dir, const char *prefix, - - reloc_section = mods_section + 1; - strcpy (reloc_section->name, ".reloc"); -- reloc_section->virtual_size = grub_cpu_to_le32 (layout.reloc_size); -- reloc_section->virtual_address = grub_cpu_to_le32 (reloc_addr + layout.bss_size); -- reloc_section->raw_data_size = grub_cpu_to_le32 (layout.reloc_size); -- reloc_section->raw_data_offset = grub_cpu_to_le32 (reloc_addr); -+ reloc_section->virtual_size = grub_host_to_target32 (layout.reloc_size); -+ reloc_section->virtual_address = grub_host_to_target32 (reloc_addr + layout.bss_size); -+ reloc_section->raw_data_size = grub_host_to_target32 (layout.reloc_size); -+ reloc_section->raw_data_offset = grub_host_to_target32 (reloc_addr); - reloc_section->characteristics - = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA - | GRUB_PE32_SCN_MEM_DISCARDABLE diff --git a/SOURCES/0414-commands-hashsum-Fix-a-memory-leak.patch b/SOURCES/0414-commands-hashsum-Fix-a-memory-leak.patch new file mode 100644 index 0000000..3508882 --- /dev/null +++ b/SOURCES/0414-commands-hashsum-Fix-a-memory-leak.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Tue, 1 Dec 2020 23:41:24 +0000 +Subject: [PATCH] commands/hashsum: Fix a memory leak + +check_list() uses grub_file_getline(), which allocates a buffer. +If the hash list file contains invalid lines, the function leaks +this buffer when it returns an error. + +Fixes: CID 176635 + +Signed-off-by: Chris Coulson +Reviewed-by: Daniel Kiper +--- + grub-core/commands/hashsum.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/grub-core/commands/hashsum.c b/grub-core/commands/hashsum.c +index 456ba908b6f..b8a22b0c8bb 100644 +--- a/grub-core/commands/hashsum.c ++++ b/grub-core/commands/hashsum.c +@@ -128,11 +128,17 @@ check_list (const gcry_md_spec_t *hash, const char *hashfilename, + high = hextoval (*p++); + low = hextoval (*p++); + if (high < 0 || low < 0) +- return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list"); ++ { ++ grub_free (buf); ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list"); ++ } + expected[i] = (high << 4) | low; + } + if ((p[0] != ' ' && p[0] != '\t') || (p[1] != ' ' && p[1] != '\t')) +- return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list"); ++ { ++ grub_free (buf); ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list"); ++ } + p += 2; + if (prefix) + { +@@ -140,7 +146,10 @@ check_list (const gcry_md_spec_t *hash, const char *hashfilename, + + filename = grub_xasprintf ("%s/%s", prefix, p); + if (!filename) +- return grub_errno; ++ { ++ grub_free (buf); ++ return grub_errno; ++ } + file = grub_file_open (filename, GRUB_FILE_TYPE_TO_HASH + | (!uncompress ? GRUB_FILE_TYPE_NO_DECOMPRESS + : GRUB_FILE_TYPE_NONE)); diff --git a/SOURCES/0414-util-mkimage-Always-use-grub_host_to_target32-to-ini.patch b/SOURCES/0414-util-mkimage-Always-use-grub_host_to_target32-to-ini.patch deleted file mode 100644 index 92f9875..0000000 --- a/SOURCES/0414-util-mkimage-Always-use-grub_host_to_target32-to-ini.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Mon, 15 Feb 2021 14:14:24 +0100 -Subject: [PATCH] util/mkimage: Always use grub_host_to_target32() to - initialize PE stack and heap stuff - -This change does not impact final result of initialization itself. -However, it eases PE code unification in subsequent patches. - -Signed-off-by: Peter Jones -Signed-off-by: Javier Martinez Canillas -Reviewed-by: Daniel Kiper ---- - util/mkimage.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/util/mkimage.c b/util/mkimage.c -index 131f3ec75e2..25ea4ea9711 100644 ---- a/util/mkimage.c -+++ b/util/mkimage.c -@@ -1304,10 +1304,10 @@ grub_install_generate_image (const char *dir, const char *prefix, - o->subsystem = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION); - - /* Do these really matter? */ -- o->stack_reserve_size = grub_host_to_target64 (0x10000); -- o->stack_commit_size = grub_host_to_target64 (0x10000); -- o->heap_reserve_size = grub_host_to_target64 (0x10000); -- o->heap_commit_size = grub_host_to_target64 (0x10000); -+ o->stack_reserve_size = grub_host_to_target32 (0x10000); -+ o->stack_commit_size = grub_host_to_target32 (0x10000); -+ o->heap_reserve_size = grub_host_to_target32 (0x10000); -+ o->heap_commit_size = grub_host_to_target32 (0x10000); - - o->num_data_directories - = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); diff --git a/SOURCES/0415-util-mkimage-Unify-more-of-the-PE32-and-PE32-header-.patch b/SOURCES/0415-util-mkimage-Unify-more-of-the-PE32-and-PE32-header-.patch deleted file mode 100644 index 78e18fb..0000000 --- a/SOURCES/0415-util-mkimage-Unify-more-of-the-PE32-and-PE32-header-.patch +++ /dev/null @@ -1,165 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Fri, 19 Feb 2021 14:22:13 +0100 -Subject: [PATCH] util/mkimage: Unify more of the PE32 and PE32+ header set-up - -There's quite a bit of code duplication in the code that sets the optional -header for PE32 and PE32+. The two are very similar with the exception of -a few fields that have type grub_uint64_t instead of grub_uint32_t. - -Factor out the common code and add a PE_OHDR() macro that simplifies the -set-up and make the code more readable. - -Signed-off-by: Peter Jones -Signed-off-by: Javier Martinez Canillas -Reviewed-by: Daniel Kiper ---- - util/mkimage.c | 111 ++++++++++++++++++++++++++------------------------------- - 1 file changed, 51 insertions(+), 60 deletions(-) - -diff --git a/util/mkimage.c b/util/mkimage.c -index 25ea4ea9711..f7bf69efec2 100644 ---- a/util/mkimage.c -+++ b/util/mkimage.c -@@ -771,6 +771,21 @@ grub_install_get_image_targets_string (void) - return formats; - } - -+/* -+ * tmp_ is just here so the compiler knows we'll never derefernce a NULL. -+ * It should get fully optimized away. -+ */ -+#define PE_OHDR(o32, o64, field) (*( \ -+{ \ -+ __typeof__((o64)->field) tmp_; \ -+ __typeof__((o64)->field) *ret_ = &tmp_; \ -+ if (o32) \ -+ ret_ = (void *)(&((o32)->field)); \ -+ else if (o64) \ -+ ret_ = (void *)(&((o64)->field)); \ -+ ret_; \ -+})) -+ - void - grub_install_generate_image (const char *dir, const char *prefix, - FILE *out, const char *outname, char *mods[], -@@ -1205,6 +1220,8 @@ grub_install_generate_image (const char *dir, const char *prefix, - static const grub_uint8_t stub[] = GRUB_PE32_MSDOS_STUB; - int header_size; - int reloc_addr; -+ struct grub_pe32_optional_header *o32 = NULL; -+ struct grub_pe64_optional_header *o64 = NULL; - - if (image_target->voidp_sizeof == 4) - header_size = EFI32_HEADER_SIZE; -@@ -1246,76 +1263,50 @@ grub_install_generate_image (const char *dir, const char *prefix, - /* The PE Optional header. */ - if (image_target->voidp_sizeof == 4) - { -- struct grub_pe32_optional_header *o; -- - c->optional_header_size = grub_host_to_target16 (sizeof (struct grub_pe32_optional_header)); - -- o = (struct grub_pe32_optional_header *) -- (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE -- + sizeof (struct grub_pe32_coff_header)); -- o->magic = grub_host_to_target16 (GRUB_PE32_PE32_MAGIC); -- o->code_size = grub_host_to_target32 (layout.exec_size); -- o->data_size = grub_host_to_target32 (reloc_addr - layout.exec_size -- - header_size); -- o->entry_addr = grub_host_to_target32 (layout.start_address); -- o->code_base = grub_host_to_target32 (header_size); -+ o32 = (struct grub_pe32_optional_header *) -+ (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE + -+ sizeof (struct grub_pe32_coff_header)); -+ o32->magic = grub_host_to_target16 (GRUB_PE32_PE32_MAGIC); -+ o32->data_base = grub_host_to_target32 (header_size + layout.exec_size); - -- o->data_base = grub_host_to_target32 (header_size + layout.exec_size); -- -- o->image_base = 0; -- o->section_alignment = grub_host_to_target32 (image_target->section_align); -- o->file_alignment = grub_host_to_target32 (image_target->section_align); -- o->image_size = grub_host_to_target32 (pe_size); -- o->header_size = grub_host_to_target32 (header_size); -- o->subsystem = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION); -- -- /* Do these really matter? */ -- o->stack_reserve_size = grub_host_to_target32 (0x10000); -- o->stack_commit_size = grub_host_to_target32 (0x10000); -- o->heap_reserve_size = grub_host_to_target32 (0x10000); -- o->heap_commit_size = grub_host_to_target32 (0x10000); -- -- o->num_data_directories = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); -- -- o->base_relocation_table.rva = grub_host_to_target32 (reloc_addr); -- o->base_relocation_table.size = grub_host_to_target32 (layout.reloc_size); -- sections = o + 1; -+ sections = o32 + 1; - } - else - { -- struct grub_pe64_optional_header *o; -- - c->optional_header_size = grub_host_to_target16 (sizeof (struct grub_pe64_optional_header)); - -- o = (struct grub_pe64_optional_header *) -- (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE -- + sizeof (struct grub_pe32_coff_header)); -- o->magic = grub_host_to_target16 (GRUB_PE32_PE64_MAGIC); -- o->code_size = grub_host_to_target32 (layout.exec_size); -- o->data_size = grub_host_to_target32 (reloc_addr - layout.exec_size -- - header_size); -- o->entry_addr = grub_host_to_target32 (layout.start_address); -- o->code_base = grub_host_to_target32 (header_size); -- o->image_base = 0; -- o->section_alignment = grub_host_to_target32 (image_target->section_align); -- o->file_alignment = grub_host_to_target32 (image_target->section_align); -- o->image_size = grub_host_to_target32 (pe_size); -- o->header_size = grub_host_to_target32 (header_size); -- o->subsystem = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION); -+ o64 = (struct grub_pe64_optional_header *) -+ (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE + -+ sizeof (struct grub_pe32_coff_header)); -+ o64->magic = grub_host_to_target16 (GRUB_PE32_PE64_MAGIC); - -- /* Do these really matter? */ -- o->stack_reserve_size = grub_host_to_target32 (0x10000); -- o->stack_commit_size = grub_host_to_target32 (0x10000); -- o->heap_reserve_size = grub_host_to_target32 (0x10000); -- o->heap_commit_size = grub_host_to_target32 (0x10000); -- -- o->num_data_directories -- = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); -- -- o->base_relocation_table.rva = grub_host_to_target32 (reloc_addr); -- o->base_relocation_table.size = grub_host_to_target32 (layout.reloc_size); -- sections = o + 1; -+ sections = o64 + 1; - } -+ -+ PE_OHDR (o32, o64, code_size) = grub_host_to_target32 (layout.exec_size); -+ PE_OHDR (o32, o64, data_size) = grub_host_to_target32 (reloc_addr - layout.exec_size - header_size); -+ PE_OHDR (o32, o64, entry_addr) = grub_host_to_target32 (layout.start_address); -+ PE_OHDR (o32, o64, code_base) = grub_host_to_target32 (header_size); -+ -+ PE_OHDR (o32, o64, image_base) = 0; -+ PE_OHDR (o32, o64, section_alignment) = grub_host_to_target32 (image_target->section_align); -+ PE_OHDR (o32, o64, file_alignment) = grub_host_to_target32 (GRUB_PE32_FILE_ALIGNMENT); -+ PE_OHDR (o32, o64, image_size) = grub_host_to_target32 (pe_size); -+ PE_OHDR (o32, o64, header_size) = grub_host_to_target32 (header_size); -+ PE_OHDR (o32, o64, subsystem) = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION); -+ -+ /* Do these really matter? */ -+ PE_OHDR (o32, o64, stack_reserve_size) = grub_host_to_target32 (0x10000); -+ PE_OHDR (o32, o64, stack_commit_size) = grub_host_to_target32 (0x10000); -+ PE_OHDR (o32, o64, heap_reserve_size) = grub_host_to_target32 (0x10000); -+ PE_OHDR (o32, o64, heap_commit_size) = grub_host_to_target32 (0x10000); -+ -+ PE_OHDR (o32, o64, num_data_directories) = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); -+ PE_OHDR (o32, o64, base_relocation_table.rva) = grub_host_to_target32 (reloc_addr); -+ PE_OHDR (o32, o64, base_relocation_table.size) = grub_host_to_target32 (layout.reloc_size); -+ - /* The sections. */ - text_section = sections; - strcpy (text_section->name, ".text"); diff --git a/SOURCES/0415-video-efi_gop-Remove-unnecessary-return-value-of-gru.patch b/SOURCES/0415-video-efi_gop-Remove-unnecessary-return-value-of-gru.patch new file mode 100644 index 0000000..fce5f99 --- /dev/null +++ b/SOURCES/0415-video-efi_gop-Remove-unnecessary-return-value-of-gru.patch @@ -0,0 +1,91 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Tue, 8 Dec 2020 21:14:31 +0000 +Subject: [PATCH] video/efi_gop: Remove unnecessary return value of + grub_video_gop_fill_mode_info() + +The return value of grub_video_gop_fill_mode_info() is never able to be +anything other than GRUB_ERR_NONE. So, rather than continue to return +a value and checking it each time, it is more correct to redefine the +function to not return anything and remove checks of its return value +altogether. + +Fixes: CID 96701 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/video/efi_gop.c | 25 ++++++------------------- + 1 file changed, 6 insertions(+), 19 deletions(-) + +diff --git a/grub-core/video/efi_gop.c b/grub-core/video/efi_gop.c +index c9e40e8d4e9..9fcc41ac03c 100644 +--- a/grub-core/video/efi_gop.c ++++ b/grub-core/video/efi_gop.c +@@ -229,7 +229,7 @@ grub_video_gop_fill_real_mode_info (unsigned mode, + return GRUB_ERR_NONE; + } + +-static grub_err_t ++static void + grub_video_gop_fill_mode_info (unsigned mode, + struct grub_efi_gop_mode_info *in, + struct grub_video_mode_info *out) +@@ -254,8 +254,6 @@ grub_video_gop_fill_mode_info (unsigned mode, + out->blit_format = GRUB_VIDEO_BLIT_FORMAT_BGRA_8888; + out->mode_type |= (GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED + | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP); +- +- return GRUB_ERR_NONE; + } + + static int +@@ -268,7 +266,6 @@ grub_video_gop_iterate (int (*hook) (const struct grub_video_mode_info *info, vo + grub_efi_uintn_t size; + grub_efi_status_t status; + struct grub_efi_gop_mode_info *info = NULL; +- grub_err_t err; + struct grub_video_mode_info mode_info; + + status = efi_call_4 (gop->query_mode, gop, mode, &size, &info); +@@ -279,12 +276,7 @@ grub_video_gop_iterate (int (*hook) (const struct grub_video_mode_info *info, vo + continue; + } + +- err = grub_video_gop_fill_mode_info (mode, info, &mode_info); +- if (err) +- { +- grub_errno = GRUB_ERR_NONE; +- continue; +- } ++ grub_video_gop_fill_mode_info (mode, info, &mode_info); + if (hook (&mode_info, hook_arg)) + return 1; + } +@@ -468,13 +460,8 @@ grub_video_gop_setup (unsigned int width, unsigned int height, + + info = gop->mode->info; + +- err = grub_video_gop_fill_mode_info (gop->mode->mode, info, +- &framebuffer.mode_info); +- if (err) +- { +- grub_dprintf ("video", "GOP: couldn't fill mode info\n"); +- return err; +- } ++ grub_video_gop_fill_mode_info (gop->mode->mode, info, ++ &framebuffer.mode_info); + + framebuffer.ptr = (void *) (grub_addr_t) gop->mode->fb_base; + framebuffer.offscreen +@@ -488,8 +475,8 @@ grub_video_gop_setup (unsigned int width, unsigned int height, + { + grub_dprintf ("video", "GOP: couldn't allocate shadow\n"); + grub_errno = 0; +- err = grub_video_gop_fill_mode_info (gop->mode->mode, info, +- &framebuffer.mode_info); ++ grub_video_gop_fill_mode_info (gop->mode->mode, info, ++ &framebuffer.mode_info); + buffer = framebuffer.ptr; + } + diff --git a/SOURCES/0416-util-mkimage-Reorder-PE-optional-header-fields-set-u.patch b/SOURCES/0416-util-mkimage-Reorder-PE-optional-header-fields-set-u.patch deleted file mode 100644 index c073598..0000000 --- a/SOURCES/0416-util-mkimage-Reorder-PE-optional-header-fields-set-u.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Mon, 15 Feb 2021 14:21:48 +0100 -Subject: [PATCH] util/mkimage: Reorder PE optional header fields set-up - -This makes the PE32 and PE32+ header fields set-up easier to follow by -setting them closer to the initialization of their related sections. - -Signed-off-by: Peter Jones -Signed-off-by: Javier Martinez Canillas -Reviewed-by: Daniel Kiper ---- - util/mkimage.c | 16 ++++++++-------- - 1 file changed, 8 insertions(+), 8 deletions(-) - -diff --git a/util/mkimage.c b/util/mkimage.c -index f7bf69efec2..18a92c68d15 100644 ---- a/util/mkimage.c -+++ b/util/mkimage.c -@@ -1285,16 +1285,12 @@ grub_install_generate_image (const char *dir, const char *prefix, - sections = o64 + 1; - } - -- PE_OHDR (o32, o64, code_size) = grub_host_to_target32 (layout.exec_size); -- PE_OHDR (o32, o64, data_size) = grub_host_to_target32 (reloc_addr - layout.exec_size - header_size); -+ PE_OHDR (o32, o64, header_size) = grub_host_to_target32 (header_size); - PE_OHDR (o32, o64, entry_addr) = grub_host_to_target32 (layout.start_address); -- PE_OHDR (o32, o64, code_base) = grub_host_to_target32 (header_size); -- - PE_OHDR (o32, o64, image_base) = 0; -+ PE_OHDR (o32, o64, image_size) = grub_host_to_target32 (pe_size); - PE_OHDR (o32, o64, section_alignment) = grub_host_to_target32 (image_target->section_align); - PE_OHDR (o32, o64, file_alignment) = grub_host_to_target32 (GRUB_PE32_FILE_ALIGNMENT); -- PE_OHDR (o32, o64, image_size) = grub_host_to_target32 (pe_size); -- PE_OHDR (o32, o64, header_size) = grub_host_to_target32 (header_size); - PE_OHDR (o32, o64, subsystem) = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION); - - /* Do these really matter? */ -@@ -1304,10 +1300,10 @@ grub_install_generate_image (const char *dir, const char *prefix, - PE_OHDR (o32, o64, heap_commit_size) = grub_host_to_target32 (0x10000); - - PE_OHDR (o32, o64, num_data_directories) = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); -- PE_OHDR (o32, o64, base_relocation_table.rva) = grub_host_to_target32 (reloc_addr); -- PE_OHDR (o32, o64, base_relocation_table.size) = grub_host_to_target32 (layout.reloc_size); - - /* The sections. */ -+ PE_OHDR (o32, o64, code_base) = grub_host_to_target32 (header_size); -+ PE_OHDR (o32, o64, code_size) = grub_host_to_target32 (layout.exec_size); - text_section = sections; - strcpy (text_section->name, ".text"); - text_section->virtual_size = grub_host_to_target32 (layout.exec_size); -@@ -1319,6 +1315,8 @@ grub_install_generate_image (const char *dir, const char *prefix, - | GRUB_PE32_SCN_MEM_EXECUTE - | GRUB_PE32_SCN_MEM_READ); - -+ PE_OHDR (o32, o64, data_size) = grub_host_to_target32 (reloc_addr - layout.exec_size - header_size); -+ - data_section = text_section + 1; - strcpy (data_section->name, ".data"); - data_section->virtual_size = grub_host_to_target32 (layout.kernel_size - layout.exec_size); -@@ -1341,6 +1339,8 @@ grub_install_generate_image (const char *dir, const char *prefix, - | GRUB_PE32_SCN_MEM_READ - | GRUB_PE32_SCN_MEM_WRITE); - -+ PE_OHDR (o32, o64, base_relocation_table.rva) = grub_host_to_target32 (reloc_addr); -+ PE_OHDR (o32, o64, base_relocation_table.size) = grub_host_to_target32 (layout.reloc_size); - reloc_section = mods_section + 1; - strcpy (reloc_section->name, ".reloc"); - reloc_section->virtual_size = grub_host_to_target32 (layout.reloc_size); diff --git a/SOURCES/0416-video-fb-fbfill-Fix-potential-integer-overflow.patch b/SOURCES/0416-video-fb-fbfill-Fix-potential-integer-overflow.patch new file mode 100644 index 0000000..895fd9d --- /dev/null +++ b/SOURCES/0416-video-fb-fbfill-Fix-potential-integer-overflow.patch @@ -0,0 +1,75 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Wed, 4 Nov 2020 15:10:51 +0000 +Subject: [PATCH] video/fb/fbfill: Fix potential integer overflow + +The multiplication of 2 unsigned 32-bit integers may overflow before +promotion to unsigned 64-bit. We should ensure that the multiplication +is done with overflow detection. Additionally, use grub_sub() for +subtraction. + +Fixes: CID 73640, CID 73697, CID 73702, CID 73823 + +Signed-off-by: Darren Kenny +Signed-off-by: Marco A Benatto +Reviewed-by: Daniel Kiper +--- + grub-core/video/fb/fbfill.c | 17 +++++++++++++---- + 1 file changed, 13 insertions(+), 4 deletions(-) + +diff --git a/grub-core/video/fb/fbfill.c b/grub-core/video/fb/fbfill.c +index 11816d07a0b..a37acd1e293 100644 +--- a/grub-core/video/fb/fbfill.c ++++ b/grub-core/video/fb/fbfill.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + #include + + /* Generic filler that works for every supported mode. */ +@@ -61,7 +62,9 @@ grub_video_fbfill_direct32 (struct grub_video_fbblit_info *dst, + + /* Calculate the number of bytes to advance from the end of one line + to the beginning of the next line. */ +- rowskip = dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width; ++ if (grub_mul (dst->mode_info->bytes_per_pixel, width, &rowskip) || ++ grub_sub (dst->mode_info->pitch, rowskip, &rowskip)) ++ return; + + /* Get the start address. */ + dstptr = grub_video_fb_get_video_ptr (dst, x, y); +@@ -98,7 +101,9 @@ grub_video_fbfill_direct24 (struct grub_video_fbblit_info *dst, + #endif + /* Calculate the number of bytes to advance from the end of one line + to the beginning of the next line. */ +- rowskip = dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width; ++ if (grub_mul (dst->mode_info->bytes_per_pixel, width, &rowskip) || ++ grub_sub (dst->mode_info->pitch, rowskip, &rowskip)) ++ return; + + /* Get the start address. */ + dstptr = grub_video_fb_get_video_ptr (dst, x, y); +@@ -131,7 +136,9 @@ grub_video_fbfill_direct16 (struct grub_video_fbblit_info *dst, + + /* Calculate the number of bytes to advance from the end of one line + to the beginning of the next line. */ +- rowskip = (dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width); ++ if (grub_mul (dst->mode_info->bytes_per_pixel, width, &rowskip) || ++ grub_sub (dst->mode_info->pitch, rowskip, &rowskip)) ++ return; + + /* Get the start address. */ + dstptr = grub_video_fb_get_video_ptr (dst, x, y); +@@ -161,7 +168,9 @@ grub_video_fbfill_direct8 (struct grub_video_fbblit_info *dst, + + /* Calculate the number of bytes to advance from the end of one line + to the beginning of the next line. */ +- rowskip = dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width; ++ if (grub_mul (dst->mode_info->bytes_per_pixel, width, &rowskip) || ++ grub_sub (dst->mode_info->pitch, rowskip, &rowskip)) ++ return; + + /* Get the start address. */ + dstptr = grub_video_fb_get_video_ptr (dst, x, y); diff --git a/SOURCES/0417-util-mkimage-Improve-data_size-value-calculation.patch b/SOURCES/0417-util-mkimage-Improve-data_size-value-calculation.patch deleted file mode 100644 index f20e244..0000000 --- a/SOURCES/0417-util-mkimage-Improve-data_size-value-calculation.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 11 Feb 2021 17:07:33 +0100 -Subject: [PATCH] util/mkimage: Improve data_size value calculation - -According to "Microsoft Portable Executable and Common Object File Format -Specification", the Optional Header SizeOfInitializedData field contains: - - Size of the initialized data section, or the sum of all such sections if - there are multiple data sections. - -Make this explicit by adding the GRUB kernel data size to the sum of all -the modules sizes. The ALIGN_UP() is not required by the PE spec but do -it to avoid alignment issues. - -Signed-off-by: Peter Jones -Signed-off-by: Javier Martinez Canillas -Reviewed-by: Daniel Kiper ---- - util/mkimage.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/util/mkimage.c b/util/mkimage.c -index 18a92c68d15..ed2d59d995f 100644 ---- a/util/mkimage.c -+++ b/util/mkimage.c -@@ -1213,6 +1213,7 @@ grub_install_generate_image (const char *dir, const char *prefix, - void *pe_img; - grub_uint8_t *header; - void *sections; -+ size_t scn_size; - size_t pe_size; - struct grub_pe32_coff_header *c; - struct grub_pe32_section_table *text_section, *data_section; -@@ -1315,7 +1316,10 @@ grub_install_generate_image (const char *dir, const char *prefix, - | GRUB_PE32_SCN_MEM_EXECUTE - | GRUB_PE32_SCN_MEM_READ); - -- PE_OHDR (o32, o64, data_size) = grub_host_to_target32 (reloc_addr - layout.exec_size - header_size); -+ scn_size = ALIGN_UP (layout.kernel_size - layout.exec_size, GRUB_PE32_FILE_ALIGNMENT); -+ PE_OHDR (o32, o64, data_size) = grub_host_to_target32 (scn_size + -+ ALIGN_UP (total_module_size, -+ GRUB_PE32_FILE_ALIGNMENT)); - - data_section = text_section + 1; - strcpy (data_section->name, ".data"); diff --git a/SOURCES/0417-video-fb-video_fb-Fix-multiple-integer-overflows.patch b/SOURCES/0417-video-fb-video_fb-Fix-multiple-integer-overflows.patch new file mode 100644 index 0000000..fa61935 --- /dev/null +++ b/SOURCES/0417-video-fb-video_fb-Fix-multiple-integer-overflows.patch @@ -0,0 +1,101 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Wed, 4 Nov 2020 14:43:44 +0000 +Subject: [PATCH] video/fb/video_fb: Fix multiple integer overflows + +The calculation of the unsigned 64-bit value is being generated by +multiplying 2, signed or unsigned, 32-bit integers which may overflow +before promotion to unsigned 64-bit. Fix all of them. + +Fixes: CID 73703, CID 73767, CID 73833 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/video/fb/video_fb.c | 52 ++++++++++++++++++++++++++++++------------- + 1 file changed, 36 insertions(+), 16 deletions(-) + +diff --git a/grub-core/video/fb/video_fb.c b/grub-core/video/fb/video_fb.c +index 1a602c8b251..1c9a138dcdc 100644 +--- a/grub-core/video/fb/video_fb.c ++++ b/grub-core/video/fb/video_fb.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -1417,15 +1418,23 @@ doublebuf_blit_update_screen (void) + { + if (framebuffer.current_dirty.first_line + <= framebuffer.current_dirty.last_line) +- grub_memcpy ((char *) framebuffer.pages[0] +- + framebuffer.current_dirty.first_line +- * framebuffer.back_target->mode_info.pitch, +- (char *) framebuffer.back_target->data +- + framebuffer.current_dirty.first_line +- * framebuffer.back_target->mode_info.pitch, +- framebuffer.back_target->mode_info.pitch +- * (framebuffer.current_dirty.last_line +- - framebuffer.current_dirty.first_line)); ++ { ++ grub_size_t copy_size; ++ ++ if (grub_sub (framebuffer.current_dirty.last_line, ++ framebuffer.current_dirty.first_line, ©_size) || ++ grub_mul (framebuffer.back_target->mode_info.pitch, copy_size, ©_size)) ++ { ++ /* Shouldn't happen, but if it does we've a bug. */ ++ return GRUB_ERR_BUG; ++ } ++ ++ grub_memcpy ((char *) framebuffer.pages[0] + framebuffer.current_dirty.first_line * ++ framebuffer.back_target->mode_info.pitch, ++ (char *) framebuffer.back_target->data + framebuffer.current_dirty.first_line * ++ framebuffer.back_target->mode_info.pitch, ++ copy_size); ++ } + framebuffer.current_dirty.first_line + = framebuffer.back_target->mode_info.height; + framebuffer.current_dirty.last_line = 0; +@@ -1439,7 +1448,7 @@ grub_video_fb_doublebuf_blit_init (struct grub_video_fbrender_target **back, + volatile void *framebuf) + { + grub_err_t err; +- grub_size_t page_size = mode_info.pitch * mode_info.height; ++ grub_size_t page_size = (grub_size_t) mode_info.pitch * mode_info.height; + + framebuffer.offscreen_buffer = grub_zalloc (page_size); + if (! framebuffer.offscreen_buffer) +@@ -1482,12 +1491,23 @@ doublebuf_pageflipping_update_screen (void) + last_line = framebuffer.previous_dirty.last_line; + + if (first_line <= last_line) +- grub_memcpy ((char *) framebuffer.pages[framebuffer.render_page] +- + first_line * framebuffer.back_target->mode_info.pitch, +- (char *) framebuffer.back_target->data +- + first_line * framebuffer.back_target->mode_info.pitch, +- framebuffer.back_target->mode_info.pitch +- * (last_line - first_line)); ++ { ++ grub_size_t copy_size; ++ ++ if (grub_sub (last_line, first_line, ©_size) || ++ grub_mul (framebuffer.back_target->mode_info.pitch, copy_size, ©_size)) ++ { ++ /* Shouldn't happen, but if it does we've a bug. */ ++ return GRUB_ERR_BUG; ++ } ++ ++ grub_memcpy ((char *) framebuffer.pages[framebuffer.render_page] + first_line * ++ framebuffer.back_target->mode_info.pitch, ++ (char *) framebuffer.back_target->data + first_line * ++ framebuffer.back_target->mode_info.pitch, ++ copy_size); ++ } ++ + framebuffer.previous_dirty = framebuffer.current_dirty; + framebuffer.current_dirty.first_line + = framebuffer.back_target->mode_info.height; diff --git a/SOURCES/0418-util-mkimage-Refactor-section-setup-to-use-a-helper.patch b/SOURCES/0418-util-mkimage-Refactor-section-setup-to-use-a-helper.patch deleted file mode 100644 index b65f8c8..0000000 --- a/SOURCES/0418-util-mkimage-Refactor-section-setup-to-use-a-helper.patch +++ /dev/null @@ -1,216 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Mon, 15 Feb 2021 14:58:06 +0100 -Subject: [PATCH] util/mkimage: Refactor section setup to use a helper - -Add a init_pe_section() helper function to setup PE sections. This makes -the code simpler and easier to read. - -Signed-off-by: Peter Jones -Signed-off-by: Javier Martinez Canillas -Reviewed-by: Daniel Kiper ---- - util/mkimage.c | 141 +++++++++++++++++++++++++++++++-------------------------- - 1 file changed, 76 insertions(+), 65 deletions(-) - -diff --git a/util/mkimage.c b/util/mkimage.c -index ed2d59d995f..e8e579304aa 100644 ---- a/util/mkimage.c -+++ b/util/mkimage.c -@@ -771,6 +771,38 @@ grub_install_get_image_targets_string (void) - return formats; - } - -+/* -+ * The image_target parameter is used by the grub_host_to_target32() macro. -+ */ -+static struct grub_pe32_section_table * -+init_pe_section(const struct grub_install_image_target_desc *image_target, -+ struct grub_pe32_section_table *section, -+ const char * const name, -+ grub_uint32_t *vma, grub_uint32_t vsz, grub_uint32_t valign, -+ grub_uint32_t *rda, grub_uint32_t rsz, -+ grub_uint32_t characteristics) -+{ -+ size_t len = strlen (name); -+ -+ if (len > sizeof (section->name)) -+ grub_util_error (_("section name %s length is bigger than %lu"), -+ name, (unsigned long) sizeof (section->name)); -+ -+ memcpy (section->name, name, len); -+ -+ section->virtual_address = grub_host_to_target32 (*vma); -+ section->virtual_size = grub_host_to_target32 (vsz); -+ (*vma) = ALIGN_UP (*vma + vsz, valign); -+ -+ section->raw_data_offset = grub_host_to_target32 (*rda); -+ section->raw_data_size = grub_host_to_target32 (rsz); -+ (*rda) = ALIGN_UP (*rda + rsz, GRUB_PE32_FILE_ALIGNMENT); -+ -+ section->characteristics = grub_host_to_target32 (characteristics); -+ -+ return section + 1; -+} -+ - /* - * tmp_ is just here so the compiler knows we'll never derefernce a NULL. - * It should get fully optimized away. -@@ -1210,17 +1242,13 @@ grub_install_generate_image (const char *dir, const char *prefix, - break; - case IMAGE_EFI: - { -- void *pe_img; -- grub_uint8_t *header; -- void *sections; -+ char *pe_img, *header; -+ struct grub_pe32_section_table *section; - size_t scn_size; -- size_t pe_size; -+ grub_uint32_t vma, raw_data; -+ size_t pe_size, header_size; - struct grub_pe32_coff_header *c; -- struct grub_pe32_section_table *text_section, *data_section; -- struct grub_pe32_section_table *mods_section, *reloc_section; - static const grub_uint8_t stub[] = GRUB_PE32_MSDOS_STUB; -- int header_size; -- int reloc_addr; - struct grub_pe32_optional_header *o32 = NULL; - struct grub_pe64_optional_header *o64 = NULL; - -@@ -1229,17 +1257,12 @@ grub_install_generate_image (const char *dir, const char *prefix, - else - header_size = EFI64_HEADER_SIZE; - -- reloc_addr = ALIGN_UP (header_size + core_size, -- image_target->section_align); -+ vma = raw_data = header_size; -+ pe_size = ALIGN_UP (header_size + core_size, GRUB_PE32_FILE_ALIGNMENT) + -+ ALIGN_UP (layout.reloc_size, GRUB_PE32_FILE_ALIGNMENT); -+ header = pe_img = xcalloc (1, pe_size); - -- pe_size = ALIGN_UP (reloc_addr + layout.reloc_size, -- image_target->section_align); -- pe_img = xmalloc (reloc_addr + layout.reloc_size); -- memset (pe_img, 0, header_size); -- memcpy ((char *) pe_img + header_size, core_img, core_size); -- memset ((char *) pe_img + header_size + core_size, 0, reloc_addr - (header_size + core_size)); -- memcpy ((char *) pe_img + reloc_addr, layout.reloc_section, layout.reloc_size); -- header = pe_img; -+ memcpy (pe_img + raw_data, core_img, core_size); - - /* The magic. */ - memcpy (header, stub, GRUB_PE32_MSDOS_STUB_SIZE); -@@ -1272,18 +1295,17 @@ grub_install_generate_image (const char *dir, const char *prefix, - o32->magic = grub_host_to_target16 (GRUB_PE32_PE32_MAGIC); - o32->data_base = grub_host_to_target32 (header_size + layout.exec_size); - -- sections = o32 + 1; -+ section = (struct grub_pe32_section_table *)(o32 + 1); - } - else - { - c->optional_header_size = grub_host_to_target16 (sizeof (struct grub_pe64_optional_header)); -- - o64 = (struct grub_pe64_optional_header *) - (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE + - sizeof (struct grub_pe32_coff_header)); - o64->magic = grub_host_to_target16 (GRUB_PE32_PE64_MAGIC); - -- sections = o64 + 1; -+ section = (struct grub_pe32_section_table *)(o64 + 1); - } - - PE_OHDR (o32, o64, header_size) = grub_host_to_target32 (header_size); -@@ -1303,58 +1325,47 @@ grub_install_generate_image (const char *dir, const char *prefix, - PE_OHDR (o32, o64, num_data_directories) = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); - - /* The sections. */ -- PE_OHDR (o32, o64, code_base) = grub_host_to_target32 (header_size); -+ PE_OHDR (o32, o64, code_base) = grub_host_to_target32 (vma); - PE_OHDR (o32, o64, code_size) = grub_host_to_target32 (layout.exec_size); -- text_section = sections; -- strcpy (text_section->name, ".text"); -- text_section->virtual_size = grub_host_to_target32 (layout.exec_size); -- text_section->virtual_address = grub_host_to_target32 (header_size); -- text_section->raw_data_size = grub_host_to_target32 (layout.exec_size); -- text_section->raw_data_offset = grub_host_to_target32 (header_size); -- text_section->characteristics = grub_cpu_to_le32_compile_time ( -- GRUB_PE32_SCN_CNT_CODE -- | GRUB_PE32_SCN_MEM_EXECUTE -- | GRUB_PE32_SCN_MEM_READ); -+ section = init_pe_section (image_target, section, ".text", -+ &vma, layout.exec_size, -+ image_target->section_align, -+ &raw_data, layout.exec_size, -+ GRUB_PE32_SCN_CNT_CODE | -+ GRUB_PE32_SCN_MEM_EXECUTE | -+ GRUB_PE32_SCN_MEM_READ); - - scn_size = ALIGN_UP (layout.kernel_size - layout.exec_size, GRUB_PE32_FILE_ALIGNMENT); - PE_OHDR (o32, o64, data_size) = grub_host_to_target32 (scn_size + - ALIGN_UP (total_module_size, - GRUB_PE32_FILE_ALIGNMENT)); - -- data_section = text_section + 1; -- strcpy (data_section->name, ".data"); -- data_section->virtual_size = grub_host_to_target32 (layout.kernel_size - layout.exec_size); -- data_section->virtual_address = grub_host_to_target32 (header_size + layout.exec_size); -- data_section->raw_data_size = grub_host_to_target32 (layout.kernel_size - layout.exec_size); -- data_section->raw_data_offset = grub_host_to_target32 (header_size + layout.exec_size); -- data_section->characteristics -- = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA -- | GRUB_PE32_SCN_MEM_READ -- | GRUB_PE32_SCN_MEM_WRITE); -- -- mods_section = data_section + 1; -- strcpy (mods_section->name, "mods"); -- mods_section->virtual_size = grub_host_to_target32 (reloc_addr - layout.kernel_size - header_size); -- mods_section->virtual_address = grub_host_to_target32 (header_size + layout.kernel_size + layout.bss_size); -- mods_section->raw_data_size = grub_host_to_target32 (reloc_addr - layout.kernel_size - header_size); -- mods_section->raw_data_offset = grub_host_to_target32 (header_size + layout.kernel_size); -- mods_section->characteristics -- = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA -- | GRUB_PE32_SCN_MEM_READ -- | GRUB_PE32_SCN_MEM_WRITE); -+ section = init_pe_section (image_target, section, ".data", -+ &vma, scn_size, image_target->section_align, -+ &raw_data, scn_size, -+ GRUB_PE32_SCN_CNT_INITIALIZED_DATA | -+ GRUB_PE32_SCN_MEM_READ | -+ GRUB_PE32_SCN_MEM_WRITE); -+ -+ scn_size = pe_size - layout.reloc_size - raw_data; -+ section = init_pe_section (image_target, section, "mods", -+ &vma, scn_size, image_target->section_align, -+ &raw_data, scn_size, -+ GRUB_PE32_SCN_CNT_INITIALIZED_DATA | -+ GRUB_PE32_SCN_MEM_READ | -+ GRUB_PE32_SCN_MEM_WRITE); -+ -+ scn_size = layout.reloc_size; -+ PE_OHDR (o32, o64, base_relocation_table.rva) = grub_host_to_target32 (vma); -+ PE_OHDR (o32, o64, base_relocation_table.size) = grub_host_to_target32 (scn_size); -+ memcpy (pe_img + raw_data, layout.reloc_section, scn_size); -+ init_pe_section (image_target, section, ".reloc", -+ &vma, scn_size, image_target->section_align, -+ &raw_data, scn_size, -+ GRUB_PE32_SCN_CNT_INITIALIZED_DATA | -+ GRUB_PE32_SCN_MEM_DISCARDABLE | -+ GRUB_PE32_SCN_MEM_READ); - -- PE_OHDR (o32, o64, base_relocation_table.rva) = grub_host_to_target32 (reloc_addr); -- PE_OHDR (o32, o64, base_relocation_table.size) = grub_host_to_target32 (layout.reloc_size); -- reloc_section = mods_section + 1; -- strcpy (reloc_section->name, ".reloc"); -- reloc_section->virtual_size = grub_host_to_target32 (layout.reloc_size); -- reloc_section->virtual_address = grub_host_to_target32 (reloc_addr + layout.bss_size); -- reloc_section->raw_data_size = grub_host_to_target32 (layout.reloc_size); -- reloc_section->raw_data_offset = grub_host_to_target32 (reloc_addr); -- reloc_section->characteristics -- = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA -- | GRUB_PE32_SCN_MEM_DISCARDABLE -- | GRUB_PE32_SCN_MEM_READ); - free (core_img); - core_img = pe_img; - core_size = pe_size; diff --git a/SOURCES/0418-video-fb-video_fb-Fix-possible-integer-overflow.patch b/SOURCES/0418-video-fb-video_fb-Fix-possible-integer-overflow.patch new file mode 100644 index 0000000..ce9204f --- /dev/null +++ b/SOURCES/0418-video-fb-video_fb-Fix-possible-integer-overflow.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Fri, 4 Dec 2020 14:51:30 +0000 +Subject: [PATCH] video/fb/video_fb: Fix possible integer overflow + +It is minimal possibility that the values being used here will overflow. +So, change the code to use the safemath function grub_mul() to ensure +that doesn't happen. + +Fixes: CID 73761 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/video/fb/video_fb.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/grub-core/video/fb/video_fb.c b/grub-core/video/fb/video_fb.c +index 1c9a138dcdc..ae6b89f9aea 100644 +--- a/grub-core/video/fb/video_fb.c ++++ b/grub-core/video/fb/video_fb.c +@@ -1537,7 +1537,13 @@ doublebuf_pageflipping_init (struct grub_video_mode_info *mode_info, + volatile void *page1_ptr) + { + grub_err_t err; +- grub_size_t page_size = mode_info->pitch * mode_info->height; ++ grub_size_t page_size = 0; ++ ++ if (grub_mul (mode_info->pitch, mode_info->height, &page_size)) ++ { ++ /* Shouldn't happen, but if it does we've a bug. */ ++ return GRUB_ERR_BUG; ++ } + + framebuffer.offscreen_buffer = grub_malloc (page_size); + if (! framebuffer.offscreen_buffer) diff --git a/SOURCES/0419-util-mkimage-Add-an-option-to-import-SBAT-metadata-i.patch b/SOURCES/0419-util-mkimage-Add-an-option-to-import-SBAT-metadata-i.patch deleted file mode 100644 index f359681..0000000 --- a/SOURCES/0419-util-mkimage-Add-an-option-to-import-SBAT-metadata-i.patch +++ /dev/null @@ -1,263 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Mon, 15 Feb 2021 17:07:00 +0100 -Subject: [PATCH] util/mkimage: Add an option to import SBAT metadata into a - .sbat section - -Add a --sbat option to the grub-mkimage tool which allows us to import -an SBAT metadata formatted as a CSV file into a .sbat section of the -EFI binary. - -Signed-off-by: Peter Jones -Signed-off-by: Javier Martinez Canillas -Reviewed-by: Daniel Kiper ---- - util/grub-install-common.c | 3 ++- - util/grub-mkimage.c | 15 ++++++++++++++- - util/mkimage.c | 43 ++++++++++++++++++++++++++++++++++++------- - include/grub/util/install.h | 3 ++- - include/grub/util/mkimage.h | 1 + - docs/grub.texi | 21 +++++++++++++++++++++ - 6 files changed, 76 insertions(+), 10 deletions(-) - -diff --git a/util/grub-install-common.c b/util/grub-install-common.c -index cf993c059ad..909db42e7d6 100644 ---- a/util/grub-install-common.c -+++ b/util/grub-install-common.c -@@ -506,7 +506,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, -- note, compression, dtb); -+ note, compression, dtb, NULL); -+ - while (dc--) - grub_install_pop_module (); - } -diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c -index 98d24cc06ea..bce7f7a5f02 100644 ---- a/util/grub-mkimage.c -+++ b/util/grub-mkimage.c -@@ -81,6 +81,7 @@ static struct argp_option options[] = { - {"output", 'o', N_("FILE"), 0, N_("output a generated image to FILE [default=stdout]"), 0}, - {"format", 'O', N_("FORMAT"), 0, 0, 0}, - {"compression", 'C', "(xz|none|auto)", 0, N_("choose the compression to use for core image"), 0}, -+ {"sbat", 's', N_("FILE"), 0, N_("SBAT metadata"), 0}, - {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, - { 0, 0, 0, 0, 0, 0 } - }; -@@ -123,6 +124,7 @@ struct arguments - size_t npubkeys; - char *font; - char *config; -+ char *sbat; - int note; - const struct grub_install_image_target_desc *image_target; - grub_compression_t comp; -@@ -224,6 +226,13 @@ argp_parser (int key, char *arg, struct argp_state *state) - arguments->prefix = xstrdup (arg); - break; - -+ case 's': -+ if (arguments->sbat) -+ free (arguments->sbat); -+ -+ arguments->sbat = xstrdup (arg); -+ break; -+ - case 'v': - verbosity++; - break; -@@ -309,7 +318,8 @@ main (int argc, char *argv[]) - arguments.memdisk, arguments.pubkeys, - arguments.npubkeys, arguments.config, - arguments.image_target, arguments.note, -- arguments.comp, arguments.dtb); -+ arguments.comp, arguments.dtb, -+ arguments.sbat); - - grub_util_file_sync (fp); - fclose (fp); -@@ -324,5 +334,8 @@ main (int argc, char *argv[]) - if (arguments.output) - free (arguments.output); - -+ if (arguments.sbat) -+ free (arguments.sbat); -+ - return 0; - } -diff --git a/util/mkimage.c b/util/mkimage.c -index e8e579304aa..8c7d9164396 100644 ---- a/util/mkimage.c -+++ b/util/mkimage.c -@@ -824,12 +824,13 @@ 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) -+ int note, grub_compression_t comp, const char *dtb_path, -+ const char *sbat_path) - { - char *kernel_img, *core_img; - size_t total_module_size, core_size; - size_t memdisk_size = 0, config_size = 0; -- size_t prefix_size = 0, dtb_size = 0; -+ size_t prefix_size = 0, dtb_size = 0, sbat_size = 0; - char *kernel_path; - size_t offset; - struct grub_util_path_list *path_list, *p; -@@ -880,6 +881,9 @@ grub_install_generate_image (const char *dir, const char *prefix, - total_module_size += dtb_size + sizeof (struct grub_module_header); - } - -+ if (sbat_path != NULL && image_target->id != IMAGE_EFI) -+ grub_util_error (_(".sbat section can be embedded into EFI images only")); -+ - if (config_path) - { - config_size = ALIGN_ADDR (grub_util_get_image_size (config_path) + 1); -@@ -1242,8 +1246,9 @@ grub_install_generate_image (const char *dir, const char *prefix, - break; - case IMAGE_EFI: - { -- char *pe_img, *header; -+ char *pe_img, *pe_sbat, *header; - struct grub_pe32_section_table *section; -+ size_t n_sections = 4; - size_t scn_size; - grub_uint32_t vma, raw_data; - size_t pe_size, header_size; -@@ -1258,8 +1263,15 @@ grub_install_generate_image (const char *dir, const char *prefix, - header_size = EFI64_HEADER_SIZE; - - vma = raw_data = header_size; -+ -+ if (sbat_path != NULL) -+ { -+ sbat_size = ALIGN_ADDR (grub_util_get_image_size (sbat_path)); -+ sbat_size = ALIGN_UP (sbat_size, GRUB_PE32_FILE_ALIGNMENT); -+ } -+ - pe_size = ALIGN_UP (header_size + core_size, GRUB_PE32_FILE_ALIGNMENT) + -- ALIGN_UP (layout.reloc_size, GRUB_PE32_FILE_ALIGNMENT); -+ ALIGN_UP (layout.reloc_size, GRUB_PE32_FILE_ALIGNMENT) + sbat_size; - header = pe_img = xcalloc (1, pe_size); - - memcpy (pe_img + raw_data, core_img, core_size); -@@ -1274,7 +1286,10 @@ grub_install_generate_image (const char *dir, const char *prefix, - + GRUB_PE32_SIGNATURE_SIZE); - c->machine = grub_host_to_target16 (image_target->pe_target); - -- c->num_sections = grub_host_to_target16 (4); -+ if (sbat_path != NULL) -+ n_sections++; -+ -+ c->num_sections = grub_host_to_target16 (n_sections); - c->time = grub_host_to_target32 (STABLE_EMBEDDING_TIMESTAMP); - c->characteristics = grub_host_to_target16 (GRUB_PE32_EXECUTABLE_IMAGE - | GRUB_PE32_LINE_NUMS_STRIPPED -@@ -1336,7 +1351,8 @@ grub_install_generate_image (const char *dir, const char *prefix, - GRUB_PE32_SCN_MEM_READ); - - scn_size = ALIGN_UP (layout.kernel_size - layout.exec_size, GRUB_PE32_FILE_ALIGNMENT); -- PE_OHDR (o32, o64, data_size) = grub_host_to_target32 (scn_size + -+ /* ALIGN_UP (sbat_size, GRUB_PE32_FILE_ALIGNMENT) is done earlier. */ -+ PE_OHDR (o32, o64, data_size) = grub_host_to_target32 (scn_size + sbat_size + - ALIGN_UP (total_module_size, - GRUB_PE32_FILE_ALIGNMENT)); - -@@ -1347,7 +1363,7 @@ grub_install_generate_image (const char *dir, const char *prefix, - GRUB_PE32_SCN_MEM_READ | - GRUB_PE32_SCN_MEM_WRITE); - -- scn_size = pe_size - layout.reloc_size - raw_data; -+ scn_size = pe_size - layout.reloc_size - sbat_size - raw_data; - section = init_pe_section (image_target, section, "mods", - &vma, scn_size, image_target->section_align, - &raw_data, scn_size, -@@ -1355,6 +1371,19 @@ grub_install_generate_image (const char *dir, const char *prefix, - GRUB_PE32_SCN_MEM_READ | - GRUB_PE32_SCN_MEM_WRITE); - -+ if (sbat_path != NULL) -+ { -+ pe_sbat = pe_img + raw_data; -+ grub_util_load_image (sbat_path, pe_sbat); -+ -+ section = init_pe_section (image_target, section, ".sbat", -+ &vma, sbat_size, -+ image_target->section_align, -+ &raw_data, sbat_size, -+ GRUB_PE32_SCN_CNT_INITIALIZED_DATA | -+ GRUB_PE32_SCN_MEM_READ); -+ } -+ - scn_size = layout.reloc_size; - PE_OHDR (o32, o64, base_relocation_table.rva) = grub_host_to_target32 (vma); - PE_OHDR (o32, o64, base_relocation_table.size) = grub_host_to_target32 (scn_size); -diff --git a/include/grub/util/install.h b/include/grub/util/install.h -index 0dba8b67f93..a08f0b5325f 100644 ---- a/include/grub/util/install.h -+++ b/include/grub/util/install.h -@@ -180,7 +180,8 @@ grub_install_generate_image (const char *dir, const char *prefix, - char *config_path, - const struct grub_install_image_target_desc *image_target, - int note, -- grub_compression_t comp, const char *dtb_file); -+ grub_compression_t comp, const char *dtb_file, -+ const char *sbat_path); - - const struct grub_install_image_target_desc * - grub_install_get_image_target (const char *arg); -diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h -index b3a5ca132bc..151c178e6ee 100644 ---- a/include/grub/util/mkimage.h -+++ b/include/grub/util/mkimage.h -@@ -24,6 +24,7 @@ struct grub_mkimage_layout - size_t exec_size; - size_t kernel_size; - size_t bss_size; -+ size_t sbat_size; - grub_uint64_t start_address; - void *reloc_section; - size_t reloc_size; -diff --git a/docs/grub.texi b/docs/grub.texi -index 067aa294162..fc7b56b8f47 100644 ---- a/docs/grub.texi -+++ b/docs/grub.texi -@@ -5642,6 +5642,7 @@ environment variables and commands are listed in the same order. - @menu - * Authentication and authorisation:: Users and access control - * Using digital signatures:: Booting digitally signed code -+* Secure Boot Advanced Targeting:: Embedded information for generation number based revocation - * Lockdown:: Lockdown when booting on a secure setup - - @end menu -@@ -5806,6 +5807,26 @@ 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 Secure Boot Advanced Targeting -+@section Embedded information for generation number based revocation -+ -+The Secure Boot Advanced Targeting (SBAT) is a mechanism to allow the revocation -+of components in the boot path by using generation numbers embedded into the EFI -+binaries. The SBAT metadata is located in an .sbat data section that has set of -+UTF-8 strings as comma-separated values (CSV). See -+@uref{https://github.com/rhboot/shim/blob/main/SBAT.md} for more details. -+ -+To add a data section containing the SBAT information into the binary, the -+@option{--sbat} option of @command{grub-mkimage} command should be used. The content -+of a CSV file, encoded with UTF-8, is copied as is to the .sbat data section into -+the generated EFI binary. The CSV file can be stored anywhere on the file system. -+ -+@example -+grub-mkimage -O x86_64-efi -o grubx64.efi -p '(tftp)/grub' --sbat sbat.csv efinet tftp -+@end example -+ -+ - @node Lockdown - @section Lockdown when booting on a secure setup - diff --git a/SOURCES/0419-video-readers-jpeg-Test-for-an-invalid-next-marker-r.patch b/SOURCES/0419-video-readers-jpeg-Test-for-an-invalid-next-marker-r.patch new file mode 100644 index 0000000..f9a514a --- /dev/null +++ b/SOURCES/0419-video-readers-jpeg-Test-for-an-invalid-next-marker-r.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Fri, 4 Dec 2020 15:39:00 +0000 +Subject: [PATCH] video/readers/jpeg: Test for an invalid next marker reference + from a jpeg file + +While it may never happen, and potentially could be caught at the end of +the function, it is worth checking up front for a bad reference to the +next marker just in case of a maliciously crafted file being provided. + +Fixes: CID 73694 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/video/readers/jpeg.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index 31359a4c9c8..0b6ce3cee64 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -253,6 +253,12 @@ grub_jpeg_decode_quan_table (struct grub_jpeg_data *data) + next_marker = data->file->offset; + next_marker += grub_jpeg_get_word (data); + ++ if (next_marker > data->file->size) ++ { ++ /* Should never be set beyond the size of the file. */ ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid next reference"); ++ } ++ + while (data->file->offset + sizeof (data->quan_table[id]) + 1 + <= next_marker) + { diff --git a/SOURCES/0420-gfxmenu-gui_list-Remove-code-that-coverity-is-flaggi.patch b/SOURCES/0420-gfxmenu-gui_list-Remove-code-that-coverity-is-flaggi.patch new file mode 100644 index 0000000..c9caf70 --- /dev/null +++ b/SOURCES/0420-gfxmenu-gui_list-Remove-code-that-coverity-is-flaggi.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Mon, 7 Dec 2020 14:44:47 +0000 +Subject: [PATCH] gfxmenu/gui_list: Remove code that coverity is flagging as + dead + +The test of value for NULL before calling grub_strdup() is not required, +since the if condition prior to this has already tested for value being +NULL and cannot reach this code if it is. + +Fixes: CID 73659 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/gfxmenu/gui_list.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/gfxmenu/gui_list.c b/grub-core/gfxmenu/gui_list.c +index 01477cdf2b3..df334a6c56f 100644 +--- a/grub-core/gfxmenu/gui_list.c ++++ b/grub-core/gfxmenu/gui_list.c +@@ -771,7 +771,7 @@ list_set_property (void *vself, const char *name, const char *value) + { + self->need_to_recreate_boxes = 1; + grub_free (self->selected_item_box_pattern); +- self->selected_item_box_pattern = value ? grub_strdup (value) : 0; ++ self->selected_item_box_pattern = grub_strdup (value); + self->selected_item_box_pattern_inherit = 0; + } + } diff --git a/SOURCES/0420-kern-misc-Split-parse_printf_args-into-format-parsin.patch b/SOURCES/0420-kern-misc-Split-parse_printf_args-into-format-parsin.patch deleted file mode 100644 index 879ce59..0000000 --- a/SOURCES/0420-kern-misc-Split-parse_printf_args-into-format-parsin.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Thomas Frauendorfer | Miray Software -Date: Mon, 15 Feb 2021 13:40:16 +0100 -Subject: [PATCH] kern/misc: Split parse_printf_args() into format parsing and - va_list handling - -This patch is preparing for a follow up patch which will use -the format parsing part to compare the arguments in a printf() -format from an external source against a printf() format with -expected arguments. - -Signed-off-by: Thomas Frauendorfer | Miray Software -Reviewed-by: Daniel Kiper ---- - grub-core/kern/misc.c | 11 +++++++++-- - 1 file changed, 9 insertions(+), 2 deletions(-) - -diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c -index 62b4068e810..ca851c29d51 100644 ---- a/grub-core/kern/misc.c -+++ b/grub-core/kern/misc.c -@@ -678,8 +678,7 @@ grub_lltoa (char *str, int c, unsigned long long n) - } - - static void --parse_printf_args (const char *fmt0, struct printf_args *args, -- va_list args_in) -+parse_printf_arg_fmt (const char *fmt0, struct printf_args *args) - { - const char *fmt; - char c; -@@ -837,6 +836,14 @@ parse_printf_args (const char *fmt0, struct printf_args *args, - break; - } - } -+} -+ -+static void -+parse_printf_args (const char *fmt0, struct printf_args *args, va_list args_in) -+{ -+ grub_size_t n; -+ -+ parse_printf_arg_fmt (fmt0, args); - - for (n = 0; n < args->count; n++) - switch (args->ptr[n].type) diff --git a/SOURCES/0421-kern-misc-Add-STRING-type-for-internal-printf-format.patch b/SOURCES/0421-kern-misc-Add-STRING-type-for-internal-printf-format.patch deleted file mode 100644 index f301df2..0000000 --- a/SOURCES/0421-kern-misc-Add-STRING-type-for-internal-printf-format.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Thomas Frauendorfer | Miray Software -Date: Mon, 15 Feb 2021 14:04:26 +0100 -Subject: [PATCH] kern/misc: Add STRING type for internal printf() format - handling - -Set printf() argument type for "%s" to new type STRING. This is in -preparation for a follow up patch to compare a printf() format string -against an expected printf() format string. - -For "%s" the corresponding printf() argument is dereferenced as pointer -while all other argument types are defined as integer value. However, -when validating a printf() format it is necessary to differentiate "%s" -from "%p" and other integers. So, let's do that. - -Signed-off-by: Thomas Frauendorfer | Miray Software -Reviewed-by: Daniel Kiper ---- - grub-core/kern/misc.c | 13 +++++++++++-- - 1 file changed, 11 insertions(+), 2 deletions(-) - -diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c -index ca851c29d51..9e2a237b118 100644 ---- a/grub-core/kern/misc.c -+++ b/grub-core/kern/misc.c -@@ -34,7 +34,8 @@ union printf_arg - enum - { - INT, LONG, LONGLONG, -- UNSIGNED_INT = 3, UNSIGNED_LONG, UNSIGNED_LONGLONG -+ UNSIGNED_INT = 3, UNSIGNED_LONG, UNSIGNED_LONGLONG, -+ STRING - } type; - long long ll; - }; -@@ -824,12 +825,14 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args) - args->ptr[curn].type = INT + longfmt; - break; - case 'p': -- case 's': - if (sizeof (void *) == sizeof (long long)) - args->ptr[curn].type = UNSIGNED_LONGLONG; - else - args->ptr[curn].type = UNSIGNED_INT; - break; -+ case 's': -+ args->ptr[curn].type = STRING; -+ break; - case 'C': - case 'c': - args->ptr[curn].type = INT; -@@ -864,6 +867,12 @@ parse_printf_args (const char *fmt0, struct printf_args *args, va_list args_in) - case UNSIGNED_LONGLONG: - args->ptr[n].ll = va_arg (args_in, long long); - break; -+ case STRING: -+ if (sizeof (void *) == sizeof (long long)) -+ args->ptr[n].ll = va_arg (args_in, long long); -+ else -+ args->ptr[n].ll = va_arg (args_in, unsigned int); -+ break; - } - } - diff --git a/SOURCES/0421-loader-bsd-Check-for-NULL-arg-up-front.patch b/SOURCES/0421-loader-bsd-Check-for-NULL-arg-up-front.patch new file mode 100644 index 0000000..f4c63b3 --- /dev/null +++ b/SOURCES/0421-loader-bsd-Check-for-NULL-arg-up-front.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Tue, 8 Dec 2020 21:47:13 +0000 +Subject: [PATCH] loader/bsd: Check for NULL arg up-front + +The code in the next block suggests that it is possible for .set to be +true but .arg may still be NULL. + +This code assumes that it is never NULL, yet later is testing if it is +NULL - that is inconsistent. + +So we should check first if .arg is not NULL, and remove this check that +is being flagged by Coverity since it is no longer required. + +Fixes: CID 292471 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/loader/i386/bsd.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c +index 45a71509956..b5ab848ee44 100644 +--- a/grub-core/loader/i386/bsd.c ++++ b/grub-core/loader/i386/bsd.c +@@ -1606,7 +1606,7 @@ grub_cmd_openbsd (grub_extcmd_context_t ctxt, int argc, char *argv[]) + kernel_type = KERNEL_TYPE_OPENBSD; + bootflags = grub_bsd_parse_flags (ctxt->state, openbsd_flags); + +- if (ctxt->state[OPENBSD_ROOT_ARG].set) ++ if (ctxt->state[OPENBSD_ROOT_ARG].set && ctxt->state[OPENBSD_ROOT_ARG].arg != NULL) + { + const char *arg = ctxt->state[OPENBSD_ROOT_ARG].arg; + unsigned type, unit, part; +@@ -1623,7 +1623,7 @@ grub_cmd_openbsd (grub_extcmd_context_t ctxt, int argc, char *argv[]) + "unknown disk type name"); + + unit = grub_strtoul (arg, (char **) &arg, 10); +- if (! (arg && *arg >= 'a' && *arg <= 'z')) ++ if (! (*arg >= 'a' && *arg <= 'z')) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "only device specifications of form " + " are supported"); diff --git a/SOURCES/0422-kern-misc-Add-function-to-check-printf-format-agains.patch b/SOURCES/0422-kern-misc-Add-function-to-check-printf-format-agains.patch deleted file mode 100644 index 377c9f4..0000000 --- a/SOURCES/0422-kern-misc-Add-function-to-check-printf-format-agains.patch +++ /dev/null @@ -1,215 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Thomas Frauendorfer | Miray Software -Date: Thu, 4 Feb 2021 19:02:33 +0100 -Subject: [PATCH] kern/misc: Add function to check printf() format against - expected format - -The grub_printf_fmt_check() function parses the arguments of an untrusted -printf() format and an expected printf() format and then compares the -arguments counts and arguments types. The arguments count in the untrusted -format string must be less or equal to the arguments count in the expected -format string and both arguments types must match. - -To do this the parse_printf_arg_fmt() helper function is extended in the -following way: - - 1. Add a return value to report errors to the grub_printf_fmt_check(). - - 2. Add the fmt_check argument to enable stricter format verification: - - the function expects that arguments definitions are always - terminated by a supported conversion specifier. - - positional parameters, "$", are not allowed, as they cannot be - validated correctly with the current implementation. For example - "%s%1$d" would assign the first args entry twice while leaving the - second one unchanged. - - Return an error if preallocated space in args is too small and - allocation fails for the needed size. The grub_printf_fmt_check() - should verify all arguments. So, if validation is not possible for - any reason it should return an error. - This also adds a case entry to handle "%%", which is the escape - sequence to print "%" character. - - 3. Add the max_args argument to check for the maximum allowed arguments - count in a printf() string. This should be set to the arguments count - of the expected format. Then the parse_printf_arg_fmt() function will - return an error if the arguments count is exceeded. - -The two additional arguments allow us to use parse_printf_arg_fmt() in -printf() and grub_printf_fmt_check() calls. - -When parse_printf_arg_fmt() is used by grub_printf_fmt_check() the -function parse user provided untrusted format string too. So, in -that case it is better to be too strict than too lenient. - -Signed-off-by: Thomas Frauendorfer | Miray Software -Reviewed-by: Daniel Kiper ---- - grub-core/kern/misc.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++--- - include/grub/misc.h | 16 ++++++++++ - 2 files changed, 94 insertions(+), 4 deletions(-) - -diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c -index 9e2a237b118..f56b5d2034e 100644 ---- a/grub-core/kern/misc.c -+++ b/grub-core/kern/misc.c -@@ -678,8 +678,26 @@ grub_lltoa (char *str, int c, unsigned long long n) - return p; - } - --static void --parse_printf_arg_fmt (const char *fmt0, struct printf_args *args) -+/* -+ * Parse printf() fmt0 string into args arguments. -+ * -+ * The parsed arguments are either used by a printf() function to format the fmt0 -+ * string or they are used to compare a format string from an untrusted source -+ * against a format string with expected arguments. -+ * -+ * When the fmt_check is set to !0, e.g. 1, then this function is executed in -+ * printf() format check mode. This enforces stricter rules for parsing the -+ * fmt0 to limit exposure to possible errors in printf() handling. It also -+ * disables positional parameters, "$", because some formats, e.g "%s%1$d", -+ * cannot be validated with the current implementation. -+ * -+ * The max_args allows to set a maximum number of accepted arguments. If the fmt0 -+ * string defines more arguments than the max_args then the parse_printf_arg_fmt() -+ * function returns an error. This is currently used for format check only. -+ */ -+static grub_err_t -+parse_printf_arg_fmt (const char *fmt0, struct printf_args *args, -+ int fmt_check, grub_size_t max_args) - { - const char *fmt; - char c; -@@ -706,7 +724,12 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args) - fmt++; - - if (*fmt == '$') -- fmt++; -+ { -+ if (fmt_check) -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, -+ "positional arguments are not supported"); -+ fmt++; -+ } - - if (*fmt =='-') - fmt++; -@@ -738,9 +761,19 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args) - case 's': - args->count++; - break; -+ case '%': -+ /* "%%" is the escape sequence to output "%". */ -+ break; -+ default: -+ if (fmt_check) -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "unexpected format"); -+ break; - } - } - -+ if (fmt_check && args->count > max_args) -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "too many arguments"); -+ - if (args->count <= ARRAY_SIZE (args->prealloc)) - args->ptr = args->prealloc; - else -@@ -748,6 +781,9 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args) - args->ptr = grub_calloc (args->count, sizeof (args->ptr[0])); - if (!args->ptr) - { -+ if (fmt_check) -+ return grub_errno; -+ - grub_errno = GRUB_ERR_NONE; - args->ptr = args->prealloc; - args->count = ARRAY_SIZE (args->prealloc); -@@ -839,6 +875,8 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args) - break; - } - } -+ -+ return GRUB_ERR_NONE; - } - - static void -@@ -846,7 +884,7 @@ parse_printf_args (const char *fmt0, struct printf_args *args, va_list args_in) - { - grub_size_t n; - -- parse_printf_arg_fmt (fmt0, args); -+ parse_printf_arg_fmt (fmt0, args, 0, 0); - - for (n = 0; n < args->count; n++) - switch (args->ptr[n].type) -@@ -1154,6 +1192,42 @@ grub_xasprintf (const char *fmt, ...) - return ret; - } - -+grub_err_t -+grub_printf_fmt_check (const char *fmt, const char *fmt_expected) -+{ -+ struct printf_args args_expected, args_fmt; -+ grub_err_t ret; -+ grub_size_t n; -+ -+ if (fmt == NULL || fmt_expected == NULL) -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid format"); -+ -+ ret = parse_printf_arg_fmt (fmt_expected, &args_expected, 1, GRUB_SIZE_MAX); -+ if (ret != GRUB_ERR_NONE) -+ return ret; -+ -+ /* Limit parsing to the number of expected arguments. */ -+ ret = parse_printf_arg_fmt (fmt, &args_fmt, 1, args_expected.count); -+ if (ret != GRUB_ERR_NONE) -+ { -+ free_printf_args (&args_expected); -+ return ret; -+ } -+ -+ for (n = 0; n < args_fmt.count; n++) -+ if (args_fmt.ptr[n].type != args_expected.ptr[n].type) -+ { -+ ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "arguments types do not match"); -+ break; -+ } -+ -+ free_printf_args (&args_expected); -+ free_printf_args (&args_fmt); -+ -+ return ret; -+} -+ -+ - /* Abort GRUB. This function does not return. */ - static inline void __attribute__ ((noreturn)) - grub_abort (void) -diff --git a/include/grub/misc.h b/include/grub/misc.h -index 1258ec6bbf3..b1cbb4a51bc 100644 ---- a/include/grub/misc.h -+++ b/include/grub/misc.h -@@ -487,6 +487,22 @@ grub_error_load (const struct grub_error_saved *save) - grub_errno = save->grub_errno; - } - -+/* -+ * grub_printf_fmt_checks() a fmt string for printf() against an expected -+ * format. It is intended for cases where the fmt string could come from -+ * an outside source and cannot be trusted. -+ * -+ * While expected fmt accepts a printf() format string it should be kept -+ * as simple as possible. The printf() format strings with positional -+ * parameters are NOT accepted, neither for fmt nor for fmt_expected. -+ * -+ * The fmt is accepted if it has equal or less arguments than fmt_expected -+ * and if the type of all arguments match. -+ * -+ * Returns GRUB_ERR_NONE if fmt is acceptable. -+ */ -+grub_err_t EXPORT_FUNC (grub_printf_fmt_check) (const char *fmt, const char *fmt_expected); -+ - #if BOOT_TIME_STATS - struct grub_boot_time - { diff --git a/SOURCES/0422-loader-xnu-Fix-memory-leak.patch b/SOURCES/0422-loader-xnu-Fix-memory-leak.patch new file mode 100644 index 0000000..76d9711 --- /dev/null +++ b/SOURCES/0422-loader-xnu-Fix-memory-leak.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Thu, 26 Nov 2020 12:53:10 +0000 +Subject: [PATCH] loader/xnu: Fix memory leak + +The code here is finished with the memory stored in name, but it only +frees it if there curvalue is valid, while it could actually free it +regardless. + +The fix is a simple relocation of the grub_free() to before the test +of curvalue. + +Fixes: CID 96646 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/loader/xnu.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c +index b33a384321c..16bfa7cec72 100644 +--- a/grub-core/loader/xnu.c ++++ b/grub-core/loader/xnu.c +@@ -1392,9 +1392,9 @@ grub_xnu_fill_devicetree (void) + name[len] = 0; + + curvalue = grub_xnu_create_value (curkey, name); +- if (!curvalue) +- return grub_errno; + grub_free (name); ++ if (!curvalue) ++ return grub_errno; + + data = grub_malloc (grub_strlen (var->value) + 1); + if (!data) diff --git a/SOURCES/0423-gfxmenu-gui-Check-printf-format-in-the-gui_progress_.patch b/SOURCES/0423-gfxmenu-gui-Check-printf-format-in-the-gui_progress_.patch deleted file mode 100644 index f1c4e5a..0000000 --- a/SOURCES/0423-gfxmenu-gui-Check-printf-format-in-the-gui_progress_.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Thomas Frauendorfer | Miray Software -Date: Tue, 4 Aug 2020 13:49:51 +0200 -Subject: [PATCH] gfxmenu/gui: Check printf() format in the gui_progress_bar - and gui_label - -The gui_progress_bar and gui_label components can display the timeout -value. The format string can be set through a theme file. This patch -adds a validation step to the format string. - -If a user loads a theme file into the GRUB without this patch then -a GUI label with the following settings - - + label { - ... - id = "__timeout__" - text = "%s" - } - -will interpret the current timeout value as string pointer and print the -memory at that position on the screen. It is not desired behavior. - -Signed-off-by: Thomas Frauendorfer | Miray Software -Reviewed-by: Daniel Kiper ---- - grub-core/gfxmenu/gui_label.c | 4 ++++ - grub-core/gfxmenu/gui_progress_bar.c | 3 +++ - 2 files changed, 7 insertions(+) - -diff --git a/grub-core/gfxmenu/gui_label.c b/grub-core/gfxmenu/gui_label.c -index a4c817891ee..1c190542a2b 100644 ---- a/grub-core/gfxmenu/gui_label.c -+++ b/grub-core/gfxmenu/gui_label.c -@@ -193,6 +193,10 @@ label_set_property (void *vself, const char *name, const char *value) - else if (grub_strcmp (value, "@KEYMAP_SHORT@") == 0) - value = _("enter: boot, `e': options, `c': cmd-line"); - /* FIXME: Add more templates here if needed. */ -+ -+ if (grub_printf_fmt_check(value, "%d") != GRUB_ERR_NONE) -+ value = ""; /* Unsupported format. */ -+ - self->template = grub_strdup (value); - self->text = grub_xasprintf (value, self->value); - } -diff --git a/grub-core/gfxmenu/gui_progress_bar.c b/grub-core/gfxmenu/gui_progress_bar.c -index b128f08668e..ace85a12569 100644 ---- a/grub-core/gfxmenu/gui_progress_bar.c -+++ b/grub-core/gfxmenu/gui_progress_bar.c -@@ -348,6 +348,9 @@ progress_bar_set_property (void *vself, const char *name, const char *value) - Please use the shortest form available in you language. */ - value = _("%ds"); - -+ if (grub_printf_fmt_check(value, "%d") != GRUB_ERR_NONE) -+ value = ""; /* Unsupported format. */ -+ - self->template = grub_strdup (value); - } - else if (grub_strcmp (name, "font") == 0) diff --git a/SOURCES/0423-loader-xnu-Free-driverkey-data-when-an-error-is-dete.patch b/SOURCES/0423-loader-xnu-Free-driverkey-data-when-an-error-is-dete.patch new file mode 100644 index 0000000..d4c945c --- /dev/null +++ b/SOURCES/0423-loader-xnu-Free-driverkey-data-when-an-error-is-dete.patch @@ -0,0 +1,74 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Marco A Benatto +Date: Mon, 30 Nov 2020 12:18:24 -0300 +Subject: [PATCH] loader/xnu: Free driverkey data when an error is detected in + grub_xnu_writetree_toheap() + +... to avoid memory leaks. + +Fixes: CID 96640 + +Signed-off-by: Marco A Benatto +Reviewed-by: Daniel Kiper +--- + grub-core/loader/xnu.c | 24 ++++++++++++++++++++---- + 1 file changed, 20 insertions(+), 4 deletions(-) + +diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c +index 16bfa7cec72..af885a648c6 100644 +--- a/grub-core/loader/xnu.c ++++ b/grub-core/loader/xnu.c +@@ -228,26 +228,33 @@ grub_xnu_writetree_toheap (grub_addr_t *target, grub_size_t *size) + if (! memorymap) + return grub_errno; + +- driverkey = (struct grub_xnu_devtree_key *) grub_malloc (sizeof (*driverkey)); ++ driverkey = (struct grub_xnu_devtree_key *) grub_zalloc (sizeof (*driverkey)); + if (! driverkey) + return grub_errno; + driverkey->name = grub_strdup ("DeviceTree"); + if (! driverkey->name) +- return grub_errno; ++ { ++ err = grub_errno; ++ goto fail; ++ } ++ + driverkey->datasize = sizeof (*extdesc); + driverkey->next = memorymap->first_child; + memorymap->first_child = driverkey; + driverkey->data = extdesc + = (struct grub_xnu_extdesc *) grub_malloc (sizeof (*extdesc)); + if (! driverkey->data) +- return grub_errno; ++ { ++ err = grub_errno; ++ goto fail; ++ } + + /* Allocate the space based on the size with dummy value. */ + *size = grub_xnu_writetree_get_size (grub_xnu_devtree_root, "/"); + err = grub_xnu_heap_malloc (ALIGN_UP (*size + 1, GRUB_XNU_PAGESIZE), + &src, target); + if (err) +- return err; ++ goto fail; + + /* Put real data in the dummy. */ + extdesc->addr = *target; +@@ -256,6 +263,15 @@ grub_xnu_writetree_toheap (grub_addr_t *target, grub_size_t *size) + /* Write the tree to heap. */ + grub_xnu_writetree_toheap_real (src, grub_xnu_devtree_root, "/"); + return GRUB_ERR_NONE; ++ ++ fail: ++ memorymap->first_child = NULL; ++ ++ grub_free (driverkey->data); ++ grub_free (driverkey->name); ++ grub_free (driverkey); ++ ++ return err; + } + + /* Find a key or value in parent key. */ diff --git a/SOURCES/0424-kern-mm-Fix-grub_debug_calloc-compilation-error.patch b/SOURCES/0424-kern-mm-Fix-grub_debug_calloc-compilation-error.patch deleted file mode 100644 index 619d6d5..0000000 --- a/SOURCES/0424-kern-mm-Fix-grub_debug_calloc-compilation-error.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Marco A Benatto -Date: Tue, 9 Feb 2021 12:33:06 -0300 -Subject: [PATCH] kern/mm: Fix grub_debug_calloc() compilation error - -Fix compilation error due to missing parameter to -grub_printf() when MM_DEBUG is defined. - -Fixes: 64e26162e (calloc: Make sure we always have an overflow-checking calloc() available) - -Signed-off-by: Marco A Benatto -Reviewed-by: Daniel Kiper ---- - grub-core/kern/mm.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c -index 80d0720d005..d8c8377578b 100644 ---- a/grub-core/kern/mm.c -+++ b/grub-core/kern/mm.c -@@ -594,7 +594,7 @@ grub_debug_calloc (const char *file, int line, grub_size_t nmemb, grub_size_t si - - if (grub_mm_debug) - grub_printf ("%s:%d: calloc (0x%" PRIxGRUB_SIZE ", 0x%" PRIxGRUB_SIZE ") = ", -- file, line, size); -+ file, line, nmemb, size); - ptr = grub_calloc (nmemb, size); - if (grub_mm_debug) - grub_printf ("%p\n", ptr); diff --git a/SOURCES/0424-loader-xnu-Check-if-pointer-is-NULL-before-using-it.patch b/SOURCES/0424-loader-xnu-Check-if-pointer-is-NULL-before-using-it.patch new file mode 100644 index 0000000..ba24db2 --- /dev/null +++ b/SOURCES/0424-loader-xnu-Check-if-pointer-is-NULL-before-using-it.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paulo Flabiano Smorigo +Date: Mon, 30 Nov 2020 10:36:00 -0300 +Subject: [PATCH] loader/xnu: Check if pointer is NULL before using it + +Fixes: CID 73654 + +Signed-off-by: Paulo Flabiano Smorigo +Reviewed-by: Daniel Kiper +--- + grub-core/loader/xnu.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c +index af885a648c6..49641b8bbc2 100644 +--- a/grub-core/loader/xnu.c ++++ b/grub-core/loader/xnu.c +@@ -671,6 +671,9 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile, + char *name, *nameend; + int namelen; + ++ if (infoplistname == NULL) ++ return grub_error (GRUB_ERR_BAD_FILENAME, N_("missing p-list filename")); ++ + name = get_name_ptr (infoplistname); + nameend = grub_strchr (name, '/'); + +@@ -702,10 +705,7 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile, + else + macho = 0; + +- if (infoplistname) +- infoplist = grub_file_open (infoplistname, GRUB_FILE_TYPE_XNU_INFO_PLIST); +- else +- infoplist = 0; ++ infoplist = grub_file_open (infoplistname, GRUB_FILE_TYPE_XNU_INFO_PLIST); + grub_errno = GRUB_ERR_NONE; + if (infoplist) + { diff --git a/SOURCES/0425-efi-net-Fix-malformed-device-path-arithmetic-errors-.patch b/SOURCES/0425-efi-net-Fix-malformed-device-path-arithmetic-errors-.patch deleted file mode 100644 index 054a810..0000000 --- a/SOURCES/0425-efi-net-Fix-malformed-device-path-arithmetic-errors-.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Thomas Frauendorfer | Miray Software -Date: Tue, 4 Aug 2020 17:13:05 +0200 -Subject: [PATCH] efi/net: Fix malformed device path arithmetic errors in efi - net methods - ---- - grub-core/net/efi/net.c | 26 ++++++++++++++++++++------ - 1 file changed, 20 insertions(+), 6 deletions(-) - -diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c -index 3ae1fbbe3c8..a58c24f6364 100644 ---- a/grub-core/net/efi/net.c -+++ b/grub-core/net/efi/net.c -@@ -1318,11 +1318,18 @@ grub_efi_net_boot_from_https (void) - - dp = grub_efi_get_device_path (image->device_handle); - -- while (1) -+ while (dp) - { -+ grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp); -+ if (len < 4) -+ { -+ grub_error(GRUB_ERR_OUT_OF_RANGE, -+ "malformed EFI Device Path node has length=%d", len); -+ break; -+ } -+ - 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)) -@@ -1335,7 +1342,7 @@ grub_efi_net_boot_from_https (void) - - if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) - break; -- dp = (grub_efi_device_path_t *) ((char *) dp + len); -+ dp = GRUB_EFI_NEXT_DEVICE_PATH(dp); - } - - return 0; -@@ -1353,11 +1360,18 @@ grub_efi_net_boot_from_opa (void) - - dp = grub_efi_get_device_path (image->device_handle); - -- while (1) -+ while (dp) - { -+ grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp); -+ if (len < 4) -+ { -+ grub_error(GRUB_ERR_OUT_OF_RANGE, -+ "malformed EFI Device Path node has length=%d", len); -+ break; -+ } -+ - 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)) -@@ -1368,7 +1382,7 @@ grub_efi_net_boot_from_opa (void) - - if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) - break; -- dp = (grub_efi_device_path_t *) ((char *) dp + len); -+ dp = GRUB_EFI_NEXT_DEVICE_PATH(dp); - } - - return 0; diff --git a/SOURCES/0425-util-grub-editenv-Fix-incorrect-casting-of-a-signed-.patch b/SOURCES/0425-util-grub-editenv-Fix-incorrect-casting-of-a-signed-.patch new file mode 100644 index 0000000..c90ca09 --- /dev/null +++ b/SOURCES/0425-util-grub-editenv-Fix-incorrect-casting-of-a-signed-.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Thu, 5 Nov 2020 14:33:50 +0000 +Subject: [PATCH] util/grub-editenv: Fix incorrect casting of a signed value + +The return value of ftell() may be negative (-1) on error. While it is +probably unlikely to occur, we should not blindly cast to an unsigned +value without first testing that it is not negative. + +Fixes: CID 73856 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + util/grub-editenv.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/util/grub-editenv.c b/util/grub-editenv.c +index 2918bb71cfe..e9011e0fbde 100644 +--- a/util/grub-editenv.c ++++ b/util/grub-editenv.c +@@ -128,6 +128,7 @@ open_envblk_file (const char *name) + { + FILE *fp; + char *buf; ++ long loc; + size_t size; + grub_envblk_t envblk; + +@@ -146,7 +147,12 @@ open_envblk_file (const char *name) + grub_util_error (_("cannot seek `%s': %s"), name, + strerror (errno)); + +- size = (size_t) ftell (fp); ++ loc = ftell (fp); ++ if (loc < 0) ++ grub_util_error (_("cannot get file location `%s': %s"), name, ++ strerror (errno)); ++ ++ size = (size_t) loc; + + if (fseek (fp, 0, SEEK_SET) < 0) + grub_util_error (_("cannot seek `%s': %s"), name, diff --git a/SOURCES/0426-util-glue-efi-Fix-incorrect-use-of-a-possibly-negati.patch b/SOURCES/0426-util-glue-efi-Fix-incorrect-use-of-a-possibly-negati.patch new file mode 100644 index 0000000..ad3a0d6 --- /dev/null +++ b/SOURCES/0426-util-glue-efi-Fix-incorrect-use-of-a-possibly-negati.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Fri, 4 Dec 2020 15:04:28 +0000 +Subject: [PATCH] util/glue-efi: Fix incorrect use of a possibly negative value + +It is possible for the ftell() function to return a negative value, +although it is fairly unlikely here, we should be checking for +a negative value before we assign it to an unsigned value. + +Fixes: CID 73744 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + util/glue-efi.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/util/glue-efi.c b/util/glue-efi.c +index 68f53168b58..de0fa6d33d5 100644 +--- a/util/glue-efi.c ++++ b/util/glue-efi.c +@@ -39,13 +39,23 @@ write_fat (FILE *in32, FILE *in64, FILE *out, const char *out_filename, + struct grub_macho_fat_header head; + struct grub_macho_fat_arch arch32, arch64; + grub_uint32_t size32, size64; ++ long size; + char *buf; + + fseek (in32, 0, SEEK_END); +- size32 = ftell (in32); ++ size = ftell (in32); ++ if (size < 0) ++ grub_util_error ("cannot get end of input file '%s': %s", ++ name32, strerror (errno)); ++ size32 = (grub_uint32_t) size; + fseek (in32, 0, SEEK_SET); ++ + fseek (in64, 0, SEEK_END); +- size64 = ftell (in64); ++ size = ftell (in64); ++ if (size < 0) ++ grub_util_error ("cannot get end of input file '%s': %s", ++ name64, strerror (errno)); ++ size64 = (grub_uint64_t) size; + fseek (in64, 0, SEEK_SET); + + head.magic = grub_cpu_to_le32_compile_time (GRUB_MACHO_FAT_EFI_MAGIC); diff --git a/SOURCES/0427-script-execute-Fix-NULL-dereference-in-grub_script_e.patch b/SOURCES/0427-script-execute-Fix-NULL-dereference-in-grub_script_e.patch new file mode 100644 index 0000000..88c7951 --- /dev/null +++ b/SOURCES/0427-script-execute-Fix-NULL-dereference-in-grub_script_e.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 3 Apr 2020 23:05:13 +1100 +Subject: [PATCH] script/execute: Fix NULL dereference in + grub_script_execute_cmdline() + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/script/execute.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c +index a1aadb9ee05..2e47c046741 100644 +--- a/grub-core/script/execute.c ++++ b/grub-core/script/execute.c +@@ -978,7 +978,7 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd) + struct grub_script_argv argv = { 0, 0, 0 }; + + /* Lookup the command. */ +- if (grub_script_arglist_to_argv (cmdline->arglist, &argv) || ! argv.args[0]) ++ if (grub_script_arglist_to_argv (cmdline->arglist, &argv) || ! argv.args || ! argv.args[0]) + return grub_errno; + + for (i = 0; i < argv.argc; i++) { diff --git a/SOURCES/0428-commands-ls-Require-device_name-is-not-NULL-before-p.patch b/SOURCES/0428-commands-ls-Require-device_name-is-not-NULL-before-p.patch new file mode 100644 index 0000000..b916cb1 --- /dev/null +++ b/SOURCES/0428-commands-ls-Require-device_name-is-not-NULL-before-p.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 11 Jan 2021 16:57:37 +1100 +Subject: [PATCH] commands/ls: Require device_name is not NULL before printing + +This can be triggered with: + ls -l (0 0*) +and causes a NULL deref in grub_normal_print_device_info(). + +I'm not sure if there's any implication with the IEEE 1275 platform. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/commands/ls.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/commands/ls.c b/grub-core/commands/ls.c +index 2cdb2acc552..d4dcffd3168 100644 +--- a/grub-core/commands/ls.c ++++ b/grub-core/commands/ls.c +@@ -196,7 +196,7 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human) + goto fail; + } + +- if (! *path) ++ if (! *path && device_name) + { + if (grub_errno == GRUB_ERR_UNKNOWN_FS) + grub_errno = GRUB_ERR_NONE; diff --git a/SOURCES/0429-script-execute-Avoid-crash-when-using-outside-a-func.patch b/SOURCES/0429-script-execute-Avoid-crash-when-using-outside-a-func.patch new file mode 100644 index 0000000..08fa625 --- /dev/null +++ b/SOURCES/0429-script-execute-Avoid-crash-when-using-outside-a-func.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 11 Jan 2021 17:30:42 +1100 +Subject: [PATCH] script/execute: Avoid crash when using "$#" outside a + function scope + +"$#" represents the number of arguments to a function. It is only +defined in a function scope, where "scope" is non-NULL. Currently, +if we attempt to evaluate "$#" outside a function scope, "scope" will +be NULL and we will crash with a NULL pointer dereference. + +Do not attempt to count arguments for "$#" if "scope" is NULL. This +will result in "$#" being interpreted as an empty string if evaluated +outside a function scope. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/script/execute.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c +index 2e47c046741..17f4dcab2c6 100644 +--- a/grub-core/script/execute.c ++++ b/grub-core/script/execute.c +@@ -519,7 +519,7 @@ gettext_putvar (const char *str, grub_size_t len, + return 0; + + /* Enough for any number. */ +- if (len == 1 && str[0] == '#') ++ if (len == 1 && str[0] == '#' && scope != NULL) + { + grub_snprintf (*ptr, 30, "%u", scope->argv.argc); + *ptr += grub_strlen (*ptr); diff --git a/SOURCES/0430-lib-arg-Block-repeated-short-options-that-require-an.patch b/SOURCES/0430-lib-arg-Block-repeated-short-options-that-require-an.patch new file mode 100644 index 0000000..63cf2af --- /dev/null +++ b/SOURCES/0430-lib-arg-Block-repeated-short-options-that-require-an.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 22 Jan 2021 16:07:29 +1100 +Subject: [PATCH] lib/arg: Block repeated short options that require an + argument + +Fuzzing found the following crash: + + search -hhhhhhhhhhhhhf + +We didn't allocate enough option space for 13 hints because the +allocation code counts the number of discrete arguments (i.e. argc). +However, the shortopt parsing code will happily keep processing +a combination of short options without checking if those short +options require an argument. This means you can easily end writing +past the allocated option space. + +This fixes a OOB write which can cause heap corruption. + +Fixes: CVE-2021-20225 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/lib/arg.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/grub-core/lib/arg.c b/grub-core/lib/arg.c +index 3288609a5e1..537c5e94b83 100644 +--- a/grub-core/lib/arg.c ++++ b/grub-core/lib/arg.c +@@ -299,6 +299,19 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv, + it can have an argument value. */ + if (*curshort) + { ++ /* ++ * Only permit further short opts if this one doesn't ++ * require a value. ++ */ ++ if (opt->type != ARG_TYPE_NONE && ++ !(opt->flags & GRUB_ARG_OPTION_OPTIONAL)) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("missing mandatory option for `%s'"), ++ opt->longarg); ++ goto fail; ++ } ++ + if (parse_option (cmd, opt, 0, usr) || grub_errno) + goto fail; + } diff --git a/SOURCES/0431-script-execute-Don-t-crash-on-a-for-loop-with-no-ite.patch b/SOURCES/0431-script-execute-Don-t-crash-on-a-for-loop-with-no-ite.patch new file mode 100644 index 0000000..4e61d40 --- /dev/null +++ b/SOURCES/0431-script-execute-Don-t-crash-on-a-for-loop-with-no-ite.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 22 Jan 2021 16:18:26 +1100 +Subject: [PATCH] script/execute: Don't crash on a "for" loop with no items + +The following crashes the parser: + + for x in; do + 0 + done + +This is because grub_script_arglist_to_argv() doesn't consider the +possibility that arglist is NULL. Catch that explicitly. + +This avoids a NULL pointer dereference. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/script/execute.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c +index 17f4dcab2c6..266d99ed337 100644 +--- a/grub-core/script/execute.c ++++ b/grub-core/script/execute.c +@@ -658,6 +658,9 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, + struct grub_script_arg *arg = 0; + struct grub_script_argv result = { 0, 0, 0 }; + ++ if (arglist == NULL) ++ return 1; ++ + for (; arglist && arglist->arg; arglist = arglist->next) + { + if (grub_script_argv_next (&result)) diff --git a/SOURCES/0432-commands-menuentry-Fix-quoting-in-setparams_prefix.patch b/SOURCES/0432-commands-menuentry-Fix-quoting-in-setparams_prefix.patch new file mode 100644 index 0000000..523dfb1 --- /dev/null +++ b/SOURCES/0432-commands-menuentry-Fix-quoting-in-setparams_prefix.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 22 Jan 2021 17:10:48 +1100 +Subject: [PATCH] commands/menuentry: Fix quoting in setparams_prefix() + +Commit 9acdcbf32542 (use single quotes in menuentry setparams command) +says that expressing a quoted single quote will require 3 characters. It +actually requires (and always did require!) 4 characters: + + str: a'b => a'\''b + len: 3 => 6 (2 for the letters + 4 for the quote) + +This leads to not allocating enough memory and thus out of bounds writes +that have been observed to cause heap corruption. + +Allocate 4 bytes for each single quote. + +Commit 22e7dbb2bb81 (Fix quoting in legacy parser.) does the same +quoting, but it adds 3 as extra overhead on top of the single byte that +the quote already needs. So it's correct. + +Fixes: CVE-2021-20233 +Fixes: 9acdcbf32542 (use single quotes in menuentry setparams command) + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/commands/menuentry.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c +index 4b5fcf2ce9a..7a533b9741b 100644 +--- a/grub-core/commands/menuentry.c ++++ b/grub-core/commands/menuentry.c +@@ -239,7 +239,7 @@ setparams_prefix (int argc, char **args) + len += 3; /* 3 = 1 space + 2 quotes */ + p = args[i]; + while (*p) +- len += (*p++ == '\'' ? 3 : 1); ++ len += (*p++ == '\'' ? 4 : 1); + } + + result = grub_malloc (len + 2); diff --git a/SOURCES/0433-kern-misc-Always-set-end-in-grub_strtoull.patch b/SOURCES/0433-kern-misc-Always-set-end-in-grub_strtoull.patch new file mode 100644 index 0000000..8bcb715 --- /dev/null +++ b/SOURCES/0433-kern-misc-Always-set-end-in-grub_strtoull.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Wed, 13 Jan 2021 22:19:01 +1100 +Subject: [PATCH] kern/misc: Always set *end in grub_strtoull() + +Currently, if there is an error in grub_strtoull(), *end is not set. +This differs from the usual behavior of strtoull(), and also means that +some callers may use an uninitialized value for *end. + +Set *end unconditionally. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/kern/misc.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c +index 97378c48b22..475f3e0ef05 100644 +--- a/grub-core/kern/misc.c ++++ b/grub-core/kern/misc.c +@@ -485,6 +485,10 @@ grub_strtoull (const char *str, const char ** const end, int base) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, + N_("overflow is detected")); ++ ++ if (end) ++ *end = (char *) str; ++ + return ~0ULL; + } + +@@ -496,6 +500,10 @@ grub_strtoull (const char *str, const char ** const end, int base) + { + grub_error (GRUB_ERR_BAD_NUMBER, + N_("unrecognized number")); ++ ++ if (end) ++ *end = (char *) str; ++ + return 0; + } + diff --git a/SOURCES/0434-video-readers-jpeg-Catch-files-with-unsupported-quan.patch b/SOURCES/0434-video-readers-jpeg-Catch-files-with-unsupported-quan.patch new file mode 100644 index 0000000..23e9f3e --- /dev/null +++ b/SOURCES/0434-video-readers-jpeg-Catch-files-with-unsupported-quan.patch @@ -0,0 +1,49 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 15 Jan 2021 12:57:04 +1100 +Subject: [PATCH] video/readers/jpeg: Catch files with unsupported quantization + or Huffman tables + +Our decoder only supports 2 quantization tables. If a file asks for +a quantization table with index > 1, reject it. + +Similarly, our decoder only supports 4 Huffman tables. If a file asks +for a Huffman table with index > 3, reject it. + +This fixes some out of bounds reads. It's not clear what degree of control +over subsequent execution could be gained by someone who can carefully +set up the contents of memory before loading an invalid JPEG file. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/video/readers/jpeg.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index 0b6ce3cee64..23f919aa070 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -333,7 +333,11 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data) + else if (ss != JPEG_SAMPLING_1x1) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: sampling method not supported"); ++ + data->comp_index[id][0] = grub_jpeg_get_byte (data); ++ if (data->comp_index[id][0] > 1) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: too many quantization tables"); + } + + if (data->file->offset != next_marker) +@@ -602,6 +606,10 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) + ht = grub_jpeg_get_byte (data); + data->comp_index[id][1] = (ht >> 4); + data->comp_index[id][2] = (ht & 0xF) + 2; ++ ++ 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"); + } + + grub_jpeg_get_byte (data); /* Skip 3 unused bytes. */ diff --git a/SOURCES/0435-video-readers-jpeg-Catch-OOB-reads-writes-in-grub_jp.patch b/SOURCES/0435-video-readers-jpeg-Catch-OOB-reads-writes-in-grub_jp.patch new file mode 100644 index 0000000..9cd6519 --- /dev/null +++ b/SOURCES/0435-video-readers-jpeg-Catch-OOB-reads-writes-in-grub_jp.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 15 Jan 2021 13:29:53 +1100 +Subject: [PATCH] video/readers/jpeg: Catch OOB reads/writes in + grub_jpeg_decode_du() + +The key line is: + + du[jpeg_zigzag_order[pos]] = val * (int) data->quan_table[qt][pos]; + +jpeg_zigzag_order is grub_uint8_t[64]. + +I don't understand JPEG decoders quite well enough to explain what's +going on here. However, I observe sometimes pos=64, which leads to an +OOB read of the jpeg_zigzag_order global then an OOB write to du. +That leads to various unpleasant memory corruption conditions. + +Catch where pos >= ARRAY_SIZE(jpeg_zigzag_order) and bail. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/video/readers/jpeg.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index 23f919aa070..e5148120f69 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -526,6 +526,14 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) + val = grub_jpeg_get_number (data, num & 0xF); + num >>= 4; + pos += num; ++ ++ if (pos >= ARRAY_SIZE (jpeg_zigzag_order)) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: invalid position in zigzag order!?"); ++ return; ++ } ++ + du[jpeg_zigzag_order[pos]] = val * (int) data->quan_table[qt][pos]; + pos++; + } diff --git a/SOURCES/0436-video-readers-jpeg-Don-t-decode-data-before-start-of.patch b/SOURCES/0436-video-readers-jpeg-Don-t-decode-data-before-start-of.patch new file mode 100644 index 0000000..8fc6b13 --- /dev/null +++ b/SOURCES/0436-video-readers-jpeg-Don-t-decode-data-before-start-of.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 15 Jan 2021 14:06:46 +1100 +Subject: [PATCH] video/readers/jpeg: Don't decode data before start of stream + +When a start of stream marker is encountered, we call grub_jpeg_decode_sos() +which allocates space for a bitmap. + +When a restart marker is encountered, we call grub_jpeg_decode_data() which +then fills in that bitmap. + +If we get a restart marker before the start of stream marker, we will +attempt to write to a bitmap_ptr that hasn't been allocated. Catch this +and bail out. This fixes an attempt to write to NULL. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/video/readers/jpeg.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index e5148120f69..e31602f766a 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -646,6 +646,10 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data) + nr1 = (data->image_height + vb - 1) >> (3 + data->log_vs); + 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"); ++ + for (; data->r1 < nr1 && (!data->dri || rst); + data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3) + for (c1 = 0; c1 < nc1 && (!data->dri || rst); diff --git a/SOURCES/0437-term-gfxterm-Don-t-set-up-a-font-with-glyphs-that-ar.patch b/SOURCES/0437-term-gfxterm-Don-t-set-up-a-font-with-glyphs-that-ar.patch new file mode 100644 index 0000000..533481d --- /dev/null +++ b/SOURCES/0437-term-gfxterm-Don-t-set-up-a-font-with-glyphs-that-ar.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 15 Jan 2021 20:03:20 +1100 +Subject: [PATCH] term/gfxterm: Don't set up a font with glyphs that are too + big + +Catch the case where we have a font so big that it causes the number of +rows or columns to be 0. Currently we continue and allocate a +virtual_screen.text_buffer of size 0. We then try to use that for glpyhs +and things go badly. + +On the emu platform, malloc() may give us a valid pointer, in which case +we'll access heap memory which we shouldn't. Alternatively, it may give us +NULL, in which case we'll crash. For other platforms, if I understand +grub_memalign() correctly, we will receive a valid but small allocation +that we will very likely later overrun. + +Prevent the creation of a virtual screen that isn't at least 40 cols +by 12 rows. This is arbitrary, but it seems that if your width or height +is half a standard 80x24 terminal, you're probably going to struggle to +read anything anyway. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/term/gfxterm.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/grub-core/term/gfxterm.c b/grub-core/term/gfxterm.c +index af7c090a3e7..b40fcce9151 100644 +--- a/grub-core/term/gfxterm.c ++++ b/grub-core/term/gfxterm.c +@@ -232,6 +232,15 @@ grub_virtual_screen_setup (unsigned int x, unsigned int y, + virtual_screen.columns = virtual_screen.width / virtual_screen.normal_char_width; + virtual_screen.rows = virtual_screen.height / virtual_screen.normal_char_height; + ++ /* ++ * There must be a minimum number of rows and columns for the screen to ++ * make sense. Arbitrarily pick half of 80x24. If either dimensions is 0 ++ * we would allocate 0 bytes for the text_buffer. ++ */ ++ if (virtual_screen.columns < 40 || virtual_screen.rows < 12) ++ return grub_error (GRUB_ERR_BAD_FONT, ++ "font: glyphs too large to fit on screen"); ++ + /* Allocate memory for text buffer. */ + virtual_screen.text_buffer = + (struct grub_colored_char *) grub_malloc (virtual_screen.columns diff --git a/SOURCES/0438-fs-fshelp-Catch-impermissibly-large-block-sizes-in-r.patch b/SOURCES/0438-fs-fshelp-Catch-impermissibly-large-block-sizes-in-r.patch new file mode 100644 index 0000000..67c4b55 --- /dev/null +++ b/SOURCES/0438-fs-fshelp-Catch-impermissibly-large-block-sizes-in-r.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 18 Jan 2021 11:46:39 +1100 +Subject: [PATCH] fs/fshelp: Catch impermissibly large block sizes in read + helper + +A fuzzed HFS+ filesystem had log2blocksize = 22. This gave +log2blocksize + GRUB_DISK_SECTOR_BITS = 31. 1 << 31 = 0x80000000, +which is -1 as an int. This caused some wacky behavior later on in +the function, leading to out-of-bounds writes on the destination buffer. + +Catch log2blocksize + GRUB_DISK_SECTOR_BITS >= 31. We could be stricter, +but this is the minimum that will prevent integer size weirdness. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/fs/fshelp.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/grub-core/fs/fshelp.c b/grub-core/fs/fshelp.c +index 4c902adf381..a2d0d297a52 100644 +--- a/grub-core/fs/fshelp.c ++++ b/grub-core/fs/fshelp.c +@@ -362,6 +362,18 @@ grub_fshelp_read_file (grub_disk_t disk, grub_fshelp_node_t node, + grub_disk_addr_t i, blockcnt; + int blocksize = 1 << (log2blocksize + GRUB_DISK_SECTOR_BITS); + ++ /* ++ * Catch blatantly invalid log2blocksize. We could be a lot stricter, but ++ * this is the most permissive we can be before we start to see integer ++ * overflow/underflow issues. ++ */ ++ if (log2blocksize + GRUB_DISK_SECTOR_BITS >= 31) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("blocksize too large")); ++ return -1; ++ } ++ + if (pos > filesize) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, diff --git a/SOURCES/0439-fs-hfsplus-Don-t-fetch-a-key-beyond-the-end-of-the-n.patch b/SOURCES/0439-fs-hfsplus-Don-t-fetch-a-key-beyond-the-end-of-the-n.patch new file mode 100644 index 0000000..6d15b85 --- /dev/null +++ b/SOURCES/0439-fs-hfsplus-Don-t-fetch-a-key-beyond-the-end-of-the-n.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 22 Jan 2021 18:13:56 +1100 +Subject: [PATCH] fs/hfsplus: Don't fetch a key beyond the end of the node + +Otherwise you get a wild pointer, leading to a bunch of invalid reads. +Check it falls inside the given node. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/fs/hfsplus.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/grub-core/fs/hfsplus.c b/grub-core/fs/hfsplus.c +index 03a33ea2477..423f4b956ba 100644 +--- a/grub-core/fs/hfsplus.c ++++ b/grub-core/fs/hfsplus.c +@@ -635,6 +635,10 @@ grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree, + pointer = ((char *) currkey + + grub_be_to_cpu16 (currkey->keylen) + + 2); ++ ++ if ((char *) pointer > node + btree->nodesize - 2) ++ return grub_error (GRUB_ERR_BAD_FS, "HFS+ key beyond end of node"); ++ + currnode = grub_be_to_cpu32 (grub_get_unaligned32 (pointer)); + match = 1; + } diff --git a/SOURCES/0440-fs-hfsplus-Don-t-use-uninitialized-data-on-corrupt-f.patch b/SOURCES/0440-fs-hfsplus-Don-t-use-uninitialized-data-on-corrupt-f.patch new file mode 100644 index 0000000..6418541 --- /dev/null +++ b/SOURCES/0440-fs-hfsplus-Don-t-use-uninitialized-data-on-corrupt-f.patch @@ -0,0 +1,104 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 2 Feb 2021 16:59:35 +1100 +Subject: [PATCH] fs/hfsplus: Don't use uninitialized data on corrupt + filesystems + +Valgrind identified the following use of uninitialized data: + + ==2782220== Conditional jump or move depends on uninitialised value(s) + ==2782220== at 0x42B364: grub_hfsplus_btree_search (hfsplus.c:566) + ==2782220== by 0x42B21D: grub_hfsplus_read_block (hfsplus.c:185) + ==2782220== by 0x42A693: grub_fshelp_read_file (fshelp.c:386) + ==2782220== by 0x42C598: grub_hfsplus_read_file (hfsplus.c:219) + ==2782220== by 0x42C598: grub_hfsplus_mount (hfsplus.c:330) + ==2782220== by 0x42B8C5: grub_hfsplus_dir (hfsplus.c:958) + ==2782220== by 0x4C1AE6: grub_fs_probe (fs.c:73) + ==2782220== by 0x407C94: grub_ls_list_files (ls.c:186) + ==2782220== by 0x407C94: grub_cmd_ls (ls.c:284) + ==2782220== by 0x4D7130: grub_extcmd_dispatcher (extcmd.c:55) + ==2782220== by 0x4045A6: execute_command (grub-fstest.c:59) + ==2782220== by 0x4045A6: fstest (grub-fstest.c:433) + ==2782220== by 0x4045A6: main (grub-fstest.c:772) + ==2782220== Uninitialised value was created by a heap allocation + ==2782220== at 0x483C7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) + ==2782220== by 0x4C0305: grub_malloc (mm.c:42) + ==2782220== by 0x42C21D: grub_hfsplus_mount (hfsplus.c:239) + ==2782220== by 0x42B8C5: grub_hfsplus_dir (hfsplus.c:958) + ==2782220== by 0x4C1AE6: grub_fs_probe (fs.c:73) + ==2782220== by 0x407C94: grub_ls_list_files (ls.c:186) + ==2782220== by 0x407C94: grub_cmd_ls (ls.c:284) + ==2782220== by 0x4D7130: grub_extcmd_dispatcher (extcmd.c:55) + ==2782220== by 0x4045A6: execute_command (grub-fstest.c:59) + ==2782220== by 0x4045A6: fstest (grub-fstest.c:433) + ==2782220== by 0x4045A6: main (grub-fstest.c:772) + +This happens when the process of reading the catalog file goes sufficiently +wrong that there's an attempt to read the extent overflow file, which has +not yet been loaded. Keep track of when the extent overflow file is +fully loaded and refuse to use it before then. + +The load valgrind doesn't like is btree->nodesize, and that's then used +to allocate a data structure. It looks like there are subsequently a lot +of reads based on that pointer so OOB reads are likely, and indeed crashes +(albeit difficult-to-replicate ones) have been observed in fuzzing. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/fs/hfsplus.c | 14 ++++++++++++++ + include/grub/hfsplus.h | 2 ++ + 2 files changed, 16 insertions(+) + +diff --git a/grub-core/fs/hfsplus.c b/grub-core/fs/hfsplus.c +index 423f4b956ba..8c0c804735d 100644 +--- a/grub-core/fs/hfsplus.c ++++ b/grub-core/fs/hfsplus.c +@@ -177,6 +177,17 @@ grub_hfsplus_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) + break; + } + ++ /* ++ * If the extent overflow tree isn't ready yet, we can't look ++ * in it. This can happen where the catalog file is corrupted. ++ */ ++ if (!node->data->extoverflow_tree_ready) ++ { ++ grub_error (GRUB_ERR_BAD_FS, ++ "attempted to read extent overflow tree before loading"); ++ break; ++ } ++ + /* Set up the key to look for in the extent overflow file. */ + extoverflow.extkey.fileid = node->fileid; + extoverflow.extkey.type = 0; +@@ -241,6 +252,7 @@ grub_hfsplus_mount (grub_disk_t disk) + return 0; + + data->disk = disk; ++ data->extoverflow_tree_ready = 0; + + /* Read the bootblock. */ + grub_disk_read (disk, GRUB_HFSPLUS_SBLOCK, 0, sizeof (volheader), +@@ -357,6 +369,8 @@ grub_hfsplus_mount (grub_disk_t disk) + if (data->extoverflow_tree.nodesize < 2) + goto fail; + ++ data->extoverflow_tree_ready = 1; ++ + if (grub_hfsplus_read_file (&data->attr_tree.file, 0, 0, + sizeof (struct grub_hfsplus_btnode), + sizeof (header), (char *) &header) <= 0) +diff --git a/include/grub/hfsplus.h b/include/grub/hfsplus.h +index 117740ae269..e14dd31ff54 100644 +--- a/include/grub/hfsplus.h ++++ b/include/grub/hfsplus.h +@@ -113,6 +113,8 @@ struct grub_hfsplus_data + struct grub_hfsplus_btree extoverflow_tree; + struct grub_hfsplus_btree attr_tree; + ++ int extoverflow_tree_ready; ++ + struct grub_hfsplus_file dirroot; + struct grub_hfsplus_file opened_file; + diff --git a/SOURCES/0441-fs-hfs-Disable-under-lockdown.patch b/SOURCES/0441-fs-hfs-Disable-under-lockdown.patch new file mode 100644 index 0000000..e2971f0 --- /dev/null +++ b/SOURCES/0441-fs-hfs-Disable-under-lockdown.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 18 Jan 2021 12:19:07 +1100 +Subject: [PATCH] fs/hfs: Disable under lockdown + +HFS has issues such as infinite mutual recursion that are simply too +complex to fix for such a legacy format. So simply do not permit +it to be loaded under lockdown. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/fs/hfs.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/grub-core/fs/hfs.c b/grub-core/fs/hfs.c +index 3fd4eec202c..49d1831c808 100644 +--- a/grub-core/fs/hfs.c ++++ b/grub-core/fs/hfs.c +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -1433,11 +1434,13 @@ static struct grub_fs grub_hfs_fs = + + GRUB_MOD_INIT(hfs) + { +- grub_fs_register (&grub_hfs_fs); ++ if (!grub_is_lockdown ()) ++ grub_fs_register (&grub_hfs_fs); + my_mod = mod; + } + + GRUB_MOD_FINI(hfs) + { +- grub_fs_unregister (&grub_hfs_fs); ++ if (!grub_is_lockdown()) ++ grub_fs_unregister (&grub_hfs_fs); + } diff --git a/SOURCES/0442-fs-sfs-Fix-over-read-of-root-object-name.patch b/SOURCES/0442-fs-sfs-Fix-over-read-of-root-object-name.patch new file mode 100644 index 0000000..dddbe7f --- /dev/null +++ b/SOURCES/0442-fs-sfs-Fix-over-read-of-root-object-name.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 18 Jan 2021 14:34:58 +1100 +Subject: [PATCH] fs/sfs: Fix over-read of root object name + +There's a read of the name of the root object that assumes that the name +is nul-terminated within the root block. This isn't guaranteed - it seems +SFS would require you to read multiple blocks to get a full name in general, +but maybe that doesn't apply to the root object. + +Either way, figure out how much space is left in the root block and don't +over-read it. This fixes some OOB reads. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/fs/sfs.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/grub-core/fs/sfs.c b/grub-core/fs/sfs.c +index 3ddc6b5e287..61d6c303cb3 100644 +--- a/grub-core/fs/sfs.c ++++ b/grub-core/fs/sfs.c +@@ -373,6 +373,7 @@ grub_sfs_mount (grub_disk_t disk) + struct grub_sfs_objc *rootobjc; + char *rootobjc_data = 0; + grub_uint32_t blk; ++ unsigned int max_len; + + data = grub_malloc (sizeof (*data)); + if (!data) +@@ -421,7 +422,13 @@ grub_sfs_mount (grub_disk_t disk) + data->diropen.data = data; + data->diropen.cache = 0; + data->disk = disk; +- data->label = grub_strdup ((char *) (rootobjc->objects[0].filename)); ++ ++ /* We only read 1 block of data, so truncate the name if needed. */ ++ max_len = ((GRUB_DISK_SECTOR_SIZE << data->log_blocksize) ++ - 24 /* offsetof (struct grub_sfs_objc, objects) */ ++ - 25); /* offsetof (struct grub_sfs_obj, filename) */ ++ data->label = grub_zalloc (max_len + 1); ++ grub_strncpy (data->label, (char *) rootobjc->objects[0].filename, max_len); + + grub_free (rootobjc_data); + return data; diff --git a/SOURCES/0443-fs-jfs-Do-not-move-to-leaf-level-if-name-length-is-n.patch b/SOURCES/0443-fs-jfs-Do-not-move-to-leaf-level-if-name-length-is-n.patch new file mode 100644 index 0000000..7c75a3b --- /dev/null +++ b/SOURCES/0443-fs-jfs-Do-not-move-to-leaf-level-if-name-length-is-n.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 18 Jan 2021 14:51:11 +1100 +Subject: [PATCH] fs/jfs: Do not move to leaf level if name length is negative + +Fuzzing JFS revealed crashes where a negative number would be passed +to le_to_cpu16_copy(). There it would be cast to a large positive number +and the copy would read and write off the end of the respective buffers. + +Catch this at the top as well as the bottom of the loop. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/fs/jfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/fs/jfs.c b/grub-core/fs/jfs.c +index aab3e8c7b7d..1819899bdec 100644 +--- a/grub-core/fs/jfs.c ++++ b/grub-core/fs/jfs.c +@@ -563,7 +563,7 @@ grub_jfs_getent (struct grub_jfs_diropen *diro) + + /* Move down to the leaf level. */ + nextent = leaf->next; +- if (leaf->next != 255) ++ if (leaf->next != 255 && len > 0) + do + { + next_leaf = &diro->next_leaf[nextent]; diff --git a/SOURCES/0444-fs-jfs-Limit-the-extents-that-getblk-can-consider.patch b/SOURCES/0444-fs-jfs-Limit-the-extents-that-getblk-can-consider.patch new file mode 100644 index 0000000..91ab8db --- /dev/null +++ b/SOURCES/0444-fs-jfs-Limit-the-extents-that-getblk-can-consider.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 18 Jan 2021 14:57:17 +1100 +Subject: [PATCH] fs/jfs: Limit the extents that getblk() can consider + +getblk() implicitly trusts that treehead->count is an accurate count of +the number of extents. However, that value is read from disk and is not +trustworthy, leading to OOB reads and crashes. I am not sure to what +extent the data read from OOB can influence subsequent program execution. + +Require callers to pass in the maximum number of extents for which +they have storage. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/fs/jfs.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/grub-core/fs/jfs.c b/grub-core/fs/jfs.c +index 1819899bdec..6e81f37da6c 100644 +--- a/grub-core/fs/jfs.c ++++ b/grub-core/fs/jfs.c +@@ -261,13 +261,15 @@ static grub_err_t grub_jfs_lookup_symlink (struct grub_jfs_data *data, grub_uint + static grub_int64_t + getblk (struct grub_jfs_treehead *treehead, + struct grub_jfs_tree_extent *extents, ++ int max_extents, + struct grub_jfs_data *data, + grub_uint64_t blk) + { + int found = -1; + int i; + +- for (i = 0; i < grub_le_to_cpu16 (treehead->count) - 2; i++) ++ for (i = 0; i < grub_le_to_cpu16 (treehead->count) - 2 && ++ i < max_extents; i++) + { + if (treehead->flags & GRUB_JFS_TREE_LEAF) + { +@@ -302,7 +304,7 @@ getblk (struct grub_jfs_treehead *treehead, + << (grub_le_to_cpu16 (data->sblock.log2_blksz) + - GRUB_DISK_SECTOR_BITS), 0, + sizeof (*tree), (char *) tree)) +- ret = getblk (&tree->treehead, &tree->extents[0], data, blk); ++ ret = getblk (&tree->treehead, &tree->extents[0], 254, data, blk); + grub_free (tree); + return ret; + } +@@ -316,7 +318,7 @@ static grub_int64_t + grub_jfs_blkno (struct grub_jfs_data *data, struct grub_jfs_inode *inode, + grub_uint64_t blk) + { +- return getblk (&inode->file.tree, &inode->file.extents[0], data, blk); ++ return getblk (&inode->file.tree, &inode->file.extents[0], 16, data, blk); + } + + diff --git a/SOURCES/0445-fs-jfs-Catch-infinite-recursion.patch b/SOURCES/0445-fs-jfs-Catch-infinite-recursion.patch new file mode 100644 index 0000000..dee5914 --- /dev/null +++ b/SOURCES/0445-fs-jfs-Catch-infinite-recursion.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 18 Jan 2021 15:47:24 +1100 +Subject: [PATCH] fs/jfs: Catch infinite recursion + +It's possible with a fuzzed filesystem for JFS to keep getblk()-ing +the same data over and over again, leading to stack exhaustion. + +Check if we'd be calling the function with exactly the same data as +was passed in, and if so abort. + +I'm not sure what the performance impact of this is and am open to +better ideas. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/fs/jfs.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/grub-core/fs/jfs.c b/grub-core/fs/jfs.c +index 6e81f37da6c..20d966abfc0 100644 +--- a/grub-core/fs/jfs.c ++++ b/grub-core/fs/jfs.c +@@ -304,7 +304,16 @@ getblk (struct grub_jfs_treehead *treehead, + << (grub_le_to_cpu16 (data->sblock.log2_blksz) + - GRUB_DISK_SECTOR_BITS), 0, + sizeof (*tree), (char *) tree)) +- ret = getblk (&tree->treehead, &tree->extents[0], 254, data, blk); ++ { ++ if (grub_memcmp (&tree->treehead, treehead, sizeof (struct grub_jfs_treehead)) || ++ grub_memcmp (&tree->extents, extents, 254 * sizeof (struct grub_jfs_tree_extent))) ++ ret = getblk (&tree->treehead, &tree->extents[0], 254, data, blk); ++ else ++ { ++ grub_error (GRUB_ERR_BAD_FS, "jfs: infinite recursion detected"); ++ ret = -1; ++ } ++ } + grub_free (tree); + return ret; + } diff --git a/SOURCES/0446-fs-nilfs2-Reject-too-large-keys.patch b/SOURCES/0446-fs-nilfs2-Reject-too-large-keys.patch new file mode 100644 index 0000000..76c864f --- /dev/null +++ b/SOURCES/0446-fs-nilfs2-Reject-too-large-keys.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 18 Jan 2021 16:49:09 +1100 +Subject: [PATCH] fs/nilfs2: Reject too-large keys + +NILFS2 has up to 7 keys, per the data structure. Do not permit array +indices in excess of that. + +This catches some OOB reads. I don't know how controllable the invalidly +read data is or if that could be used later in the program. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/fs/nilfs2.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/grub-core/fs/nilfs2.c b/grub-core/fs/nilfs2.c +index 598a2a55baf..61e8af9ff7b 100644 +--- a/grub-core/fs/nilfs2.c ++++ b/grub-core/fs/nilfs2.c +@@ -569,6 +569,11 @@ grub_nilfs2_btree_lookup (struct grub_nilfs2_data *data, + static inline grub_uint64_t + grub_nilfs2_direct_lookup (struct grub_nilfs2_inode *inode, grub_uint64_t key) + { ++ if (1 + key > 6) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "key is too large"); ++ return 0xffffffffffffffff; ++ } + return grub_le_to_cpu64 (inode->i_bmap[1 + key]); + } + +@@ -584,7 +589,7 @@ grub_nilfs2_bmap_lookup (struct grub_nilfs2_data *data, + { + grub_uint64_t ptr; + ptr = grub_nilfs2_direct_lookup (inode, key); +- if (need_translate) ++ if (ptr != ((grub_uint64_t) 0xffffffffffffffff) && need_translate) + ptr = grub_nilfs2_dat_translate (data, ptr); + return ptr; + } diff --git a/SOURCES/0447-fs-nilfs2-Don-t-search-children-if-provided-number-i.patch b/SOURCES/0447-fs-nilfs2-Don-t-search-children-if-provided-number-i.patch new file mode 100644 index 0000000..a46141a --- /dev/null +++ b/SOURCES/0447-fs-nilfs2-Don-t-search-children-if-provided-number-i.patch @@ -0,0 +1,96 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 18 Jan 2021 16:49:44 +1100 +Subject: [PATCH] fs/nilfs2: Don't search children if provided number is too + large + +NILFS2 reads the number of children a node has from the node. Unfortunately, +that's not trustworthy. Check if it's beyond what the filesystem permits and +reject it if so. + +This blocks some OOB reads. I'm not sure how controllable the read is and what +could be done with invalidly read data later on. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/fs/nilfs2.c | 38 +++++++++++++++++++++++--------------- + 1 file changed, 23 insertions(+), 15 deletions(-) + +diff --git a/grub-core/fs/nilfs2.c b/grub-core/fs/nilfs2.c +index 61e8af9ff7b..054ad3dc18a 100644 +--- a/grub-core/fs/nilfs2.c ++++ b/grub-core/fs/nilfs2.c +@@ -416,14 +416,34 @@ grub_nilfs2_btree_node_get_key (struct grub_nilfs2_btree_node *node, + } + + static inline int +-grub_nilfs2_btree_node_lookup (struct grub_nilfs2_btree_node *node, ++grub_nilfs2_btree_node_nchildren_max (struct grub_nilfs2_data *data, ++ struct grub_nilfs2_btree_node *node) ++{ ++ int node_children_max = ((NILFS2_BLOCK_SIZE (data) - ++ sizeof (struct grub_nilfs2_btree_node) - ++ NILFS_BTREE_NODE_EXTRA_PAD_SIZE) / ++ (sizeof (grub_uint64_t) + sizeof (grub_uint64_t))); ++ ++ return (node->bn_flags & NILFS_BTREE_NODE_ROOT) ? 3 : node_children_max; ++} ++ ++static inline int ++grub_nilfs2_btree_node_lookup (struct grub_nilfs2_data *data, ++ struct grub_nilfs2_btree_node *node, + grub_uint64_t key, int *indexp) + { + grub_uint64_t nkey; + int index, low, high, s; + + low = 0; ++ + high = grub_le_to_cpu16 (node->bn_nchildren) - 1; ++ if (high >= grub_nilfs2_btree_node_nchildren_max (data, node)) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "too many children"); ++ return 0; ++ } ++ + index = 0; + s = 0; + while (low <= high) +@@ -459,18 +479,6 @@ grub_nilfs2_btree_node_lookup (struct grub_nilfs2_btree_node *node, + return s == 0; + } + +-static inline int +-grub_nilfs2_btree_node_nchildren_max (struct grub_nilfs2_data *data, +- struct grub_nilfs2_btree_node *node) +-{ +- int node_children_max = ((NILFS2_BLOCK_SIZE (data) - +- sizeof (struct grub_nilfs2_btree_node) - +- NILFS_BTREE_NODE_EXTRA_PAD_SIZE) / +- (sizeof (grub_uint64_t) + sizeof (grub_uint64_t))); +- +- return (node->bn_flags & NILFS_BTREE_NODE_ROOT) ? 3 : node_children_max; +-} +- + static inline grub_uint64_t * + grub_nilfs2_btree_node_dptrs (struct grub_nilfs2_data *data, + struct grub_nilfs2_btree_node *node) +@@ -517,7 +525,7 @@ grub_nilfs2_btree_lookup (struct grub_nilfs2_data *data, + node = grub_nilfs2_btree_get_root (inode); + level = grub_nilfs2_btree_get_level (node); + +- found = grub_nilfs2_btree_node_lookup (node, key, &index); ++ found = grub_nilfs2_btree_node_lookup (data, node, key, &index); + ptr = grub_nilfs2_btree_node_get_ptr (data, node, index); + if (need_translate) + ptr = grub_nilfs2_dat_translate (data, ptr); +@@ -538,7 +546,7 @@ grub_nilfs2_btree_lookup (struct grub_nilfs2_data *data, + } + + if (!found) +- found = grub_nilfs2_btree_node_lookup (node, key, &index); ++ found = grub_nilfs2_btree_node_lookup (data, node, key, &index); + else + index = 0; + diff --git a/SOURCES/0448-fs-nilfs2-Properly-bail-on-errors-in-grub_nilfs2_btr.patch b/SOURCES/0448-fs-nilfs2-Properly-bail-on-errors-in-grub_nilfs2_btr.patch new file mode 100644 index 0000000..4f90e76 --- /dev/null +++ b/SOURCES/0448-fs-nilfs2-Properly-bail-on-errors-in-grub_nilfs2_btr.patch @@ -0,0 +1,64 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 18 Jan 2021 17:06:19 +1100 +Subject: [PATCH] fs/nilfs2: Properly bail on errors in + grub_nilfs2_btree_node_lookup() + +We just introduced an error return in grub_nilfs2_btree_node_lookup(). +Make sure the callers catch it. + +At the same time, make sure that grub_nilfs2_btree_node_lookup() always +inits the index pointer passed to it. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/fs/nilfs2.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/grub-core/fs/nilfs2.c b/grub-core/fs/nilfs2.c +index 054ad3dc18a..c4c4610bec0 100644 +--- a/grub-core/fs/nilfs2.c ++++ b/grub-core/fs/nilfs2.c +@@ -433,7 +433,7 @@ grub_nilfs2_btree_node_lookup (struct grub_nilfs2_data *data, + grub_uint64_t key, int *indexp) + { + grub_uint64_t nkey; +- int index, low, high, s; ++ int index = 0, low, high, s; + + low = 0; + +@@ -441,10 +441,10 @@ grub_nilfs2_btree_node_lookup (struct grub_nilfs2_data *data, + if (high >= grub_nilfs2_btree_node_nchildren_max (data, node)) + { + grub_error (GRUB_ERR_BAD_FS, "too many children"); ++ *indexp = index; + return 0; + } + +- index = 0; + s = 0; + while (low <= high) + { +@@ -526,6 +526,10 @@ grub_nilfs2_btree_lookup (struct grub_nilfs2_data *data, + level = grub_nilfs2_btree_get_level (node); + + found = grub_nilfs2_btree_node_lookup (data, node, key, &index); ++ ++ if (grub_errno != GRUB_ERR_NONE) ++ goto fail; ++ + ptr = grub_nilfs2_btree_node_get_ptr (data, node, index); + if (need_translate) + ptr = grub_nilfs2_dat_translate (data, ptr); +@@ -550,7 +554,8 @@ grub_nilfs2_btree_lookup (struct grub_nilfs2_data *data, + else + index = 0; + +- if (index < grub_nilfs2_btree_node_nchildren_max (data, node)) ++ if (index < grub_nilfs2_btree_node_nchildren_max (data, node) && ++ grub_errno == GRUB_ERR_NONE) + { + ptr = grub_nilfs2_btree_node_get_ptr (data, node, index); + if (need_translate) diff --git a/SOURCES/0449-io-gzio-Bail-if-gzio-tl-td-is-NULL.patch b/SOURCES/0449-io-gzio-Bail-if-gzio-tl-td-is-NULL.patch new file mode 100644 index 0000000..d50a182 --- /dev/null +++ b/SOURCES/0449-io-gzio-Bail-if-gzio-tl-td-is-NULL.patch @@ -0,0 +1,63 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Wed, 13 Jan 2021 20:59:09 +1100 +Subject: [PATCH] io/gzio: Bail if gzio->tl/td is NULL + +This is an ugly fix that doesn't address why gzio->tl comes to be NULL. +However, it seems to be sufficient to patch up a bunch of NULL derefs. + +It would be good to revisit this in future and see if we can have +a cleaner solution that addresses some of the causes of the unexpected +NULL pointers. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/io/gzio.c | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/grub-core/io/gzio.c b/grub-core/io/gzio.c +index 2ecf076dd5e..6e9b9c9361a 100644 +--- a/grub-core/io/gzio.c ++++ b/grub-core/io/gzio.c +@@ -669,6 +669,13 @@ inflate_codes_in_window (grub_gzio_t gzio) + { + if (! gzio->code_state) + { ++ ++ if (gzio->tl == NULL) ++ { ++ grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "NULL gzio->tl"); ++ return 1; ++ } ++ + NEEDBITS ((unsigned) gzio->bl); + if ((e = (t = gzio->tl + ((unsigned) b & ml))->e) > 16) + do +@@ -707,6 +714,12 @@ inflate_codes_in_window (grub_gzio_t gzio) + n = t->v.n + ((unsigned) b & mask_bits[e]); + DUMPBITS (e); + ++ if (gzio->td == NULL) ++ { ++ grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "NULL gzio->td"); ++ return 1; ++ } ++ + /* decode distance of block to copy */ + NEEDBITS ((unsigned) gzio->bd); + if ((e = (t = gzio->td + ((unsigned) b & md))->e) > 16) +@@ -917,6 +930,13 @@ init_dynamic_block (grub_gzio_t gzio) + n = nl + nd; + m = mask_bits[gzio->bl]; + i = l = 0; ++ ++ if (gzio->tl == NULL) ++ { ++ grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "NULL gzio->tl"); ++ return; ++ } ++ + while ((unsigned) i < n) + { + NEEDBITS ((unsigned) gzio->bl); diff --git a/SOURCES/0450-io-gzio-Add-init_dynamic_block-clean-up-if-unpacking.patch b/SOURCES/0450-io-gzio-Add-init_dynamic_block-clean-up-if-unpacking.patch new file mode 100644 index 0000000..9e33dee --- /dev/null +++ b/SOURCES/0450-io-gzio-Add-init_dynamic_block-clean-up-if-unpacking.patch @@ -0,0 +1,63 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 21 Jan 2021 00:05:58 +1100 +Subject: [PATCH] io/gzio: Add init_dynamic_block() clean up if unpacking codes + fails + +init_dynamic_block() didn't clean up gzio->tl and td in some error +paths. This left td pointing to part of tl. Then in grub_gzio_close(), +when tl was freed the storage for td would also be freed. The code then +attempts to free td explicitly, performing a UAF and then a double free. + +Explicitly clean up tl and td in the error paths. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/io/gzio.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/grub-core/io/gzio.c b/grub-core/io/gzio.c +index 6e9b9c9361a..97b34f88574 100644 +--- a/grub-core/io/gzio.c ++++ b/grub-core/io/gzio.c +@@ -953,7 +953,7 @@ init_dynamic_block (grub_gzio_t gzio) + if ((unsigned) i + j > n) + { + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "too many codes found"); +- return; ++ goto fail; + } + while (j--) + ll[i++] = l; +@@ -966,7 +966,7 @@ init_dynamic_block (grub_gzio_t gzio) + if ((unsigned) i + j > n) + { + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "too many codes found"); +- return; ++ goto fail; + } + while (j--) + ll[i++] = 0; +@@ -981,7 +981,7 @@ init_dynamic_block (grub_gzio_t gzio) + if ((unsigned) i + j > n) + { + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "too many codes found"); +- return; ++ goto fail; + } + while (j--) + ll[i++] = 0; +@@ -1019,6 +1019,12 @@ init_dynamic_block (grub_gzio_t gzio) + /* indicate we're now working on a block */ + gzio->code_state = 0; + gzio->block_len++; ++ return; ++ ++ fail: ++ huft_free (gzio->tl); ++ gzio->td = NULL; ++ gzio->tl = NULL; + } + + diff --git a/SOURCES/0451-io-gzio-Catch-missing-values-in-huft_build-and-bail.patch b/SOURCES/0451-io-gzio-Catch-missing-values-in-huft_build-and-bail.patch new file mode 100644 index 0000000..1d1c372 --- /dev/null +++ b/SOURCES/0451-io-gzio-Catch-missing-values-in-huft_build-and-bail.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 21 Jan 2021 12:20:49 +1100 +Subject: [PATCH] io/gzio: Catch missing values in huft_build() and bail + +In huft_build(), "v" is a table of values in order of bit length. +The code later (when setting up table entries in "r") assumes that all +elements of this array corresponding to a code are initialized and less +than N_MAX. However, it doesn't enforce this. + +With sufficiently manipulated inputs (e.g. from fuzzing), there can be +elements of "v" that are not filled. Therefore a lookup into "e" or "d" +will use an uninitialized value. This can lead to an invalid/OOB read on +those values, often leading to a crash. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/io/gzio.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/grub-core/io/gzio.c b/grub-core/io/gzio.c +index 97b34f88574..f85dbae237d 100644 +--- a/grub-core/io/gzio.c ++++ b/grub-core/io/gzio.c +@@ -507,6 +507,7 @@ huft_build (unsigned *b, /* code lengths in bits (all assumed <= BMAX) */ + } + + /* Make a table of values in order of bit lengths */ ++ grub_memset (v, N_MAX, ARRAY_SIZE (v)); + p = b; + i = 0; + do +@@ -588,11 +589,18 @@ huft_build (unsigned *b, /* code lengths in bits (all assumed <= BMAX) */ + r.v.n = (ush) (*p); /* simple code is just the value */ + p++; /* one compiler does not like *p++ */ + } +- else ++ else if (*p < N_MAX) + { + r.e = (uch) e[*p - s]; /* non-simple--look up in lists */ + r.v.n = d[*p++ - s]; + } ++ else ++ { ++ /* Detected an uninitialised value, abort. */ ++ if (h) ++ huft_free (u[0]); ++ return 2; ++ } + + /* fill code-like entries with r */ + f = 1 << (k - w); diff --git a/SOURCES/0452-io-gzio-Zero-gzio-tl-td-in-init_dynamic_block-if-huf.patch b/SOURCES/0452-io-gzio-Zero-gzio-tl-td-in-init_dynamic_block-if-huf.patch new file mode 100644 index 0000000..c75f528 --- /dev/null +++ b/SOURCES/0452-io-gzio-Zero-gzio-tl-td-in-init_dynamic_block-if-huf.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 21 Jan 2021 12:22:28 +1100 +Subject: [PATCH] io/gzio: Zero gzio->tl/td in init_dynamic_block() if + huft_build() fails + +If huft_build() fails, gzio->tl or gzio->td could contain pointers that +are no longer valid. Zero them out. + +This prevents a double free when grub_gzio_close() comes through and +attempts to free them again. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/io/gzio.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/grub-core/io/gzio.c b/grub-core/io/gzio.c +index f85dbae237d..e9f332fbcd9 100644 +--- a/grub-core/io/gzio.c ++++ b/grub-core/io/gzio.c +@@ -1010,6 +1010,7 @@ init_dynamic_block (grub_gzio_t gzio) + gzio->bl = lbits; + if (huft_build (ll, nl, 257, cplens, cplext, &gzio->tl, &gzio->bl) != 0) + { ++ gzio->tl = 0; + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, + "failed in building a Huffman code table"); + return; +@@ -1019,6 +1020,7 @@ init_dynamic_block (grub_gzio_t gzio) + { + huft_free (gzio->tl); + gzio->tl = 0; ++ gzio->td = 0; + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, + "failed in building a Huffman code table"); + return; diff --git a/SOURCES/0453-disk-lvm-Don-t-go-beyond-the-end-of-the-data-we-read.patch b/SOURCES/0453-disk-lvm-Don-t-go-beyond-the-end-of-the-data-we-read.patch new file mode 100644 index 0000000..3a8cb85 --- /dev/null +++ b/SOURCES/0453-disk-lvm-Don-t-go-beyond-the-end-of-the-data-we-read.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 21 Jan 2021 17:59:14 +1100 +Subject: [PATCH] disk/lvm: Don't go beyond the end of the data we read from + disk + +We unconditionally trusted offset_xl from the LVM label header, even if +it told us that the PV header/disk locations were way off past the end +of the data we read from disk. + +Require that the offset be sane, fixing an OOB read and crash. + +Fixes: CID 314367, CID 314371 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/disk/lvm.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c +index 4fbb3eac0ea..0f466040a55 100644 +--- a/grub-core/disk/lvm.c ++++ b/grub-core/disk/lvm.c +@@ -142,6 +142,20 @@ grub_lvm_detect (grub_disk_t disk, + goto fail; + } + ++ /* ++ * We read a grub_lvm_pv_header and then 2 grub_lvm_disk_locns that ++ * immediately follow the PV header. Make sure we have space for both. ++ */ ++ if (grub_le_to_cpu32 (lh->offset_xl) >= ++ GRUB_LVM_LABEL_SIZE - sizeof (struct grub_lvm_pv_header) - ++ 2 * sizeof (struct grub_lvm_disk_locn)) ++ { ++#ifdef GRUB_UTIL ++ grub_util_info ("LVM PV header/disk locations are beyond the end of the block"); ++#endif ++ goto fail; ++ } ++ + pvh = (struct grub_lvm_pv_header *) (buf + grub_le_to_cpu32(lh->offset_xl)); + + for (i = 0, j = 0; i < GRUB_LVM_ID_LEN; i++) diff --git a/SOURCES/0454-disk-lvm-Don-t-blast-past-the-end-of-the-circular-me.patch b/SOURCES/0454-disk-lvm-Don-t-blast-past-the-end-of-the-circular-me.patch new file mode 100644 index 0000000..8793efc --- /dev/null +++ b/SOURCES/0454-disk-lvm-Don-t-blast-past-the-end-of-the-circular-me.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 21 Jan 2021 18:19:51 +1100 +Subject: [PATCH] disk/lvm: Don't blast past the end of the circular metadata + buffer + +This catches at least some OOB reads, and it's possible I suppose that +if 2 * mda_size is less than GRUB_LVM_MDA_HEADER_SIZE it might catch some +OOB writes too (although that hasn't showed up as a crash in fuzzing yet). + +It's a bit ugly and I'd appreciate better suggestions. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/disk/lvm.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c +index 0f466040a55..ec3545e164b 100644 +--- a/grub-core/disk/lvm.c ++++ b/grub-core/disk/lvm.c +@@ -215,6 +215,16 @@ grub_lvm_detect (grub_disk_t disk, + if (grub_le_to_cpu64 (rlocn->offset) + grub_le_to_cpu64 (rlocn->size) > + grub_le_to_cpu64 (mdah->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; ++ } ++ + /* Metadata is circular. Copy the wrap in place. */ + grub_memcpy (metadatabuf + mda_size, + metadatabuf + GRUB_LVM_MDA_HEADER_SIZE, diff --git a/SOURCES/0455-disk-lvm-Bail-on-missing-PV-list.patch b/SOURCES/0455-disk-lvm-Bail-on-missing-PV-list.patch new file mode 100644 index 0000000..621266b --- /dev/null +++ b/SOURCES/0455-disk-lvm-Bail-on-missing-PV-list.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 21 Jan 2021 18:54:29 +1100 +Subject: [PATCH] disk/lvm: Bail on missing PV list + +There's an if block for the presence of "physical_volumes {", but if +that block is absent, then p remains NULL and a NULL-deref will result +when looking for logical volumes. + +It doesn't seem like LVM makes sense without physical volumes, so error +out rather than crashing. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/disk/lvm.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c +index ec3545e164b..1e80137c452 100644 +--- a/grub-core/disk/lvm.c ++++ b/grub-core/disk/lvm.c +@@ -371,6 +371,8 @@ error_parsing_metadata: + goto fail4; + } + } ++ else ++ goto fail4; + + p = grub_strstr (p, "logical_volumes {"); + if (p) diff --git a/SOURCES/0456-disk-lvm-Do-not-crash-if-an-expected-string-is-not-f.patch b/SOURCES/0456-disk-lvm-Do-not-crash-if-an-expected-string-is-not-f.patch new file mode 100644 index 0000000..2ca0659 --- /dev/null +++ b/SOURCES/0456-disk-lvm-Do-not-crash-if-an-expected-string-is-not-f.patch @@ -0,0 +1,79 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 21 Jan 2021 18:35:22 +1100 +Subject: [PATCH] disk/lvm: Do not crash if an expected string is not found + +Clean up a bunch of cases where we could have strstr() fail and lead to +us dereferencing NULL. + +We'll still leak memory in some cases (loops don't clean up allocations +from earlier iterations if a later iteration fails) but at least we're +not crashing. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/disk/lvm.c | 22 +++++++++++++++++----- + 1 file changed, 17 insertions(+), 5 deletions(-) + +diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c +index 1e80137c452..03587e744dc 100644 +--- a/grub-core/disk/lvm.c ++++ b/grub-core/disk/lvm.c +@@ -541,7 +541,16 @@ error_parsing_metadata: + } + + if (seg->node_count != 1) +- seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = "); ++ { ++ seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = "); ++ if (p == NULL) ++ { ++#ifdef GRUB_UTIL ++ grub_util_info ("unknown stripe_size"); ++#endif ++ goto lvs_segment_fail; ++ } ++ } + + seg->nodes = grub_calloc (seg->node_count, + sizeof (*stripe)); +@@ -561,7 +570,7 @@ error_parsing_metadata: + { + p = grub_strchr (p, '"'); + if (p == NULL) +- continue; ++ goto lvs_segment_fail2; + q = ++p; + while (*q != '"') + q++; +@@ -580,7 +589,10 @@ error_parsing_metadata: + stripe->start = grub_lvm_getvalue (&p, ",") + * vg->extent_size; + if (p == NULL) +- continue; ++ { ++ grub_free (stripe->name); ++ goto lvs_segment_fail2; ++ } + + stripe++; + } +@@ -617,7 +629,7 @@ error_parsing_metadata: + + p = grub_strchr (p, '"'); + if (p == NULL) +- continue; ++ goto lvs_segment_fail2; + q = ++p; + while (*q != '"') + q++; +@@ -705,7 +717,7 @@ error_parsing_metadata: + p = p ? grub_strchr (p + 1, '"') : 0; + p = p ? grub_strchr (p + 1, '"') : 0; + if (p == NULL) +- continue; ++ goto lvs_segment_fail2; + q = ++p; + while (*q != '"') + q++; diff --git a/SOURCES/0457-disk-lvm-Do-not-overread-metadata.patch b/SOURCES/0457-disk-lvm-Do-not-overread-metadata.patch new file mode 100644 index 0000000..2138f6c --- /dev/null +++ b/SOURCES/0457-disk-lvm-Do-not-overread-metadata.patch @@ -0,0 +1,107 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 21 Jan 2021 18:35:22 +1100 +Subject: [PATCH] disk/lvm: Do not overread metadata + +We could reach the end of valid metadata and not realize, leading to +some buffer overreads. Check if we have reached the end and bail. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/disk/lvm.c | 31 +++++++++++++++++++++++++------ + 1 file changed, 25 insertions(+), 6 deletions(-) + +diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c +index 03587e744dc..267be7b9536 100644 +--- a/grub-core/disk/lvm.c ++++ b/grub-core/disk/lvm.c +@@ -314,17 +314,23 @@ error_parsing_metadata: + while (1) + { + grub_ssize_t s; +- while (grub_isspace (*p)) ++ while (grub_isspace (*p) && p < mda_end) + p++; + ++ if (p == mda_end) ++ goto fail4; ++ + if (*p == '}') + break; + + pv = grub_zalloc (sizeof (*pv)); + q = p; +- while (*q != ' ') ++ while (*q != ' ' && q < mda_end) + q++; + ++ if (q == mda_end) ++ goto pvs_fail_noname; ++ + s = q - p; + pv->name = grub_malloc (s + 1); + grub_memcpy (pv->name, p, s); +@@ -367,6 +373,7 @@ error_parsing_metadata: + continue; + pvs_fail: + grub_free (pv->name); ++ pvs_fail_noname: + grub_free (pv); + goto fail4; + } +@@ -388,18 +395,24 @@ error_parsing_metadata: + struct grub_diskfilter_segment *seg; + int is_pvmove; + +- while (grub_isspace (*p)) ++ while (grub_isspace (*p) && p < mda_end) + p++; + ++ if (p == mda_end) ++ goto fail4; ++ + if (*p == '}') + break; + + lv = grub_zalloc (sizeof (*lv)); + + q = p; +- while (*q != ' ') ++ while (*q != ' ' && q < mda_end) + q++; + ++ if (q == mda_end) ++ goto lvs_fail; ++ + s = q - p; + lv->name = grub_strndup (p, s); + if (!lv->name) +@@ -572,9 +585,12 @@ error_parsing_metadata: + if (p == NULL) + goto lvs_segment_fail2; + q = ++p; +- while (*q != '"') ++ while (q < mda_end && *q != '"') + q++; + ++ if (q == mda_end) ++ goto lvs_segment_fail2; ++ + s = q - p; + + stripe->name = grub_malloc (s + 1); +@@ -631,9 +647,12 @@ error_parsing_metadata: + if (p == NULL) + goto lvs_segment_fail2; + q = ++p; +- while (*q != '"') ++ while (q < mda_end && *q != '"') + q++; + ++ if (q == mda_end) ++ goto lvs_segment_fail2; ++ + s = q - p; + + lvname = grub_malloc (s + 1); diff --git a/SOURCES/0458-disk-lvm-Sanitize-rlocn-offset-to-prevent-wild-read.patch b/SOURCES/0458-disk-lvm-Sanitize-rlocn-offset-to-prevent-wild-read.patch new file mode 100644 index 0000000..412873f --- /dev/null +++ b/SOURCES/0458-disk-lvm-Sanitize-rlocn-offset-to-prevent-wild-read.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 22 Jan 2021 14:43:58 +1100 +Subject: [PATCH] disk/lvm: Sanitize rlocn->offset to prevent wild read + +rlocn->offset is read directly from disk and added to the metadatabuf +pointer to create a pointer to a block of metadata. It's a 64-bit +quantity so as long as you don't overflow you can set subsequent +pointers to point anywhere in memory. + +Require that rlocn->offset fits within the metadata buffer size. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/disk/lvm.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c +index 267be7b9536..9eda28d852c 100644 +--- a/grub-core/disk/lvm.c ++++ b/grub-core/disk/lvm.c +@@ -212,6 +212,14 @@ grub_lvm_detect (grub_disk_t disk, + } + + rlocn = mdah->raw_locns; ++ if (grub_le_to_cpu64 (rlocn->offset) >= grub_le_to_cpu64 (mda_size)) ++ { ++#ifdef GRUB_UTIL ++ grub_util_info ("metadata offset is beyond end of metadata area"); ++#endif ++ goto fail2; ++ } ++ + if (grub_le_to_cpu64 (rlocn->offset) + grub_le_to_cpu64 (rlocn->size) > + grub_le_to_cpu64 (mdah->size)) + { diff --git a/SOURCES/0459-disk-lvm-Do-not-allow-a-LV-to-be-it-s-own-segment-s-.patch b/SOURCES/0459-disk-lvm-Do-not-allow-a-LV-to-be-it-s-own-segment-s-.patch new file mode 100644 index 0000000..99e32f2 --- /dev/null +++ b/SOURCES/0459-disk-lvm-Do-not-allow-a-LV-to-be-it-s-own-segment-s-.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 22 Jan 2021 14:42:21 +1100 +Subject: [PATCH] disk/lvm: Do not allow a LV to be it's own segment's node's + LV + +This prevents infinite recursion in the diskfilter verification code. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/disk/lvm.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c +index 9eda28d852c..7e86bb7df4f 100644 +--- a/grub-core/disk/lvm.c ++++ b/grub-core/disk/lvm.c +@@ -840,9 +840,13 @@ error_parsing_metadata: + } + if (lv1->segments[i].nodes[j].pv == NULL) + for (lv2 = vg->lvs; lv2; lv2 = lv2->next) +- if (grub_strcmp (lv2->name, +- lv1->segments[i].nodes[j].name) == 0) +- lv1->segments[i].nodes[j].lv = lv2; ++ { ++ if (lv1 == lv2) ++ continue; ++ if (grub_strcmp (lv2->name, ++ lv1->segments[i].nodes[j].name) == 0) ++ lv1->segments[i].nodes[j].lv = lv2; ++ } + } + + } diff --git a/SOURCES/0460-kern-parser-Fix-a-memory-leak.patch b/SOURCES/0460-kern-parser-Fix-a-memory-leak.patch new file mode 100644 index 0000000..42d42b3 --- /dev/null +++ b/SOURCES/0460-kern-parser-Fix-a-memory-leak.patch @@ -0,0 +1,73 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Wed, 18 Nov 2020 00:59:24 +0000 +Subject: [PATCH] kern/parser: Fix a memory leak + +The getline() function supplied to grub_parser_split_cmdline() returns +a newly allocated buffer and can be called multiple times, but the +returned buffer is never freed. + +Signed-off-by: Chris Coulson +Reviewed-by: Daniel Kiper +--- + grub-core/kern/parser.c | 20 ++++++++++++++++---- + 1 file changed, 16 insertions(+), 4 deletions(-) + +diff --git a/grub-core/kern/parser.c b/grub-core/kern/parser.c +index d1cf061ad68..39e4df65b86 100644 +--- a/grub-core/kern/parser.c ++++ b/grub-core/kern/parser.c +@@ -140,6 +140,7 @@ grub_parser_split_cmdline (const char *cmdline, + char buffer[1024]; + char *bp = buffer; + char *rd = (char *) cmdline; ++ char *rp = rd; + char varname[200]; + char *vp = varname; + char *args; +@@ -149,10 +150,18 @@ grub_parser_split_cmdline (const char *cmdline, + *argv = NULL; + do + { +- if (!rd || !*rd) ++ if (rp == NULL || *rp == '\0') + { ++ if (rd != cmdline) ++ { ++ grub_free (rd); ++ rd = rp = NULL; ++ } + if (getline) +- getline (&rd, 1, getline_data); ++ { ++ getline (&rd, 1, getline_data); ++ rp = rd; ++ } + else + break; + } +@@ -160,12 +169,12 @@ grub_parser_split_cmdline (const char *cmdline, + if (!rd) + break; + +- for (; *rd; rd++) ++ for (; *rp != '\0'; rp++) + { + grub_parser_state_t newstate; + char use; + +- newstate = grub_parser_cmdline_state (state, *rd, &use); ++ newstate = grub_parser_cmdline_state (state, *rp, &use); + + /* If a variable was being processed and this character does + not describe the variable anymore, write the variable to +@@ -198,6 +207,9 @@ grub_parser_split_cmdline (const char *cmdline, + } + while (state != GRUB_PARSER_STATE_TEXT && !check_varstate (state)); + ++ if (rd != cmdline) ++ grub_free (rd); ++ + /* A special case for when the last character was part of a + variable. */ + add_var (varname, &bp, &vp, state, GRUB_PARSER_STATE_TEXT); diff --git a/SOURCES/0461-kern-parser-Introduce-process_char-helper.patch b/SOURCES/0461-kern-parser-Introduce-process_char-helper.patch new file mode 100644 index 0000000..c67dc9e --- /dev/null +++ b/SOURCES/0461-kern-parser-Introduce-process_char-helper.patch @@ -0,0 +1,116 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Tue, 5 Jan 2021 22:17:28 +0000 +Subject: [PATCH] kern/parser: Introduce process_char() helper + +grub_parser_split_cmdline() iterates over each command line character. +In order to add error checking and to simplify the subsequent error +handling, split the character processing in to a separate function. + +Signed-off-by: Chris Coulson +Reviewed-by: Daniel Kiper +--- + grub-core/kern/parser.c | 74 ++++++++++++++++++++++++++++++------------------- + 1 file changed, 46 insertions(+), 28 deletions(-) + +diff --git a/grub-core/kern/parser.c b/grub-core/kern/parser.c +index 39e4df65b86..0d3582bd874 100644 +--- a/grub-core/kern/parser.c ++++ b/grub-core/kern/parser.c +@@ -1,7 +1,7 @@ + /* parser.c - the part of the parser that can return partial tokens */ + /* + * GRUB -- GRand Unified Bootloader +- * Copyright (C) 2005,2007,2009 Free Software Foundation, Inc. ++ * Copyright (C) 2005,2007,2009,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 +@@ -129,6 +129,46 @@ add_var (char *varname, char **bp, char **vp, + *((*bp)++) = *val; + } + ++static grub_err_t ++process_char (char c, char *buffer, char **bp, char *varname, char **vp, ++ grub_parser_state_t state, int *argc, ++ grub_parser_state_t *newstate) ++{ ++ char use; ++ ++ *newstate = grub_parser_cmdline_state (state, c, &use); ++ ++ /* ++ * If a variable was being processed and this character does ++ * not describe the variable anymore, write the variable to ++ * the buffer. ++ */ ++ add_var (varname, bp, vp, state, *newstate); ++ ++ if (check_varstate (*newstate)) ++ { ++ if (use) ++ *((*vp)++) = use; ++ } ++ else if (*newstate == GRUB_PARSER_STATE_TEXT && ++ state != GRUB_PARSER_STATE_ESC && grub_isspace (use)) ++ { ++ /* ++ * Don't add more than one argument if multiple ++ * spaces are used. ++ */ ++ if (*bp != buffer && *((*bp) - 1) != '\0') ++ { ++ *((*bp)++) = '\0'; ++ (*argc)++; ++ } ++ } ++ else if (use) ++ *((*bp)++) = use; ++ ++ return GRUB_ERR_NONE; ++} ++ + grub_err_t + grub_parser_split_cmdline (const char *cmdline, + grub_reader_getline_t getline, void *getline_data, +@@ -172,35 +212,13 @@ grub_parser_split_cmdline (const char *cmdline, + for (; *rp != '\0'; rp++) + { + grub_parser_state_t newstate; +- char use; + +- newstate = grub_parser_cmdline_state (state, *rp, &use); +- +- /* If a variable was being processed and this character does +- not describe the variable anymore, write the variable to +- the buffer. */ +- add_var (varname, &bp, &vp, state, newstate); +- +- if (check_varstate (newstate)) +- { +- if (use) +- *(vp++) = use; +- } +- else ++ if (process_char (*rp, buffer, &bp, varname, &vp, state, argc, ++ &newstate) != GRUB_ERR_NONE) + { +- if (newstate == GRUB_PARSER_STATE_TEXT +- && state != GRUB_PARSER_STATE_ESC && grub_isspace (use)) +- { +- /* Don't add more than one argument if multiple +- spaces are used. */ +- if (bp != buffer && *(bp - 1)) +- { +- *(bp++) = '\0'; +- (*argc)++; +- } +- } +- else if (use) +- *(bp++) = use; ++ if (rd != cmdline) ++ grub_free (rd); ++ return grub_errno; + } + state = newstate; + } diff --git a/SOURCES/0462-kern-parser-Introduce-terminate_arg-helper.patch b/SOURCES/0462-kern-parser-Introduce-terminate_arg-helper.patch new file mode 100644 index 0000000..4192ec5 --- /dev/null +++ b/SOURCES/0462-kern-parser-Introduce-terminate_arg-helper.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Thu, 7 Jan 2021 19:53:55 +0000 +Subject: [PATCH] kern/parser: Introduce terminate_arg() helper + +process_char() and grub_parser_split_cmdline() use similar code for +terminating the most recent argument. Add a helper function for this. + +Signed-off-by: Chris Coulson +Reviewed-by: Daniel Kiper +--- + grub-core/kern/parser.c | 23 +++++++++++++---------- + 1 file changed, 13 insertions(+), 10 deletions(-) + +diff --git a/grub-core/kern/parser.c b/grub-core/kern/parser.c +index 0d3582bd874..572c67089f3 100644 +--- a/grub-core/kern/parser.c ++++ b/grub-core/kern/parser.c +@@ -129,6 +129,16 @@ add_var (char *varname, char **bp, char **vp, + *((*bp)++) = *val; + } + ++static void ++terminate_arg (char *buffer, char **bp, int *argc) ++{ ++ if (*bp != buffer && *((*bp) - 1) != '\0') ++ { ++ *((*bp)++) = '\0'; ++ (*argc)++; ++ } ++} ++ + static grub_err_t + process_char (char c, char *buffer, char **bp, char *varname, char **vp, + grub_parser_state_t state, int *argc, +@@ -157,11 +167,7 @@ process_char (char c, char *buffer, char **bp, char *varname, char **vp, + * Don't add more than one argument if multiple + * spaces are used. + */ +- if (*bp != buffer && *((*bp) - 1) != '\0') +- { +- *((*bp)++) = '\0'; +- (*argc)++; +- } ++ terminate_arg (buffer, bp, argc); + } + else if (use) + *((*bp)++) = use; +@@ -232,11 +238,8 @@ grub_parser_split_cmdline (const char *cmdline, + variable. */ + add_var (varname, &bp, &vp, state, GRUB_PARSER_STATE_TEXT); + +- if (bp != buffer && *(bp - 1)) +- { +- *(bp++) = '\0'; +- (*argc)++; +- } ++ /* Ensure that the last argument is terminated. */ ++ terminate_arg (buffer, &bp, argc); + + /* If there are no args, then we're done. */ + if (!*argc) diff --git a/SOURCES/0463-kern-parser-Refactor-grub_parser_split_cmdline-clean.patch b/SOURCES/0463-kern-parser-Refactor-grub_parser_split_cmdline-clean.patch new file mode 100644 index 0000000..c6a0c49 --- /dev/null +++ b/SOURCES/0463-kern-parser-Refactor-grub_parser_split_cmdline-clean.patch @@ -0,0 +1,88 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Wed, 6 Jan 2021 13:54:26 +0000 +Subject: [PATCH] kern/parser: Refactor grub_parser_split_cmdline() cleanup + +Introduce a common function epilogue used for cleaning up on all +return paths, which will simplify additional error handling to be +introduced in a subsequent commit. + +Signed-off-by: Chris Coulson +Reviewed-by: Daniel Kiper +--- + grub-core/kern/parser.c | 35 ++++++++++++++++++++--------------- + 1 file changed, 20 insertions(+), 15 deletions(-) + +diff --git a/grub-core/kern/parser.c b/grub-core/kern/parser.c +index 572c67089f3..e010eaa1fa1 100644 +--- a/grub-core/kern/parser.c ++++ b/grub-core/kern/parser.c +@@ -221,19 +221,13 @@ grub_parser_split_cmdline (const char *cmdline, + + if (process_char (*rp, buffer, &bp, varname, &vp, state, argc, + &newstate) != GRUB_ERR_NONE) +- { +- if (rd != cmdline) +- grub_free (rd); +- return grub_errno; +- } ++ goto fail; ++ + state = newstate; + } + } + while (state != GRUB_PARSER_STATE_TEXT && !check_varstate (state)); + +- if (rd != cmdline) +- grub_free (rd); +- + /* A special case for when the last character was part of a + variable. */ + add_var (varname, &bp, &vp, state, GRUB_PARSER_STATE_TEXT); +@@ -243,20 +237,20 @@ grub_parser_split_cmdline (const char *cmdline, + + /* If there are no args, then we're done. */ + if (!*argc) +- return 0; ++ { ++ grub_errno = GRUB_ERR_NONE; ++ goto out; ++ } + + /* Reserve memory for the return values. */ + args = grub_malloc (bp - buffer); + if (!args) +- return grub_errno; ++ goto fail; + grub_memcpy (args, buffer, bp - buffer); + + *argv = grub_calloc (*argc + 1, sizeof (char *)); + if (!*argv) +- { +- grub_free (args); +- return grub_errno; +- } ++ goto fail; + + /* The arguments are separated with 0's, setup argv so it points to + the right values. */ +@@ -269,7 +263,18 @@ grub_parser_split_cmdline (const char *cmdline, + bp++; + } + +- return 0; ++ grub_errno = GRUB_ERR_NONE; ++ ++ out: ++ if (rd != cmdline) ++ grub_free (rd); ++ ++ return grub_errno; ++ ++ fail: ++ grub_free (*argv); ++ grub_free (args); ++ goto out; + } + + /* Helper for grub_parser_execute. */ diff --git a/SOURCES/0464-kern-buffer-Add-variable-sized-heap-buffer.patch b/SOURCES/0464-kern-buffer-Add-variable-sized-heap-buffer.patch new file mode 100644 index 0000000..0c46876 --- /dev/null +++ b/SOURCES/0464-kern-buffer-Add-variable-sized-heap-buffer.patch @@ -0,0 +1,304 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Thu, 7 Jan 2021 15:15:43 +0000 +Subject: [PATCH] kern/buffer: Add variable sized heap buffer + +Add a new variable sized heap buffer type (grub_buffer_t) with simple +operations for appending data, accessing the data and maintaining +a read cursor. + +Signed-off-by: Chris Coulson +Reviewed-by: Daniel Kiper +--- + grub-core/Makefile.core.def | 1 + + grub-core/kern/buffer.c | 117 +++++++++++++++++++++++++++++++++++ + include/grub/buffer.h | 144 ++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 262 insertions(+) + create mode 100644 grub-core/kern/buffer.c + create mode 100644 include/grub/buffer.h + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 02fbecd4b81..612df2e9c40 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -112,6 +112,7 @@ kernel = { + arm_efi_startup = kern/arm/efi/startup.S; + arm64_efi_startup = kern/arm64/efi/startup.S; + ++ common = kern/buffer.c; + common = kern/command.c; + common = kern/corecmd.c; + common = kern/device.c; +diff --git a/grub-core/kern/buffer.c b/grub-core/kern/buffer.c +new file mode 100644 +index 00000000000..9f5f8b86705 +--- /dev/null ++++ b/grub-core/kern/buffer.c +@@ -0,0 +1,117 @@ ++/* ++ * 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 . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++grub_buffer_t ++grub_buffer_new (grub_size_t sz) ++{ ++ struct grub_buffer *ret; ++ ++ ret = (struct grub_buffer *) grub_malloc (sizeof (*ret)); ++ if (ret == NULL) ++ return NULL; ++ ++ ret->data = (grub_uint8_t *) grub_malloc (sz); ++ if (ret->data == NULL) ++ { ++ grub_free (ret); ++ return NULL; ++ } ++ ++ ret->sz = sz; ++ ret->pos = 0; ++ ret->used = 0; ++ ++ return ret; ++} ++ ++void ++grub_buffer_free (grub_buffer_t buf) ++{ ++ grub_free (buf->data); ++ grub_free (buf); ++} ++ ++grub_err_t ++grub_buffer_ensure_space (grub_buffer_t buf, grub_size_t req) ++{ ++ grub_uint8_t *d; ++ grub_size_t newsz = 1; ++ ++ /* Is the current buffer size adequate? */ ++ if (buf->sz >= req) ++ return GRUB_ERR_NONE; ++ ++ /* Find the smallest power-of-2 size that satisfies the request. */ ++ while (newsz < req) ++ { ++ if (newsz == 0) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("requested buffer size is too large")); ++ newsz <<= 1; ++ } ++ ++ d = (grub_uint8_t *) grub_realloc (buf->data, newsz); ++ if (d == NULL) ++ return grub_errno; ++ ++ buf->data = d; ++ buf->sz = newsz; ++ ++ return GRUB_ERR_NONE; ++} ++ ++void * ++grub_buffer_take_data (grub_buffer_t buf) ++{ ++ void *data = buf->data; ++ ++ buf->data = NULL; ++ buf->sz = buf->pos = buf->used = 0; ++ ++ return data; ++} ++ ++void ++grub_buffer_reset (grub_buffer_t buf) ++{ ++ buf->pos = buf->used = 0; ++} ++ ++grub_err_t ++grub_buffer_advance_read_pos (grub_buffer_t buf, grub_size_t n) ++{ ++ grub_size_t newpos; ++ ++ if (grub_add (buf->pos, n, &newpos)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); ++ ++ if (newpos > buf->used) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("new read is position beyond the end of the written data")); ++ ++ buf->pos = newpos; ++ ++ return GRUB_ERR_NONE; ++} +diff --git a/include/grub/buffer.h b/include/grub/buffer.h +new file mode 100644 +index 00000000000..f4b10cf2810 +--- /dev/null ++++ b/include/grub/buffer.h +@@ -0,0 +1,144 @@ ++/* ++ * 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 . ++ */ ++ ++#ifndef GRUB_BUFFER_H ++#define GRUB_BUFFER_H 1 ++ ++#include ++#include ++#include ++#include ++#include ++ ++struct grub_buffer ++{ ++ grub_uint8_t *data; ++ grub_size_t sz; ++ grub_size_t pos; ++ grub_size_t used; ++}; ++ ++/* ++ * grub_buffer_t represents a simple variable sized byte buffer with ++ * read and write cursors. It currently only implements ++ * functionality required by the only user in GRUB (append byte[s], ++ * peeking data at a specified position and updating the read cursor. ++ * Some things that this doesn't do yet are: ++ * - Reading a portion of the buffer by copying data from the current ++ * read position in to a caller supplied destination buffer and then ++ * automatically updating the read cursor. ++ * - Dropping the read part at the start of the buffer when an append ++ * requires more space. ++ */ ++typedef struct grub_buffer *grub_buffer_t; ++ ++/* Allocate a new buffer with the specified initial size. */ ++extern grub_buffer_t grub_buffer_new (grub_size_t sz); ++ ++/* Free the buffer and its resources. */ ++extern void grub_buffer_free (grub_buffer_t buf); ++ ++/* Return the number of unread bytes in this buffer. */ ++static inline grub_size_t ++grub_buffer_get_unread_bytes (grub_buffer_t buf) ++{ ++ return buf->used - buf->pos; ++} ++ ++/* ++ * Ensure that the buffer size is at least the requested ++ * number of bytes. ++ */ ++extern grub_err_t grub_buffer_ensure_space (grub_buffer_t buf, grub_size_t req); ++ ++/* ++ * Append the specified number of bytes from the supplied ++ * data to the buffer. ++ */ ++static inline grub_err_t ++grub_buffer_append_data (grub_buffer_t buf, const void *data, grub_size_t len) ++{ ++ grub_size_t req; ++ ++ if (grub_add (buf->used, len, &req)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); ++ ++ if (grub_buffer_ensure_space (buf, req) != GRUB_ERR_NONE) ++ return grub_errno; ++ ++ grub_memcpy (&buf->data[buf->used], data, len); ++ buf->used = req; ++ ++ return GRUB_ERR_NONE; ++} ++ ++/* Append the supplied character to the buffer. */ ++static inline grub_err_t ++grub_buffer_append_char (grub_buffer_t buf, char c) ++{ ++ return grub_buffer_append_data (buf, &c, 1); ++} ++ ++/* ++ * Forget and return the underlying data buffer. The caller ++ * becomes the owner of this buffer, and must free it when it ++ * is no longer required. ++ */ ++extern void *grub_buffer_take_data (grub_buffer_t buf); ++ ++/* Reset this buffer. Note that this does not deallocate any resources. */ ++void grub_buffer_reset (grub_buffer_t buf); ++ ++/* ++ * Return a pointer to the underlying data buffer at the specified ++ * offset from the current read position. Note that this pointer may ++ * become invalid if the buffer is mutated further. ++ */ ++static inline void * ++grub_buffer_peek_data_at (grub_buffer_t buf, grub_size_t off) ++{ ++ if (grub_add (buf->pos, off, &off)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected.")); ++ return NULL; ++ } ++ ++ if (off >= buf->used) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("peek out of range")); ++ return NULL; ++ } ++ ++ return &buf->data[off]; ++} ++ ++/* ++ * Return a pointer to the underlying data buffer at the current ++ * read position. Note that this pointer may become invalid if the ++ * buffer is mutated further. ++ */ ++static inline void * ++grub_buffer_peek_data (grub_buffer_t buf) ++{ ++ return grub_buffer_peek_data_at (buf, 0); ++} ++ ++/* Advance the read position by the specified number of bytes. */ ++extern grub_err_t grub_buffer_advance_read_pos (grub_buffer_t buf, grub_size_t n); ++ ++#endif /* GRUB_BUFFER_H */ diff --git a/SOURCES/0465-kern-parser-Fix-a-stack-buffer-overflow.patch b/SOURCES/0465-kern-parser-Fix-a-stack-buffer-overflow.patch new file mode 100644 index 0000000..7a30d03 --- /dev/null +++ b/SOURCES/0465-kern-parser-Fix-a-stack-buffer-overflow.patch @@ -0,0 +1,244 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Thu, 7 Jan 2021 19:21:03 +0000 +Subject: [PATCH] kern/parser: Fix a stack buffer overflow + +grub_parser_split_cmdline() expands variable names present in the supplied +command line in to their corresponding variable contents and uses a 1 kiB +stack buffer for temporary storage without sufficient bounds checking. If +the function is called with a command line that references a variable with +a sufficiently large payload, it is possible to overflow the stack +buffer via tab completion, corrupt the stack frame and potentially +control execution. + +Fixes: CVE-2020-27749 + +Reported-by: Chris Coulson +Signed-off-by: Chris Coulson +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/kern/parser.c | 110 +++++++++++++++++++++++++++++------------------- + 1 file changed, 67 insertions(+), 43 deletions(-) + +diff --git a/grub-core/kern/parser.c b/grub-core/kern/parser.c +index e010eaa1fa1..6ab7aa427cc 100644 +--- a/grub-core/kern/parser.c ++++ b/grub-core/kern/parser.c +@@ -18,6 +18,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -107,8 +108,8 @@ check_varstate (grub_parser_state_t s) + } + + +-static void +-add_var (char *varname, char **bp, char **vp, ++static grub_err_t ++add_var (grub_buffer_t varname, grub_buffer_t buf, + grub_parser_state_t state, grub_parser_state_t newstate) + { + const char *val; +@@ -116,31 +117,41 @@ add_var (char *varname, char **bp, char **vp, + /* Check if a variable was being read in and the end of the name + was reached. */ + if (!(check_varstate (state) && !check_varstate (newstate))) +- return; ++ return GRUB_ERR_NONE; + +- *((*vp)++) = '\0'; +- val = grub_env_get (varname); +- *vp = varname; ++ if (grub_buffer_append_char (varname, '\0') != GRUB_ERR_NONE) ++ return grub_errno; ++ ++ val = grub_env_get ((const char *) grub_buffer_peek_data (varname)); ++ grub_buffer_reset (varname); + if (!val) +- return; ++ return GRUB_ERR_NONE; + + /* Insert the contents of the variable in the buffer. */ +- for (; *val; val++) +- *((*bp)++) = *val; ++ return grub_buffer_append_data (buf, val, grub_strlen (val)); + } + +-static void +-terminate_arg (char *buffer, char **bp, int *argc) ++static grub_err_t ++terminate_arg (grub_buffer_t buffer, int *argc) + { +- if (*bp != buffer && *((*bp) - 1) != '\0') +- { +- *((*bp)++) = '\0'; +- (*argc)++; +- } ++ grub_size_t unread = grub_buffer_get_unread_bytes (buffer); ++ ++ if (unread == 0) ++ return GRUB_ERR_NONE; ++ ++ if (*(const char *) grub_buffer_peek_data_at (buffer, unread - 1) == '\0') ++ return GRUB_ERR_NONE; ++ ++ if (grub_buffer_append_char (buffer, '\0') != GRUB_ERR_NONE) ++ return grub_errno; ++ ++ (*argc)++; ++ ++ return GRUB_ERR_NONE; + } + + static grub_err_t +-process_char (char c, char *buffer, char **bp, char *varname, char **vp, ++process_char (char c, grub_buffer_t buffer, grub_buffer_t varname, + grub_parser_state_t state, int *argc, + grub_parser_state_t *newstate) + { +@@ -153,12 +164,13 @@ process_char (char c, char *buffer, char **bp, char *varname, char **vp, + * not describe the variable anymore, write the variable to + * the buffer. + */ +- add_var (varname, bp, vp, state, *newstate); ++ if (add_var (varname, buffer, state, *newstate) != GRUB_ERR_NONE) ++ return grub_errno; + + if (check_varstate (*newstate)) + { + if (use) +- *((*vp)++) = use; ++ return grub_buffer_append_char (varname, use); + } + else if (*newstate == GRUB_PARSER_STATE_TEXT && + state != GRUB_PARSER_STATE_ESC && grub_isspace (use)) +@@ -167,10 +179,10 @@ process_char (char c, char *buffer, char **bp, char *varname, char **vp, + * Don't add more than one argument if multiple + * spaces are used. + */ +- terminate_arg (buffer, bp, argc); ++ return terminate_arg (buffer, argc); + } + else if (use) +- *((*bp)++) = use; ++ return grub_buffer_append_char (buffer, use); + + return GRUB_ERR_NONE; + } +@@ -181,19 +193,22 @@ grub_parser_split_cmdline (const char *cmdline, + int *argc, char ***argv) + { + grub_parser_state_t state = GRUB_PARSER_STATE_TEXT; +- /* XXX: Fixed size buffer, perhaps this buffer should be dynamically +- allocated. */ +- char buffer[1024]; +- char *bp = buffer; ++ grub_buffer_t buffer, varname; + char *rd = (char *) cmdline; + char *rp = rd; +- char varname[200]; +- char *vp = varname; +- char *args; + int i; + + *argc = 0; + *argv = NULL; ++ ++ buffer = grub_buffer_new (1024); ++ if (buffer == NULL) ++ return grub_errno; ++ ++ varname = grub_buffer_new (200); ++ if (varname == NULL) ++ goto fail; ++ + do + { + if (rp == NULL || *rp == '\0') +@@ -219,7 +234,7 @@ grub_parser_split_cmdline (const char *cmdline, + { + grub_parser_state_t newstate; + +- if (process_char (*rp, buffer, &bp, varname, &vp, state, argc, ++ if (process_char (*rp, buffer, varname, state, argc, + &newstate) != GRUB_ERR_NONE) + goto fail; + +@@ -230,10 +245,12 @@ grub_parser_split_cmdline (const char *cmdline, + + /* A special case for when the last character was part of a + variable. */ +- add_var (varname, &bp, &vp, state, GRUB_PARSER_STATE_TEXT); ++ if (add_var (varname, buffer, state, GRUB_PARSER_STATE_TEXT) != GRUB_ERR_NONE) ++ goto fail; + + /* Ensure that the last argument is terminated. */ +- terminate_arg (buffer, &bp, argc); ++ if (terminate_arg (buffer, argc) != GRUB_ERR_NONE) ++ goto fail; + + /* If there are no args, then we're done. */ + if (!*argc) +@@ -242,38 +259,45 @@ grub_parser_split_cmdline (const char *cmdline, + goto out; + } + +- /* Reserve memory for the return values. */ +- args = grub_malloc (bp - buffer); +- if (!args) +- goto fail; +- grub_memcpy (args, buffer, bp - buffer); +- + *argv = grub_calloc (*argc + 1, sizeof (char *)); + if (!*argv) + goto fail; + + /* The arguments are separated with 0's, setup argv so it points to + the right values. */ +- bp = args; + for (i = 0; i < *argc; i++) + { +- (*argv)[i] = bp; +- while (*bp) +- bp++; +- bp++; ++ char *arg; ++ ++ if (i > 0) ++ { ++ if (grub_buffer_advance_read_pos (buffer, 1) != GRUB_ERR_NONE) ++ goto fail; ++ } ++ ++ arg = (char *) grub_buffer_peek_data (buffer); ++ if (arg == NULL || ++ grub_buffer_advance_read_pos (buffer, grub_strlen (arg)) != GRUB_ERR_NONE) ++ goto fail; ++ ++ (*argv)[i] = arg; + } + ++ /* Keep memory for the return values. */ ++ grub_buffer_take_data (buffer); ++ + grub_errno = GRUB_ERR_NONE; + + out: + if (rd != cmdline) + grub_free (rd); ++ grub_buffer_free (buffer); ++ grub_buffer_free (varname); + + return grub_errno; + + fail: + grub_free (*argv); +- grub_free (args); + goto out; + } + diff --git a/SOURCES/0466-kern-efi-Add-initial-stack-protector-implementation.patch b/SOURCES/0466-kern-efi-Add-initial-stack-protector-implementation.patch new file mode 100644 index 0000000..8da130b --- /dev/null +++ b/SOURCES/0466-kern-efi-Add-initial-stack-protector-implementation.patch @@ -0,0 +1,298 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Fri, 19 Feb 2021 13:53:45 +0100 +Subject: [PATCH] kern/efi: Add initial stack protector implementation + +It works only on UEFI platforms but can be quite easily extended to +others architectures and platforms if needed. + +Signed-off-by: Chris Coulson +Signed-off-by: Daniel Kiper +Reviewed-by: Marco A Benatto +Reviewed-by: Javier Martinez Canillas +--- + configure.ac | 44 ++++++++++++++++++++++++++++++---- + grub-core/kern/efi/init.c | 54 ++++++++++++++++++++++++++++++++++++++++++ + include/grub/efi/api.h | 19 +++++++++++++++ + include/grub/stack_protector.h | 30 +++++++++++++++++++++++ + acinclude.m4 | 38 +++++++++++++++++++++++++++-- + grub-core/Makefile.am | 1 + + 6 files changed, 179 insertions(+), 7 deletions(-) + create mode 100644 include/grub/stack_protector.h + +diff --git a/configure.ac b/configure.ac +index 0059b938a3a..f59a7b86c51 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1330,12 +1330,41 @@ fi] + + CFLAGS="$TARGET_CFLAGS" + +-# Smashing stack protector. ++# Stack smashing protector. + grub_CHECK_STACK_PROTECTOR +-# Need that, because some distributions ship compilers that include +-# `-fstack-protector' in the default specs. +-if test "x$ssp_possible" = xyes; then +- TARGET_CFLAGS="$TARGET_CFLAGS -fno-stack-protector" ++AC_ARG_ENABLE([stack-protector], ++ AS_HELP_STRING([--enable-stack-protector], ++ [enable the stack protector]), ++ [], ++ [enable_stack_protector=no]) ++if test "x$enable_stack_protector" = xno; then ++ if test "x$ssp_possible" = xyes; then ++ # Need that, because some distributions ship compilers that include ++ # `-fstack-protector' in the default specs. ++ TARGET_CFLAGS="$TARGET_CFLAGS -fno-stack-protector" ++ fi ++elif test "x$platform" != xefi; then ++ AC_MSG_ERROR([--enable-stack-protector is only supported on EFI platforms]) ++elif test "x$ssp_global_possible" != xyes; then ++ AC_MSG_ERROR([--enable-stack-protector is not supported (compiler doesn't support -mstack-protector-guard=global)]) ++else ++ TARGET_CFLAGS="$TARGET_CFLAGS -mstack-protector-guard=global" ++ if test "x$enable_stack_protector" = xyes; then ++ if test "x$ssp_possible" != xyes; then ++ AC_MSG_ERROR([--enable-stack-protector is not supported (compiler doesn't support -fstack-protector)]) ++ fi ++ TARGET_CFLAGS="$TARGET_CFLAGS -fstack-protector" ++ elif test "x$enable_stack_protector" = xstrong; then ++ if test "x$ssp_strong_possible" != xyes; then ++ AC_MSG_ERROR([--enable-stack-protector=strong is not supported (compiler doesn't support -fstack-protector-strong)]) ++ fi ++ TARGET_CFLAGS="$TARGET_CFLAGS -fstack-protector-strong" ++ else ++ # Note, -fstack-protector-all requires that the protector is disabled for ++ # functions that appear in the call stack when the canary is initialized. ++ AC_MSG_ERROR([invalid value $enable_stack_protector for --enable-stack-protector]) ++ fi ++ TARGET_CPPFLAGS="$TARGET_CPPFLAGS -DGRUB_STACK_PROTECTOR=1" + fi + + CFLAGS="$TARGET_CFLAGS" +@@ -2247,5 +2276,10 @@ echo "Without liblzma (no support for XZ-compressed mips images) ($liblzma_excus + else + echo "With liblzma from $LIBLZMA (support for XZ-compressed mips images)" + fi ++if test "x$enable_stack_protector" != xno; then ++echo "With stack smashing protector: Yes" ++else ++echo "With stack smashing protector: No" ++fi + echo "*******************************************************" + ] +diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c +index 97bf36906a4..501608f743e 100644 +--- a/grub-core/kern/efi/init.c ++++ b/grub-core/kern/efi/init.c +@@ -28,6 +28,58 @@ + #include + #include + #include ++#include ++ ++#ifdef GRUB_STACK_PROTECTOR ++ ++static grub_efi_guid_t rng_protocol_guid = GRUB_EFI_RNG_PROTOCOL_GUID; ++ ++/* ++ * Don't put this on grub_efi_init()'s local stack to avoid it ++ * getting a stack check. ++ */ ++static grub_efi_uint8_t stack_chk_guard_buf[32]; ++ ++grub_addr_t __stack_chk_guard; ++ ++void __attribute__ ((noreturn)) ++__stack_chk_fail (void) ++{ ++ /* ++ * Assume it's not safe to call into EFI Boot Services. Sorry, that ++ * means no console message here. ++ */ ++ do ++ { ++ /* Do not optimize out the loop. */ ++ asm volatile (""); ++ } ++ while (1); ++} ++ ++static void ++stack_protector_init (void) ++{ ++ grub_efi_rng_protocol_t *rng; ++ ++ /* Set up the stack canary. Make errors here non-fatal for now. */ ++ rng = grub_efi_locate_protocol (&rng_protocol_guid, NULL); ++ if (rng != NULL) ++ { ++ grub_efi_status_t status; ++ ++ status = efi_call_4 (rng->get_rng, rng, NULL, sizeof (stack_chk_guard_buf), ++ stack_chk_guard_buf); ++ if (status == GRUB_EFI_SUCCESS) ++ grub_memcpy (&__stack_chk_guard, stack_chk_guard_buf, sizeof (__stack_chk_guard)); ++ } ++} ++#else ++static void ++stack_protector_init (void) ++{ ++} ++#endif + + grub_addr_t grub_modbase; + +@@ -92,6 +144,8 @@ grub_efi_init (void) + messages. */ + grub_console_init (); + ++ stack_protector_init (); ++ + /* Initialize the memory management system. */ + grub_efi_mm_init (); + +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index a092fddb629..37e7b162874 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -344,6 +344,11 @@ + { 0x89, 0x29, 0x48, 0xbc, 0xd9, 0x0a, 0xd3, 0x1a } \ + } + ++#define GRUB_EFI_RNG_PROTOCOL_GUID \ ++ { 0x3152bca5, 0xeade, 0x433d, \ ++ { 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44 } \ ++ } ++ + struct grub_efi_sal_system_table + { + grub_uint32_t signature; +@@ -2067,6 +2072,20 @@ struct grub_efi_ip6_config_manual_address { + }; + typedef struct grub_efi_ip6_config_manual_address grub_efi_ip6_config_manual_address_t; + ++typedef grub_efi_guid_t grub_efi_rng_algorithm_t; ++ ++struct grub_efi_rng_protocol ++{ ++ grub_efi_status_t (*get_info) (struct grub_efi_rng_protocol *this, ++ grub_efi_uintn_t *rng_algorithm_list_size, ++ grub_efi_rng_algorithm_t *rng_algorithm_list); ++ grub_efi_status_t (*get_rng) (struct grub_efi_rng_protocol *this, ++ grub_efi_rng_algorithm_t *rng_algorithm, ++ grub_efi_uintn_t rng_value_length, ++ grub_efi_uint8_t *rng_value); ++}; ++typedef struct grub_efi_rng_protocol grub_efi_rng_protocol_t; ++ + #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \ + || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) + +diff --git a/include/grub/stack_protector.h b/include/grub/stack_protector.h +new file mode 100644 +index 00000000000..c88dc00b5f9 +--- /dev/null ++++ b/include/grub/stack_protector.h +@@ -0,0 +1,30 @@ ++/* ++ * 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 . ++ */ ++ ++#ifndef GRUB_STACK_PROTECTOR_H ++#define GRUB_STACK_PROTECTOR_H 1 ++ ++#include ++#include ++ ++#ifdef GRUB_STACK_PROTECTOR ++extern grub_addr_t EXPORT_VAR (__stack_chk_guard); ++extern void __attribute__ ((noreturn)) EXPORT_FUNC (__stack_chk_fail) (void); ++#endif ++ ++#endif /* GRUB_STACK_PROTECTOR_H */ +diff --git a/acinclude.m4 b/acinclude.m4 +index 242e829ff23..21238fcfd03 100644 +--- a/acinclude.m4 ++++ b/acinclude.m4 +@@ -324,9 +324,9 @@ fi + ]) + + +-dnl Check if the C compiler supports `-fstack-protector'. ++dnl Check if the C compiler supports the stack protector + AC_DEFUN([grub_CHECK_STACK_PROTECTOR],[ +-[# Smashing stack protector. ++[# Stack smashing protector. + ssp_possible=yes] + AC_MSG_CHECKING([whether `$CC' accepts `-fstack-protector']) + # Is this a reliable test case? +@@ -343,6 +343,40 @@ else + ssp_possible=no] + AC_MSG_RESULT([no]) + [fi] ++[# Strong stack smashing protector. ++ssp_strong_possible=yes] ++AC_MSG_CHECKING([whether `$CC' accepts `-fstack-protector-strong']) ++# Is this a reliable test case? ++AC_LANG_CONFTEST([AC_LANG_SOURCE([[ ++void foo (void) { volatile char a[8]; a[3]; } ++]])]) ++[# `$CC -c -o ...' might not be portable. But, oh, well... Is calling ++# `ac_compile' like this correct, after all? ++if eval "$ac_compile -S -fstack-protector-strong -o conftest.s" 2> /dev/null; then] ++ AC_MSG_RESULT([yes]) ++ [# Should we clear up other files as well, having called `AC_LANG_CONFTEST'? ++ rm -f conftest.s ++else ++ ssp_strong_possible=no] ++ AC_MSG_RESULT([no]) ++[fi] ++[# Global stack smashing protector. ++ssp_global_possible=yes] ++AC_MSG_CHECKING([whether `$CC' accepts `-mstack-protector-guard=global']) ++# Is this a reliable test case? ++AC_LANG_CONFTEST([AC_LANG_SOURCE([[ ++void foo (void) { volatile char a[8]; a[3]; } ++]])]) ++[# `$CC -c -o ...' might not be portable. But, oh, well... Is calling ++# `ac_compile' like this correct, after all? ++if eval "$ac_compile -S -fstack-protector -mstack-protector-guard=global -o conftest.s" 2> /dev/null; then] ++ AC_MSG_RESULT([yes]) ++ [# Should we clear up other files as well, having called `AC_LANG_CONFTEST'? ++ rm -f conftest.s ++else ++ ssp_global_possible=no] ++ AC_MSG_RESULT([no]) ++[fi] + ]) + + dnl Check if the C compiler supports `-mstack-arg-probe' (Cygwin). +diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am +index a6f1b0dcd06..308ad8850c9 100644 +--- a/grub-core/Makefile.am ++++ b/grub-core/Makefile.am +@@ -92,6 +92,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/stack_protector.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/term.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/time.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/mm_private.h diff --git a/SOURCES/0467-util-mkimage-Remove-unused-code-to-add-BSS-section.patch b/SOURCES/0467-util-mkimage-Remove-unused-code-to-add-BSS-section.patch new file mode 100644 index 0000000..6447426 --- /dev/null +++ b/SOURCES/0467-util-mkimage-Remove-unused-code-to-add-BSS-section.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Thu, 11 Feb 2021 17:06:49 +0100 +Subject: [PATCH] util/mkimage: Remove unused code to add BSS section + +The code is compiled out so there is no reason to keep it. + +Additionally, don't set bss_size field since we do not add a BSS section. + +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + util/mkimage.c | 17 ----------------- + 1 file changed, 17 deletions(-) + +diff --git a/util/mkimage.c b/util/mkimage.c +index 2529de4bb78..64f4f139832 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -1292,7 +1292,6 @@ grub_install_generate_image (const char *dir, const char *prefix, + o->code_size = grub_host_to_target32 (layout.exec_size); + o->data_size = grub_cpu_to_le32 (reloc_addr - layout.exec_size + - header_size); +- o->bss_size = grub_cpu_to_le32 (layout.bss_size); + o->entry_addr = grub_cpu_to_le32 (layout.start_address); + o->code_base = grub_cpu_to_le32 (header_size); + +@@ -1330,7 +1329,6 @@ grub_install_generate_image (const char *dir, const char *prefix, + o->code_size = grub_host_to_target32 (layout.exec_size); + o->data_size = grub_cpu_to_le32 (reloc_addr - layout.exec_size + - header_size); +- o->bss_size = grub_cpu_to_le32 (layout.bss_size); + o->entry_addr = grub_cpu_to_le32 (layout.start_address); + o->code_base = grub_cpu_to_le32 (header_size); + o->image_base = 0; +@@ -1375,21 +1373,6 @@ grub_install_generate_image (const char *dir, const char *prefix, + = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA + | GRUB_PE32_SCN_MEM_READ + | GRUB_PE32_SCN_MEM_WRITE); +- +-#if 0 +- bss_section = data_section + 1; +- strcpy (bss_section->name, ".bss"); +- bss_section->virtual_size = grub_cpu_to_le32 (layout.bss_size); +- bss_section->virtual_address = grub_cpu_to_le32 (header_size + layout.kernel_size); +- bss_section->raw_data_size = 0; +- bss_section->raw_data_offset = 0; +- bss_section->characteristics +- = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_MEM_READ +- | GRUB_PE32_SCN_MEM_WRITE +- | GRUB_PE32_SCN_ALIGN_64BYTES +- | GRUB_PE32_SCN_CNT_INITIALIZED_DATA +- | 0x80); +-#endif + + mods_section = data_section + 1; + strcpy (mods_section->name, "mods"); diff --git a/SOURCES/0468-util-mkimage-Use-grub_host_to_target32-instead-of-gr.patch b/SOURCES/0468-util-mkimage-Use-grub_host_to_target32-instead-of-gr.patch new file mode 100644 index 0000000..0043fd0 --- /dev/null +++ b/SOURCES/0468-util-mkimage-Use-grub_host_to_target32-instead-of-gr.patch @@ -0,0 +1,109 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 15 Feb 2021 13:59:21 +0100 +Subject: [PATCH] util/mkimage: Use grub_host_to_target32() instead of + grub_cpu_to_le32() + +The latter doesn't take into account the target image endianness. There is +a grub_cpu_to_le32_compile_time() but no compile time variant for function +grub_host_to_target32(). So, let's keep using the other one for this case. + +Signed-off-by: Peter Jones +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + util/mkimage.c | 44 ++++++++++++++++++++++---------------------- + 1 file changed, 22 insertions(+), 22 deletions(-) + +diff --git a/util/mkimage.c b/util/mkimage.c +index 64f4f139832..601521d34cf 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -1290,10 +1290,10 @@ grub_install_generate_image (const char *dir, const char *prefix, + + sizeof (struct grub_pe32_coff_header)); + o->magic = grub_host_to_target16 (GRUB_PE32_PE32_MAGIC); + o->code_size = grub_host_to_target32 (layout.exec_size); +- o->data_size = grub_cpu_to_le32 (reloc_addr - layout.exec_size ++ o->data_size = grub_host_to_target32 (reloc_addr - layout.exec_size + - header_size); +- o->entry_addr = grub_cpu_to_le32 (layout.start_address); +- o->code_base = grub_cpu_to_le32 (header_size); ++ o->entry_addr = grub_host_to_target32 (layout.start_address); ++ o->code_base = grub_host_to_target32 (header_size); + + o->data_base = grub_host_to_target32 (header_size + layout.exec_size); + +@@ -1327,10 +1327,10 @@ grub_install_generate_image (const char *dir, const char *prefix, + + sizeof (struct grub_pe32_coff_header)); + o->magic = grub_host_to_target16 (GRUB_PE32_PE64_MAGIC); + o->code_size = grub_host_to_target32 (layout.exec_size); +- o->data_size = grub_cpu_to_le32 (reloc_addr - layout.exec_size ++ o->data_size = grub_host_to_target32 (reloc_addr - layout.exec_size + - header_size); +- o->entry_addr = grub_cpu_to_le32 (layout.start_address); +- o->code_base = grub_cpu_to_le32 (header_size); ++ o->entry_addr = grub_host_to_target32 (layout.start_address); ++ o->code_base = grub_host_to_target32 (header_size); + o->image_base = 0; + o->section_alignment = grub_host_to_target32 (image_target->section_align); + o->file_alignment = grub_host_to_target32 (image_target->section_align); +@@ -1354,10 +1354,10 @@ grub_install_generate_image (const char *dir, const char *prefix, + /* The sections. */ + text_section = sections; + strcpy (text_section->name, ".text"); +- text_section->virtual_size = grub_cpu_to_le32 (layout.exec_size); +- text_section->virtual_address = grub_cpu_to_le32 (header_size); +- text_section->raw_data_size = grub_cpu_to_le32 (layout.exec_size); +- text_section->raw_data_offset = grub_cpu_to_le32 (header_size); ++ text_section->virtual_size = grub_host_to_target32 (layout.exec_size); ++ text_section->virtual_address = grub_host_to_target32 (header_size); ++ text_section->raw_data_size = grub_host_to_target32 (layout.exec_size); ++ text_section->raw_data_offset = grub_host_to_target32 (header_size); + text_section->characteristics = grub_cpu_to_le32_compile_time ( + GRUB_PE32_SCN_CNT_CODE + | GRUB_PE32_SCN_MEM_EXECUTE +@@ -1365,10 +1365,10 @@ grub_install_generate_image (const char *dir, const char *prefix, + + data_section = text_section + 1; + strcpy (data_section->name, ".data"); +- data_section->virtual_size = grub_cpu_to_le32 (layout.kernel_size - layout.exec_size); +- data_section->virtual_address = grub_cpu_to_le32 (header_size + layout.exec_size); +- data_section->raw_data_size = grub_cpu_to_le32 (layout.kernel_size - layout.exec_size); +- data_section->raw_data_offset = grub_cpu_to_le32 (header_size + layout.exec_size); ++ data_section->virtual_size = grub_host_to_target32 (layout.kernel_size - layout.exec_size); ++ data_section->virtual_address = grub_host_to_target32 (header_size + layout.exec_size); ++ data_section->raw_data_size = grub_host_to_target32 (layout.kernel_size - layout.exec_size); ++ data_section->raw_data_offset = grub_host_to_target32 (header_size + layout.exec_size); + data_section->characteristics + = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA + | GRUB_PE32_SCN_MEM_READ +@@ -1376,10 +1376,10 @@ grub_install_generate_image (const char *dir, const char *prefix, + + mods_section = data_section + 1; + strcpy (mods_section->name, "mods"); +- mods_section->virtual_size = grub_cpu_to_le32 (reloc_addr - layout.kernel_size - header_size); +- mods_section->virtual_address = grub_cpu_to_le32 (header_size + layout.kernel_size + layout.bss_size); +- mods_section->raw_data_size = grub_cpu_to_le32 (reloc_addr - layout.kernel_size - header_size); +- mods_section->raw_data_offset = grub_cpu_to_le32 (header_size + layout.kernel_size); ++ mods_section->virtual_size = grub_host_to_target32 (reloc_addr - layout.kernel_size - header_size); ++ mods_section->virtual_address = grub_host_to_target32 (header_size + layout.kernel_size + layout.bss_size); ++ mods_section->raw_data_size = grub_host_to_target32 (reloc_addr - layout.kernel_size - header_size); ++ mods_section->raw_data_offset = grub_host_to_target32 (header_size + layout.kernel_size); + mods_section->characteristics + = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA + | GRUB_PE32_SCN_MEM_READ +@@ -1387,10 +1387,10 @@ grub_install_generate_image (const char *dir, const char *prefix, + + reloc_section = mods_section + 1; + strcpy (reloc_section->name, ".reloc"); +- reloc_section->virtual_size = grub_cpu_to_le32 (layout.reloc_size); +- reloc_section->virtual_address = grub_cpu_to_le32 (reloc_addr + layout.bss_size); +- reloc_section->raw_data_size = grub_cpu_to_le32 (layout.reloc_size); +- reloc_section->raw_data_offset = grub_cpu_to_le32 (reloc_addr); ++ reloc_section->virtual_size = grub_host_to_target32 (layout.reloc_size); ++ reloc_section->virtual_address = grub_host_to_target32 (reloc_addr + layout.bss_size); ++ reloc_section->raw_data_size = grub_host_to_target32 (layout.reloc_size); ++ reloc_section->raw_data_offset = grub_host_to_target32 (reloc_addr); + reloc_section->characteristics + = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA + | GRUB_PE32_SCN_MEM_DISCARDABLE diff --git a/SOURCES/0469-util-mkimage-Always-use-grub_host_to_target32-to-ini.patch b/SOURCES/0469-util-mkimage-Always-use-grub_host_to_target32-to-ini.patch new file mode 100644 index 0000000..cef0a35 --- /dev/null +++ b/SOURCES/0469-util-mkimage-Always-use-grub_host_to_target32-to-ini.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 15 Feb 2021 14:14:24 +0100 +Subject: [PATCH] util/mkimage: Always use grub_host_to_target32() to + initialize PE stack and heap stuff + +This change does not impact final result of initialization itself. +However, it eases PE code unification in subsequent patches. + +Signed-off-by: Peter Jones +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + util/mkimage.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/util/mkimage.c b/util/mkimage.c +index 601521d34cf..d2876cdb5fb 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -1339,10 +1339,10 @@ grub_install_generate_image (const char *dir, const char *prefix, + o->subsystem = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION); + + /* Do these really matter? */ +- o->stack_reserve_size = grub_host_to_target64 (0x10000); +- o->stack_commit_size = grub_host_to_target64 (0x10000); +- o->heap_reserve_size = grub_host_to_target64 (0x10000); +- o->heap_commit_size = grub_host_to_target64 (0x10000); ++ o->stack_reserve_size = grub_host_to_target32 (0x10000); ++ o->stack_commit_size = grub_host_to_target32 (0x10000); ++ o->heap_reserve_size = grub_host_to_target32 (0x10000); ++ o->heap_commit_size = grub_host_to_target32 (0x10000); + + o->num_data_directories + = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); diff --git a/SOURCES/0470-util-mkimage-Unify-more-of-the-PE32-and-PE32-header-.patch b/SOURCES/0470-util-mkimage-Unify-more-of-the-PE32-and-PE32-header-.patch new file mode 100644 index 0000000..e8e286a --- /dev/null +++ b/SOURCES/0470-util-mkimage-Unify-more-of-the-PE32-and-PE32-header-.patch @@ -0,0 +1,165 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 19 Feb 2021 14:22:13 +0100 +Subject: [PATCH] util/mkimage: Unify more of the PE32 and PE32+ header set-up + +There's quite a bit of code duplication in the code that sets the optional +header for PE32 and PE32+. The two are very similar with the exception of +a few fields that have type grub_uint64_t instead of grub_uint32_t. + +Factor out the common code and add a PE_OHDR() macro that simplifies the +set-up and make the code more readable. + +Signed-off-by: Peter Jones +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + util/mkimage.c | 111 ++++++++++++++++++++++++++------------------------------- + 1 file changed, 51 insertions(+), 60 deletions(-) + +diff --git a/util/mkimage.c b/util/mkimage.c +index d2876cdb5fb..ff5462c98c1 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -771,6 +771,21 @@ grub_install_get_image_targets_string (void) + return formats; + } + ++/* ++ * tmp_ is just here so the compiler knows we'll never derefernce a NULL. ++ * It should get fully optimized away. ++ */ ++#define PE_OHDR(o32, o64, field) (*( \ ++{ \ ++ __typeof__((o64)->field) tmp_; \ ++ __typeof__((o64)->field) *ret_ = &tmp_; \ ++ if (o32) \ ++ ret_ = (void *)(&((o32)->field)); \ ++ else if (o64) \ ++ ret_ = (void *)(&((o64)->field)); \ ++ ret_; \ ++})) ++ + void + grub_install_generate_image (const char *dir, const char *prefix, + FILE *out, const char *outname, char *mods[], +@@ -1240,6 +1255,8 @@ grub_install_generate_image (const char *dir, const char *prefix, + static const grub_uint8_t stub[] = GRUB_PE32_MSDOS_STUB; + int header_size; + int reloc_addr; ++ struct grub_pe32_optional_header *o32 = NULL; ++ struct grub_pe64_optional_header *o64 = NULL; + + if (image_target->voidp_sizeof == 4) + header_size = EFI32_HEADER_SIZE; +@@ -1281,76 +1298,50 @@ grub_install_generate_image (const char *dir, const char *prefix, + /* The PE Optional header. */ + if (image_target->voidp_sizeof == 4) + { +- struct grub_pe32_optional_header *o; +- + c->optional_header_size = grub_host_to_target16 (sizeof (struct grub_pe32_optional_header)); + +- o = (struct grub_pe32_optional_header *) +- (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE +- + sizeof (struct grub_pe32_coff_header)); +- o->magic = grub_host_to_target16 (GRUB_PE32_PE32_MAGIC); +- o->code_size = grub_host_to_target32 (layout.exec_size); +- o->data_size = grub_host_to_target32 (reloc_addr - layout.exec_size +- - header_size); +- o->entry_addr = grub_host_to_target32 (layout.start_address); +- o->code_base = grub_host_to_target32 (header_size); ++ o32 = (struct grub_pe32_optional_header *) ++ (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE + ++ sizeof (struct grub_pe32_coff_header)); ++ o32->magic = grub_host_to_target16 (GRUB_PE32_PE32_MAGIC); ++ o32->data_base = grub_host_to_target32 (header_size + layout.exec_size); + +- o->data_base = grub_host_to_target32 (header_size + layout.exec_size); +- +- o->image_base = 0; +- o->section_alignment = grub_host_to_target32 (image_target->section_align); +- o->file_alignment = grub_host_to_target32 (image_target->section_align); +- o->image_size = grub_host_to_target32 (pe_size); +- o->header_size = grub_host_to_target32 (header_size); +- o->subsystem = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION); +- +- /* Do these really matter? */ +- o->stack_reserve_size = grub_host_to_target32 (0x10000); +- o->stack_commit_size = grub_host_to_target32 (0x10000); +- o->heap_reserve_size = grub_host_to_target32 (0x10000); +- o->heap_commit_size = grub_host_to_target32 (0x10000); +- +- o->num_data_directories = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); +- +- o->base_relocation_table.rva = grub_host_to_target32 (reloc_addr); +- o->base_relocation_table.size = grub_host_to_target32 (layout.reloc_size); +- sections = o + 1; ++ sections = o32 + 1; + } + else + { +- struct grub_pe64_optional_header *o; +- + c->optional_header_size = grub_host_to_target16 (sizeof (struct grub_pe64_optional_header)); + +- o = (struct grub_pe64_optional_header *) +- (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE +- + sizeof (struct grub_pe32_coff_header)); +- o->magic = grub_host_to_target16 (GRUB_PE32_PE64_MAGIC); +- o->code_size = grub_host_to_target32 (layout.exec_size); +- o->data_size = grub_host_to_target32 (reloc_addr - layout.exec_size +- - header_size); +- o->entry_addr = grub_host_to_target32 (layout.start_address); +- o->code_base = grub_host_to_target32 (header_size); +- o->image_base = 0; +- o->section_alignment = grub_host_to_target32 (image_target->section_align); +- o->file_alignment = grub_host_to_target32 (image_target->section_align); +- o->image_size = grub_host_to_target32 (pe_size); +- o->header_size = grub_host_to_target32 (header_size); +- o->subsystem = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION); ++ o64 = (struct grub_pe64_optional_header *) ++ (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE + ++ sizeof (struct grub_pe32_coff_header)); ++ o64->magic = grub_host_to_target16 (GRUB_PE32_PE64_MAGIC); + +- /* Do these really matter? */ +- o->stack_reserve_size = grub_host_to_target32 (0x10000); +- o->stack_commit_size = grub_host_to_target32 (0x10000); +- o->heap_reserve_size = grub_host_to_target32 (0x10000); +- o->heap_commit_size = grub_host_to_target32 (0x10000); +- +- o->num_data_directories +- = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); +- +- o->base_relocation_table.rva = grub_host_to_target32 (reloc_addr); +- o->base_relocation_table.size = grub_host_to_target32 (layout.reloc_size); +- sections = o + 1; ++ sections = o64 + 1; + } ++ ++ PE_OHDR (o32, o64, code_size) = grub_host_to_target32 (layout.exec_size); ++ PE_OHDR (o32, o64, data_size) = grub_host_to_target32 (reloc_addr - layout.exec_size - header_size); ++ PE_OHDR (o32, o64, entry_addr) = grub_host_to_target32 (layout.start_address); ++ PE_OHDR (o32, o64, code_base) = grub_host_to_target32 (header_size); ++ ++ PE_OHDR (o32, o64, image_base) = 0; ++ PE_OHDR (o32, o64, section_alignment) = grub_host_to_target32 (image_target->section_align); ++ PE_OHDR (o32, o64, file_alignment) = grub_host_to_target32 (GRUB_PE32_FILE_ALIGNMENT); ++ PE_OHDR (o32, o64, image_size) = grub_host_to_target32 (pe_size); ++ PE_OHDR (o32, o64, header_size) = grub_host_to_target32 (header_size); ++ PE_OHDR (o32, o64, subsystem) = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION); ++ ++ /* Do these really matter? */ ++ PE_OHDR (o32, o64, stack_reserve_size) = grub_host_to_target32 (0x10000); ++ PE_OHDR (o32, o64, stack_commit_size) = grub_host_to_target32 (0x10000); ++ PE_OHDR (o32, o64, heap_reserve_size) = grub_host_to_target32 (0x10000); ++ PE_OHDR (o32, o64, heap_commit_size) = grub_host_to_target32 (0x10000); ++ ++ PE_OHDR (o32, o64, num_data_directories) = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); ++ PE_OHDR (o32, o64, base_relocation_table.rva) = grub_host_to_target32 (reloc_addr); ++ PE_OHDR (o32, o64, base_relocation_table.size) = grub_host_to_target32 (layout.reloc_size); ++ + /* The sections. */ + text_section = sections; + strcpy (text_section->name, ".text"); diff --git a/SOURCES/0471-util-mkimage-Reorder-PE-optional-header-fields-set-u.patch b/SOURCES/0471-util-mkimage-Reorder-PE-optional-header-fields-set-u.patch new file mode 100644 index 0000000..95a3c7d --- /dev/null +++ b/SOURCES/0471-util-mkimage-Reorder-PE-optional-header-fields-set-u.patch @@ -0,0 +1,69 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 15 Feb 2021 14:21:48 +0100 +Subject: [PATCH] util/mkimage: Reorder PE optional header fields set-up + +This makes the PE32 and PE32+ header fields set-up easier to follow by +setting them closer to the initialization of their related sections. + +Signed-off-by: Peter Jones +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + util/mkimage.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/util/mkimage.c b/util/mkimage.c +index ff5462c98c1..e73a5864b22 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -1320,16 +1320,12 @@ grub_install_generate_image (const char *dir, const char *prefix, + sections = o64 + 1; + } + +- PE_OHDR (o32, o64, code_size) = grub_host_to_target32 (layout.exec_size); +- PE_OHDR (o32, o64, data_size) = grub_host_to_target32 (reloc_addr - layout.exec_size - header_size); ++ PE_OHDR (o32, o64, header_size) = grub_host_to_target32 (header_size); + PE_OHDR (o32, o64, entry_addr) = grub_host_to_target32 (layout.start_address); +- PE_OHDR (o32, o64, code_base) = grub_host_to_target32 (header_size); +- + PE_OHDR (o32, o64, image_base) = 0; ++ PE_OHDR (o32, o64, image_size) = grub_host_to_target32 (pe_size); + PE_OHDR (o32, o64, section_alignment) = grub_host_to_target32 (image_target->section_align); + PE_OHDR (o32, o64, file_alignment) = grub_host_to_target32 (GRUB_PE32_FILE_ALIGNMENT); +- PE_OHDR (o32, o64, image_size) = grub_host_to_target32 (pe_size); +- PE_OHDR (o32, o64, header_size) = grub_host_to_target32 (header_size); + PE_OHDR (o32, o64, subsystem) = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION); + + /* Do these really matter? */ +@@ -1339,10 +1335,10 @@ grub_install_generate_image (const char *dir, const char *prefix, + PE_OHDR (o32, o64, heap_commit_size) = grub_host_to_target32 (0x10000); + + PE_OHDR (o32, o64, num_data_directories) = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); +- PE_OHDR (o32, o64, base_relocation_table.rva) = grub_host_to_target32 (reloc_addr); +- PE_OHDR (o32, o64, base_relocation_table.size) = grub_host_to_target32 (layout.reloc_size); + + /* The sections. */ ++ PE_OHDR (o32, o64, code_base) = grub_host_to_target32 (header_size); ++ PE_OHDR (o32, o64, code_size) = grub_host_to_target32 (layout.exec_size); + text_section = sections; + strcpy (text_section->name, ".text"); + text_section->virtual_size = grub_host_to_target32 (layout.exec_size); +@@ -1354,6 +1350,8 @@ grub_install_generate_image (const char *dir, const char *prefix, + | GRUB_PE32_SCN_MEM_EXECUTE + | GRUB_PE32_SCN_MEM_READ); + ++ PE_OHDR (o32, o64, data_size) = grub_host_to_target32 (reloc_addr - layout.exec_size - header_size); ++ + data_section = text_section + 1; + strcpy (data_section->name, ".data"); + data_section->virtual_size = grub_host_to_target32 (layout.kernel_size - layout.exec_size); +@@ -1376,6 +1374,8 @@ grub_install_generate_image (const char *dir, const char *prefix, + | GRUB_PE32_SCN_MEM_READ + | GRUB_PE32_SCN_MEM_WRITE); + ++ PE_OHDR (o32, o64, base_relocation_table.rva) = grub_host_to_target32 (reloc_addr); ++ PE_OHDR (o32, o64, base_relocation_table.size) = grub_host_to_target32 (layout.reloc_size); + reloc_section = mods_section + 1; + strcpy (reloc_section->name, ".reloc"); + reloc_section->virtual_size = grub_host_to_target32 (layout.reloc_size); diff --git a/SOURCES/0472-util-mkimage-Improve-data_size-value-calculation.patch b/SOURCES/0472-util-mkimage-Improve-data_size-value-calculation.patch new file mode 100644 index 0000000..31428ef --- /dev/null +++ b/SOURCES/0472-util-mkimage-Improve-data_size-value-calculation.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 11 Feb 2021 17:07:33 +0100 +Subject: [PATCH] util/mkimage: Improve data_size value calculation + +According to "Microsoft Portable Executable and Common Object File Format +Specification", the Optional Header SizeOfInitializedData field contains: + + Size of the initialized data section, or the sum of all such sections if + there are multiple data sections. + +Make this explicit by adding the GRUB kernel data size to the sum of all +the modules sizes. The ALIGN_UP() is not required by the PE spec but do +it to avoid alignment issues. + +Signed-off-by: Peter Jones +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + util/mkimage.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/util/mkimage.c b/util/mkimage.c +index e73a5864b22..f22b398d973 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -1248,6 +1248,7 @@ grub_install_generate_image (const char *dir, const char *prefix, + void *pe_img; + grub_uint8_t *header; + void *sections; ++ size_t scn_size; + size_t pe_size; + struct grub_pe32_coff_header *c; + struct grub_pe32_section_table *text_section, *data_section; +@@ -1350,7 +1351,10 @@ grub_install_generate_image (const char *dir, const char *prefix, + | GRUB_PE32_SCN_MEM_EXECUTE + | GRUB_PE32_SCN_MEM_READ); + +- PE_OHDR (o32, o64, data_size) = grub_host_to_target32 (reloc_addr - layout.exec_size - header_size); ++ scn_size = ALIGN_UP (layout.kernel_size - layout.exec_size, GRUB_PE32_FILE_ALIGNMENT); ++ PE_OHDR (o32, o64, data_size) = grub_host_to_target32 (scn_size + ++ ALIGN_UP (total_module_size, ++ GRUB_PE32_FILE_ALIGNMENT)); + + data_section = text_section + 1; + strcpy (data_section->name, ".data"); diff --git a/SOURCES/0473-util-mkimage-Refactor-section-setup-to-use-a-helper.patch b/SOURCES/0473-util-mkimage-Refactor-section-setup-to-use-a-helper.patch new file mode 100644 index 0000000..41d3f2f --- /dev/null +++ b/SOURCES/0473-util-mkimage-Refactor-section-setup-to-use-a-helper.patch @@ -0,0 +1,216 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 15 Feb 2021 14:58:06 +0100 +Subject: [PATCH] util/mkimage: Refactor section setup to use a helper + +Add a init_pe_section() helper function to setup PE sections. This makes +the code simpler and easier to read. + +Signed-off-by: Peter Jones +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + util/mkimage.c | 141 +++++++++++++++++++++++++++++++-------------------------- + 1 file changed, 76 insertions(+), 65 deletions(-) + +diff --git a/util/mkimage.c b/util/mkimage.c +index f22b398d973..0f5ae2a76f2 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -771,6 +771,38 @@ grub_install_get_image_targets_string (void) + return formats; + } + ++/* ++ * The image_target parameter is used by the grub_host_to_target32() macro. ++ */ ++static struct grub_pe32_section_table * ++init_pe_section(const struct grub_install_image_target_desc *image_target, ++ struct grub_pe32_section_table *section, ++ const char * const name, ++ grub_uint32_t *vma, grub_uint32_t vsz, grub_uint32_t valign, ++ grub_uint32_t *rda, grub_uint32_t rsz, ++ grub_uint32_t characteristics) ++{ ++ size_t len = strlen (name); ++ ++ if (len > sizeof (section->name)) ++ grub_util_error (_("section name %s length is bigger than %lu"), ++ name, (unsigned long) sizeof (section->name)); ++ ++ memcpy (section->name, name, len); ++ ++ section->virtual_address = grub_host_to_target32 (*vma); ++ section->virtual_size = grub_host_to_target32 (vsz); ++ (*vma) = ALIGN_UP (*vma + vsz, valign); ++ ++ section->raw_data_offset = grub_host_to_target32 (*rda); ++ section->raw_data_size = grub_host_to_target32 (rsz); ++ (*rda) = ALIGN_UP (*rda + rsz, GRUB_PE32_FILE_ALIGNMENT); ++ ++ section->characteristics = grub_host_to_target32 (characteristics); ++ ++ return section + 1; ++} ++ + /* + * tmp_ is just here so the compiler knows we'll never derefernce a NULL. + * It should get fully optimized away. +@@ -1245,17 +1277,13 @@ grub_install_generate_image (const char *dir, const char *prefix, + break; + case IMAGE_EFI: + { +- void *pe_img; +- grub_uint8_t *header; +- void *sections; ++ char *pe_img, *header; ++ struct grub_pe32_section_table *section; + size_t scn_size; +- size_t pe_size; ++ grub_uint32_t vma, raw_data; ++ size_t pe_size, header_size; + struct grub_pe32_coff_header *c; +- struct grub_pe32_section_table *text_section, *data_section; +- struct grub_pe32_section_table *mods_section, *reloc_section; + static const grub_uint8_t stub[] = GRUB_PE32_MSDOS_STUB; +- int header_size; +- int reloc_addr; + struct grub_pe32_optional_header *o32 = NULL; + struct grub_pe64_optional_header *o64 = NULL; + +@@ -1264,17 +1292,12 @@ grub_install_generate_image (const char *dir, const char *prefix, + else + header_size = EFI64_HEADER_SIZE; + +- reloc_addr = ALIGN_UP (header_size + core_size, +- image_target->section_align); ++ vma = raw_data = header_size; ++ pe_size = ALIGN_UP (header_size + core_size, GRUB_PE32_FILE_ALIGNMENT) + ++ ALIGN_UP (layout.reloc_size, GRUB_PE32_FILE_ALIGNMENT); ++ header = pe_img = xcalloc (1, pe_size); + +- pe_size = ALIGN_UP (reloc_addr + layout.reloc_size, +- image_target->section_align); +- pe_img = xmalloc (reloc_addr + layout.reloc_size); +- memset (pe_img, 0, header_size); +- memcpy ((char *) pe_img + header_size, core_img, core_size); +- memset ((char *) pe_img + header_size + core_size, 0, reloc_addr - (header_size + core_size)); +- memcpy ((char *) pe_img + reloc_addr, layout.reloc_section, layout.reloc_size); +- header = pe_img; ++ memcpy (pe_img + raw_data, core_img, core_size); + + /* The magic. */ + memcpy (header, stub, GRUB_PE32_MSDOS_STUB_SIZE); +@@ -1307,18 +1330,17 @@ grub_install_generate_image (const char *dir, const char *prefix, + o32->magic = grub_host_to_target16 (GRUB_PE32_PE32_MAGIC); + o32->data_base = grub_host_to_target32 (header_size + layout.exec_size); + +- sections = o32 + 1; ++ section = (struct grub_pe32_section_table *)(o32 + 1); + } + else + { + c->optional_header_size = grub_host_to_target16 (sizeof (struct grub_pe64_optional_header)); +- + o64 = (struct grub_pe64_optional_header *) + (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE + + sizeof (struct grub_pe32_coff_header)); + o64->magic = grub_host_to_target16 (GRUB_PE32_PE64_MAGIC); + +- sections = o64 + 1; ++ section = (struct grub_pe32_section_table *)(o64 + 1); + } + + PE_OHDR (o32, o64, header_size) = grub_host_to_target32 (header_size); +@@ -1338,58 +1360,47 @@ grub_install_generate_image (const char *dir, const char *prefix, + PE_OHDR (o32, o64, num_data_directories) = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); + + /* The sections. */ +- PE_OHDR (o32, o64, code_base) = grub_host_to_target32 (header_size); ++ PE_OHDR (o32, o64, code_base) = grub_host_to_target32 (vma); + PE_OHDR (o32, o64, code_size) = grub_host_to_target32 (layout.exec_size); +- text_section = sections; +- strcpy (text_section->name, ".text"); +- text_section->virtual_size = grub_host_to_target32 (layout.exec_size); +- text_section->virtual_address = grub_host_to_target32 (header_size); +- text_section->raw_data_size = grub_host_to_target32 (layout.exec_size); +- text_section->raw_data_offset = grub_host_to_target32 (header_size); +- text_section->characteristics = grub_cpu_to_le32_compile_time ( +- GRUB_PE32_SCN_CNT_CODE +- | GRUB_PE32_SCN_MEM_EXECUTE +- | GRUB_PE32_SCN_MEM_READ); ++ section = init_pe_section (image_target, section, ".text", ++ &vma, layout.exec_size, ++ image_target->section_align, ++ &raw_data, layout.exec_size, ++ GRUB_PE32_SCN_CNT_CODE | ++ GRUB_PE32_SCN_MEM_EXECUTE | ++ GRUB_PE32_SCN_MEM_READ); + + scn_size = ALIGN_UP (layout.kernel_size - layout.exec_size, GRUB_PE32_FILE_ALIGNMENT); + PE_OHDR (o32, o64, data_size) = grub_host_to_target32 (scn_size + + ALIGN_UP (total_module_size, + GRUB_PE32_FILE_ALIGNMENT)); + +- data_section = text_section + 1; +- strcpy (data_section->name, ".data"); +- data_section->virtual_size = grub_host_to_target32 (layout.kernel_size - layout.exec_size); +- data_section->virtual_address = grub_host_to_target32 (header_size + layout.exec_size); +- data_section->raw_data_size = grub_host_to_target32 (layout.kernel_size - layout.exec_size); +- data_section->raw_data_offset = grub_host_to_target32 (header_size + layout.exec_size); +- data_section->characteristics +- = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA +- | GRUB_PE32_SCN_MEM_READ +- | GRUB_PE32_SCN_MEM_WRITE); +- +- mods_section = data_section + 1; +- strcpy (mods_section->name, "mods"); +- mods_section->virtual_size = grub_host_to_target32 (reloc_addr - layout.kernel_size - header_size); +- mods_section->virtual_address = grub_host_to_target32 (header_size + layout.kernel_size + layout.bss_size); +- mods_section->raw_data_size = grub_host_to_target32 (reloc_addr - layout.kernel_size - header_size); +- mods_section->raw_data_offset = grub_host_to_target32 (header_size + layout.kernel_size); +- mods_section->characteristics +- = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA +- | GRUB_PE32_SCN_MEM_READ +- | GRUB_PE32_SCN_MEM_WRITE); ++ section = init_pe_section (image_target, section, ".data", ++ &vma, scn_size, image_target->section_align, ++ &raw_data, scn_size, ++ GRUB_PE32_SCN_CNT_INITIALIZED_DATA | ++ GRUB_PE32_SCN_MEM_READ | ++ GRUB_PE32_SCN_MEM_WRITE); ++ ++ scn_size = pe_size - layout.reloc_size - raw_data; ++ section = init_pe_section (image_target, section, "mods", ++ &vma, scn_size, image_target->section_align, ++ &raw_data, scn_size, ++ GRUB_PE32_SCN_CNT_INITIALIZED_DATA | ++ GRUB_PE32_SCN_MEM_READ | ++ GRUB_PE32_SCN_MEM_WRITE); ++ ++ scn_size = layout.reloc_size; ++ PE_OHDR (o32, o64, base_relocation_table.rva) = grub_host_to_target32 (vma); ++ PE_OHDR (o32, o64, base_relocation_table.size) = grub_host_to_target32 (scn_size); ++ memcpy (pe_img + raw_data, layout.reloc_section, scn_size); ++ init_pe_section (image_target, section, ".reloc", ++ &vma, scn_size, image_target->section_align, ++ &raw_data, scn_size, ++ GRUB_PE32_SCN_CNT_INITIALIZED_DATA | ++ GRUB_PE32_SCN_MEM_DISCARDABLE | ++ GRUB_PE32_SCN_MEM_READ); + +- PE_OHDR (o32, o64, base_relocation_table.rva) = grub_host_to_target32 (reloc_addr); +- PE_OHDR (o32, o64, base_relocation_table.size) = grub_host_to_target32 (layout.reloc_size); +- reloc_section = mods_section + 1; +- strcpy (reloc_section->name, ".reloc"); +- reloc_section->virtual_size = grub_host_to_target32 (layout.reloc_size); +- reloc_section->virtual_address = grub_host_to_target32 (reloc_addr + layout.bss_size); +- reloc_section->raw_data_size = grub_host_to_target32 (layout.reloc_size); +- reloc_section->raw_data_offset = grub_host_to_target32 (reloc_addr); +- reloc_section->characteristics +- = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA +- | GRUB_PE32_SCN_MEM_DISCARDABLE +- | GRUB_PE32_SCN_MEM_READ); + free (core_img); + core_img = pe_img; + core_size = pe_size; diff --git a/SOURCES/0474-util-mkimage-Add-an-option-to-import-SBAT-metadata-i.patch b/SOURCES/0474-util-mkimage-Add-an-option-to-import-SBAT-metadata-i.patch new file mode 100644 index 0000000..7044e57 --- /dev/null +++ b/SOURCES/0474-util-mkimage-Add-an-option-to-import-SBAT-metadata-i.patch @@ -0,0 +1,260 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 15 Feb 2021 17:07:00 +0100 +Subject: [PATCH] util/mkimage: Add an option to import SBAT metadata into a + .sbat section + +Add a --sbat option to the grub-mkimage tool which allows us to import +an SBAT metadata formatted as a CSV file into a .sbat section of the +EFI binary. + +Signed-off-by: Peter Jones +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + util/grub-install-common.c | 2 +- + util/grub-mkimage.c | 15 ++++++++++++++- + util/mkimage.c | 43 ++++++++++++++++++++++++++++++++++++------- + include/grub/util/install.h | 3 ++- + include/grub/util/mkimage.h | 1 + + docs/grub.texi | 19 +++++++++++++++++++ + 6 files changed, 73 insertions(+), 10 deletions(-) + +diff --git a/util/grub-install-common.c b/util/grub-install-common.c +index fa6b65347ea..fde4ca7fc8c 100644 +--- a/util/grub-install-common.c ++++ b/util/grub-install-common.c +@@ -537,7 +537,7 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, + pubkeys, npubkeys, + x509keys, nx509keys, + config_path, tgt, +- note, appsig_size, compression, dtb); ++ note, appsig_size, compression, dtb, NULL); + while (dc--) + grub_install_pop_module (); + } +diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c +index 394d2dc5fc9..17a86261ffc 100644 +--- a/util/grub-mkimage.c ++++ b/util/grub-mkimage.c +@@ -82,6 +82,7 @@ static struct argp_option options[] = { + {"output", 'o', N_("FILE"), 0, N_("output a generated image to FILE [default=stdout]"), 0}, + {"format", 'O', N_("FORMAT"), 0, 0, 0}, + {"compression", 'C', "(xz|none|auto)", 0, N_("choose the compression to use for core image"), 0}, ++ {"sbat", 's', N_("FILE"), 0, N_("SBAT metadata"), 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 } +@@ -127,6 +128,7 @@ struct arguments + size_t nx509keys; + char *font; + char *config; ++ char *sbat; + int note; + size_t appsig_size; + const struct grub_install_image_target_desc *image_target; +@@ -244,6 +246,13 @@ argp_parser (int key, char *arg, struct argp_state *state) + arguments->prefix = xstrdup (arg); + break; + ++ case 's': ++ if (arguments->sbat) ++ free (arguments->sbat); ++ ++ arguments->sbat = xstrdup (arg); ++ break; ++ + case 'v': + verbosity++; + break; +@@ -331,7 +340,8 @@ main (int argc, char *argv[]) + arguments.nx509keys, arguments.config, + arguments.image_target, arguments.note, + arguments.appsig_size, +- arguments.comp, arguments.dtb); ++ arguments.comp, arguments.dtb, ++ arguments.sbat); + + grub_util_file_sync (fp); + fclose (fp); +@@ -346,5 +356,8 @@ main (int argc, char *argv[]) + if (arguments.output) + free (arguments.output); + ++ if (arguments.sbat) ++ free (arguments.sbat); ++ + return 0; + } +diff --git a/util/mkimage.c b/util/mkimage.c +index 0f5ae2a76f2..16418e245d3 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -826,12 +826,13 @@ grub_install_generate_image (const char *dir, const char *prefix, + 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) ++ int note, size_t appsig_size, grub_compression_t comp, ++ const char *dtb_path, const char *sbat_path) + { + char *kernel_img, *core_img; + size_t total_module_size, core_size; + size_t memdisk_size = 0, config_size = 0; +- size_t prefix_size = 0, dtb_size = 0; ++ size_t prefix_size = 0, dtb_size = 0, sbat_size = 0; + char *kernel_path; + size_t offset; + struct grub_util_path_list *path_list, *p; +@@ -895,6 +896,9 @@ grub_install_generate_image (const char *dir, const char *prefix, + total_module_size += dtb_size + sizeof (struct grub_module_header); + } + ++ if (sbat_path != NULL && image_target->id != IMAGE_EFI) ++ grub_util_error (_(".sbat section can be embedded into EFI images only")); ++ + if (config_path) + { + config_size = ALIGN_ADDR (grub_util_get_image_size (config_path) + 1); +@@ -1277,8 +1281,9 @@ grub_install_generate_image (const char *dir, const char *prefix, + break; + case IMAGE_EFI: + { +- char *pe_img, *header; ++ char *pe_img, *pe_sbat, *header; + struct grub_pe32_section_table *section; ++ size_t n_sections = 4; + size_t scn_size; + grub_uint32_t vma, raw_data; + size_t pe_size, header_size; +@@ -1293,8 +1298,15 @@ grub_install_generate_image (const char *dir, const char *prefix, + header_size = EFI64_HEADER_SIZE; + + vma = raw_data = header_size; ++ ++ if (sbat_path != NULL) ++ { ++ sbat_size = ALIGN_ADDR (grub_util_get_image_size (sbat_path)); ++ sbat_size = ALIGN_UP (sbat_size, GRUB_PE32_FILE_ALIGNMENT); ++ } ++ + pe_size = ALIGN_UP (header_size + core_size, GRUB_PE32_FILE_ALIGNMENT) + +- ALIGN_UP (layout.reloc_size, GRUB_PE32_FILE_ALIGNMENT); ++ ALIGN_UP (layout.reloc_size, GRUB_PE32_FILE_ALIGNMENT) + sbat_size; + header = pe_img = xcalloc (1, pe_size); + + memcpy (pe_img + raw_data, core_img, core_size); +@@ -1309,7 +1321,10 @@ grub_install_generate_image (const char *dir, const char *prefix, + + GRUB_PE32_SIGNATURE_SIZE); + c->machine = grub_host_to_target16 (image_target->pe_target); + +- c->num_sections = grub_host_to_target16 (4); ++ if (sbat_path != NULL) ++ n_sections++; ++ ++ c->num_sections = grub_host_to_target16 (n_sections); + c->time = grub_host_to_target32 (STABLE_EMBEDDING_TIMESTAMP); + c->characteristics = grub_host_to_target16 (GRUB_PE32_EXECUTABLE_IMAGE + | GRUB_PE32_LINE_NUMS_STRIPPED +@@ -1371,7 +1386,8 @@ grub_install_generate_image (const char *dir, const char *prefix, + GRUB_PE32_SCN_MEM_READ); + + scn_size = ALIGN_UP (layout.kernel_size - layout.exec_size, GRUB_PE32_FILE_ALIGNMENT); +- PE_OHDR (o32, o64, data_size) = grub_host_to_target32 (scn_size + ++ /* ALIGN_UP (sbat_size, GRUB_PE32_FILE_ALIGNMENT) is done earlier. */ ++ PE_OHDR (o32, o64, data_size) = grub_host_to_target32 (scn_size + sbat_size + + ALIGN_UP (total_module_size, + GRUB_PE32_FILE_ALIGNMENT)); + +@@ -1382,7 +1398,7 @@ grub_install_generate_image (const char *dir, const char *prefix, + GRUB_PE32_SCN_MEM_READ | + GRUB_PE32_SCN_MEM_WRITE); + +- scn_size = pe_size - layout.reloc_size - raw_data; ++ scn_size = pe_size - layout.reloc_size - sbat_size - raw_data; + section = init_pe_section (image_target, section, "mods", + &vma, scn_size, image_target->section_align, + &raw_data, scn_size, +@@ -1390,6 +1406,19 @@ grub_install_generate_image (const char *dir, const char *prefix, + GRUB_PE32_SCN_MEM_READ | + GRUB_PE32_SCN_MEM_WRITE); + ++ if (sbat_path != NULL) ++ { ++ pe_sbat = pe_img + raw_data; ++ grub_util_load_image (sbat_path, pe_sbat); ++ ++ section = init_pe_section (image_target, section, ".sbat", ++ &vma, sbat_size, ++ image_target->section_align, ++ &raw_data, sbat_size, ++ GRUB_PE32_SCN_CNT_INITIALIZED_DATA | ++ GRUB_PE32_SCN_MEM_READ); ++ } ++ + scn_size = layout.reloc_size; + PE_OHDR (o32, o64, base_relocation_table.rva) = grub_host_to_target32 (vma); + PE_OHDR (o32, o64, base_relocation_table.size) = grub_host_to_target32 (scn_size); +diff --git a/include/grub/util/install.h b/include/grub/util/install.h +index 95059285bd4..dad17561c4f 100644 +--- a/include/grub/util/install.h ++++ b/include/grub/util/install.h +@@ -187,7 +187,8 @@ grub_install_generate_image (const char *dir, const char *prefix, + 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_file); ++ grub_compression_t comp, const char *dtb_file, ++ const char *sbat_path); + + const struct grub_install_image_target_desc * + grub_install_get_image_target (const char *arg); +diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h +index cef7fffa7ae..f48d544c28a 100644 +--- a/include/grub/util/mkimage.h ++++ b/include/grub/util/mkimage.h +@@ -24,6 +24,7 @@ struct grub_mkimage_layout + size_t exec_size; + size_t kernel_size; + size_t bss_size; ++ size_t sbat_size; + grub_uint64_t start_address; + void *reloc_section; + size_t reloc_size; +diff --git a/docs/grub.texi b/docs/grub.texi +index 314bbeb8471..52e6e5763b8 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -5719,6 +5719,7 @@ environment variables and commands are listed in the same order. + * Using GPG-style digital signatures:: Booting digitally signed code + * Using appended signatures:: An alternative approach to booting digitally signed code + * Signing GRUB itself:: Ensuring the integrity of the GRUB core image ++* Secure Boot Advanced Targeting:: Embedded information for generation number based revocation + * Lockdown:: Lockdown when booting on a secure setup + @end menu + +@@ -6010,6 +6011,24 @@ As with UEFI secure boot, it is necessary to build in the required modules, + or sign them separately. + + ++@node Secure Boot Advanced Targeting ++@section Embedded information for generation number based revocation ++ ++The Secure Boot Advanced Targeting (SBAT) is a mechanism to allow the revocation ++of components in the boot path by using generation numbers embedded into the EFI ++binaries. The SBAT metadata is located in an .sbat data section that has set of ++UTF-8 strings as comma-separated values (CSV). See ++@uref{https://github.com/rhboot/shim/blob/main/SBAT.md} for more details. ++ ++To add a data section containing the SBAT information into the binary, the ++@option{--sbat} option of @command{grub-mkimage} command should be used. The content ++of a CSV file, encoded with UTF-8, is copied as is to the .sbat data section into ++the generated EFI binary. The CSV file can be stored anywhere on the file system. ++ ++@example ++grub-mkimage -O x86_64-efi -o grubx64.efi -p '(tftp)/grub' --sbat sbat.csv efinet tftp ++@end example ++ + @node Lockdown + @section Lockdown when booting on a secure setup + diff --git a/SOURCES/0475-kern-misc-Split-parse_printf_args-into-format-parsin.patch b/SOURCES/0475-kern-misc-Split-parse_printf_args-into-format-parsin.patch new file mode 100644 index 0000000..7ff44dd --- /dev/null +++ b/SOURCES/0475-kern-misc-Split-parse_printf_args-into-format-parsin.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Thomas Frauendorfer | Miray Software +Date: Mon, 15 Feb 2021 13:40:16 +0100 +Subject: [PATCH] kern/misc: Split parse_printf_args() into format parsing and + va_list handling + +This patch is preparing for a follow up patch which will use +the format parsing part to compare the arguments in a printf() +format from an external source against a printf() format with +expected arguments. + +Signed-off-by: Thomas Frauendorfer | Miray Software +Reviewed-by: Daniel Kiper +--- + grub-core/kern/misc.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c +index 475f3e0ef05..ebfcc95f01d 100644 +--- a/grub-core/kern/misc.c ++++ b/grub-core/kern/misc.c +@@ -711,8 +711,7 @@ grub_lltoa (char *str, int c, unsigned long long n) + } + + static void +-parse_printf_args (const char *fmt0, struct printf_args *args, +- va_list args_in) ++parse_printf_arg_fmt (const char *fmt0, struct printf_args *args) + { + const char *fmt; + char c; +@@ -870,6 +869,14 @@ parse_printf_args (const char *fmt0, struct printf_args *args, + break; + } + } ++} ++ ++static void ++parse_printf_args (const char *fmt0, struct printf_args *args, va_list args_in) ++{ ++ grub_size_t n; ++ ++ parse_printf_arg_fmt (fmt0, args); + + for (n = 0; n < args->count; n++) + switch (args->ptr[n].type) diff --git a/SOURCES/0476-kern-misc-Add-STRING-type-for-internal-printf-format.patch b/SOURCES/0476-kern-misc-Add-STRING-type-for-internal-printf-format.patch new file mode 100644 index 0000000..8e6e474 --- /dev/null +++ b/SOURCES/0476-kern-misc-Add-STRING-type-for-internal-printf-format.patch @@ -0,0 +1,64 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Thomas Frauendorfer | Miray Software +Date: Mon, 15 Feb 2021 14:04:26 +0100 +Subject: [PATCH] kern/misc: Add STRING type for internal printf() format + handling + +Set printf() argument type for "%s" to new type STRING. This is in +preparation for a follow up patch to compare a printf() format string +against an expected printf() format string. + +For "%s" the corresponding printf() argument is dereferenced as pointer +while all other argument types are defined as integer value. However, +when validating a printf() format it is necessary to differentiate "%s" +from "%p" and other integers. So, let's do that. + +Signed-off-by: Thomas Frauendorfer | Miray Software +Reviewed-by: Daniel Kiper +--- + grub-core/kern/misc.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c +index ebfcc95f01d..07456faa2a7 100644 +--- a/grub-core/kern/misc.c ++++ b/grub-core/kern/misc.c +@@ -37,7 +37,8 @@ union printf_arg + enum + { + INT, LONG, LONGLONG, +- UNSIGNED_INT = 3, UNSIGNED_LONG, UNSIGNED_LONGLONG ++ UNSIGNED_INT = 3, UNSIGNED_LONG, UNSIGNED_LONGLONG, ++ STRING + } type; + long long ll; + }; +@@ -857,12 +858,14 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args) + args->ptr[curn].type = INT + longfmt; + break; + case 'p': +- case 's': + if (sizeof (void *) == sizeof (long long)) + args->ptr[curn].type = UNSIGNED_LONGLONG; + else + args->ptr[curn].type = UNSIGNED_INT; + break; ++ case 's': ++ args->ptr[curn].type = STRING; ++ break; + case 'C': + case 'c': + args->ptr[curn].type = INT; +@@ -897,6 +900,12 @@ parse_printf_args (const char *fmt0, struct printf_args *args, va_list args_in) + case UNSIGNED_LONGLONG: + args->ptr[n].ll = va_arg (args_in, long long); + break; ++ case STRING: ++ if (sizeof (void *) == sizeof (long long)) ++ args->ptr[n].ll = va_arg (args_in, long long); ++ else ++ args->ptr[n].ll = va_arg (args_in, unsigned int); ++ break; + } + } + diff --git a/SOURCES/0477-kern-misc-Add-function-to-check-printf-format-agains.patch b/SOURCES/0477-kern-misc-Add-function-to-check-printf-format-agains.patch new file mode 100644 index 0000000..0dacf63 --- /dev/null +++ b/SOURCES/0477-kern-misc-Add-function-to-check-printf-format-agains.patch @@ -0,0 +1,215 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Thomas Frauendorfer | Miray Software +Date: Thu, 4 Feb 2021 19:02:33 +0100 +Subject: [PATCH] kern/misc: Add function to check printf() format against + expected format + +The grub_printf_fmt_check() function parses the arguments of an untrusted +printf() format and an expected printf() format and then compares the +arguments counts and arguments types. The arguments count in the untrusted +format string must be less or equal to the arguments count in the expected +format string and both arguments types must match. + +To do this the parse_printf_arg_fmt() helper function is extended in the +following way: + + 1. Add a return value to report errors to the grub_printf_fmt_check(). + + 2. Add the fmt_check argument to enable stricter format verification: + - the function expects that arguments definitions are always + terminated by a supported conversion specifier. + - positional parameters, "$", are not allowed, as they cannot be + validated correctly with the current implementation. For example + "%s%1$d" would assign the first args entry twice while leaving the + second one unchanged. + - Return an error if preallocated space in args is too small and + allocation fails for the needed size. The grub_printf_fmt_check() + should verify all arguments. So, if validation is not possible for + any reason it should return an error. + This also adds a case entry to handle "%%", which is the escape + sequence to print "%" character. + + 3. Add the max_args argument to check for the maximum allowed arguments + count in a printf() string. This should be set to the arguments count + of the expected format. Then the parse_printf_arg_fmt() function will + return an error if the arguments count is exceeded. + +The two additional arguments allow us to use parse_printf_arg_fmt() in +printf() and grub_printf_fmt_check() calls. + +When parse_printf_arg_fmt() is used by grub_printf_fmt_check() the +function parse user provided untrusted format string too. So, in +that case it is better to be too strict than too lenient. + +Signed-off-by: Thomas Frauendorfer | Miray Software +Reviewed-by: Daniel Kiper +--- + grub-core/kern/misc.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++--- + include/grub/misc.h | 16 ++++++++++ + 2 files changed, 94 insertions(+), 4 deletions(-) + +diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c +index 07456faa2a7..859d71659a2 100644 +--- a/grub-core/kern/misc.c ++++ b/grub-core/kern/misc.c +@@ -711,8 +711,26 @@ grub_lltoa (char *str, int c, unsigned long long n) + return p; + } + +-static void +-parse_printf_arg_fmt (const char *fmt0, struct printf_args *args) ++/* ++ * Parse printf() fmt0 string into args arguments. ++ * ++ * The parsed arguments are either used by a printf() function to format the fmt0 ++ * string or they are used to compare a format string from an untrusted source ++ * against a format string with expected arguments. ++ * ++ * When the fmt_check is set to !0, e.g. 1, then this function is executed in ++ * printf() format check mode. This enforces stricter rules for parsing the ++ * fmt0 to limit exposure to possible errors in printf() handling. It also ++ * disables positional parameters, "$", because some formats, e.g "%s%1$d", ++ * cannot be validated with the current implementation. ++ * ++ * The max_args allows to set a maximum number of accepted arguments. If the fmt0 ++ * string defines more arguments than the max_args then the parse_printf_arg_fmt() ++ * function returns an error. This is currently used for format check only. ++ */ ++static grub_err_t ++parse_printf_arg_fmt (const char *fmt0, struct printf_args *args, ++ int fmt_check, grub_size_t max_args) + { + const char *fmt; + char c; +@@ -739,7 +757,12 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args) + fmt++; + + if (*fmt == '$') +- fmt++; ++ { ++ if (fmt_check) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ "positional arguments are not supported"); ++ fmt++; ++ } + + if (*fmt =='-') + fmt++; +@@ -771,9 +794,19 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args) + case 's': + args->count++; + break; ++ case '%': ++ /* "%%" is the escape sequence to output "%". */ ++ break; ++ default: ++ if (fmt_check) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "unexpected format"); ++ break; + } + } + ++ if (fmt_check && args->count > max_args) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "too many arguments"); ++ + if (args->count <= ARRAY_SIZE (args->prealloc)) + args->ptr = args->prealloc; + else +@@ -781,6 +814,9 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args) + args->ptr = grub_calloc (args->count, sizeof (args->ptr[0])); + if (!args->ptr) + { ++ if (fmt_check) ++ return grub_errno; ++ + grub_errno = GRUB_ERR_NONE; + args->ptr = args->prealloc; + args->count = ARRAY_SIZE (args->prealloc); +@@ -872,6 +908,8 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args) + break; + } + } ++ ++ return GRUB_ERR_NONE; + } + + static void +@@ -879,7 +917,7 @@ parse_printf_args (const char *fmt0, struct printf_args *args, va_list args_in) + { + grub_size_t n; + +- parse_printf_arg_fmt (fmt0, args); ++ parse_printf_arg_fmt (fmt0, args, 0, 0); + + for (n = 0; n < args->count; n++) + switch (args->ptr[n].type) +@@ -1187,6 +1225,42 @@ grub_xasprintf (const char *fmt, ...) + return ret; + } + ++grub_err_t ++grub_printf_fmt_check (const char *fmt, const char *fmt_expected) ++{ ++ struct printf_args args_expected, args_fmt; ++ grub_err_t ret; ++ grub_size_t n; ++ ++ if (fmt == NULL || fmt_expected == NULL) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid format"); ++ ++ ret = parse_printf_arg_fmt (fmt_expected, &args_expected, 1, GRUB_SIZE_MAX); ++ if (ret != GRUB_ERR_NONE) ++ return ret; ++ ++ /* Limit parsing to the number of expected arguments. */ ++ ret = parse_printf_arg_fmt (fmt, &args_fmt, 1, args_expected.count); ++ if (ret != GRUB_ERR_NONE) ++ { ++ free_printf_args (&args_expected); ++ return ret; ++ } ++ ++ for (n = 0; n < args_fmt.count; n++) ++ if (args_fmt.ptr[n].type != args_expected.ptr[n].type) ++ { ++ ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "arguments types do not match"); ++ break; ++ } ++ ++ free_printf_args (&args_expected); ++ free_printf_args (&args_fmt); ++ ++ return ret; ++} ++ ++ + /* Abort GRUB. This function does not return. */ + static inline void __attribute__ ((noreturn)) + grub_abort (void) +diff --git a/include/grub/misc.h b/include/grub/misc.h +index 6ca03c4d692..6be6a88f652 100644 +--- a/include/grub/misc.h ++++ b/include/grub/misc.h +@@ -488,6 +488,22 @@ grub_error_load (const struct grub_error_saved *save) + grub_errno = save->grub_errno; + } + ++/* ++ * grub_printf_fmt_checks() a fmt string for printf() against an expected ++ * format. It is intended for cases where the fmt string could come from ++ * an outside source and cannot be trusted. ++ * ++ * While expected fmt accepts a printf() format string it should be kept ++ * as simple as possible. The printf() format strings with positional ++ * parameters are NOT accepted, neither for fmt nor for fmt_expected. ++ * ++ * The fmt is accepted if it has equal or less arguments than fmt_expected ++ * and if the type of all arguments match. ++ * ++ * Returns GRUB_ERR_NONE if fmt is acceptable. ++ */ ++grub_err_t EXPORT_FUNC (grub_printf_fmt_check) (const char *fmt, const char *fmt_expected); ++ + #if BOOT_TIME_STATS + struct grub_boot_time + { diff --git a/SOURCES/0478-gfxmenu-gui-Check-printf-format-in-the-gui_progress_.patch b/SOURCES/0478-gfxmenu-gui-Check-printf-format-in-the-gui_progress_.patch new file mode 100644 index 0000000..f1c4e5a --- /dev/null +++ b/SOURCES/0478-gfxmenu-gui-Check-printf-format-in-the-gui_progress_.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Thomas Frauendorfer | Miray Software +Date: Tue, 4 Aug 2020 13:49:51 +0200 +Subject: [PATCH] gfxmenu/gui: Check printf() format in the gui_progress_bar + and gui_label + +The gui_progress_bar and gui_label components can display the timeout +value. The format string can be set through a theme file. This patch +adds a validation step to the format string. + +If a user loads a theme file into the GRUB without this patch then +a GUI label with the following settings + + + label { + ... + id = "__timeout__" + text = "%s" + } + +will interpret the current timeout value as string pointer and print the +memory at that position on the screen. It is not desired behavior. + +Signed-off-by: Thomas Frauendorfer | Miray Software +Reviewed-by: Daniel Kiper +--- + grub-core/gfxmenu/gui_label.c | 4 ++++ + grub-core/gfxmenu/gui_progress_bar.c | 3 +++ + 2 files changed, 7 insertions(+) + +diff --git a/grub-core/gfxmenu/gui_label.c b/grub-core/gfxmenu/gui_label.c +index a4c817891ee..1c190542a2b 100644 +--- a/grub-core/gfxmenu/gui_label.c ++++ b/grub-core/gfxmenu/gui_label.c +@@ -193,6 +193,10 @@ label_set_property (void *vself, const char *name, const char *value) + else if (grub_strcmp (value, "@KEYMAP_SHORT@") == 0) + value = _("enter: boot, `e': options, `c': cmd-line"); + /* FIXME: Add more templates here if needed. */ ++ ++ if (grub_printf_fmt_check(value, "%d") != GRUB_ERR_NONE) ++ value = ""; /* Unsupported format. */ ++ + self->template = grub_strdup (value); + self->text = grub_xasprintf (value, self->value); + } +diff --git a/grub-core/gfxmenu/gui_progress_bar.c b/grub-core/gfxmenu/gui_progress_bar.c +index b128f08668e..ace85a12569 100644 +--- a/grub-core/gfxmenu/gui_progress_bar.c ++++ b/grub-core/gfxmenu/gui_progress_bar.c +@@ -348,6 +348,9 @@ progress_bar_set_property (void *vself, const char *name, const char *value) + Please use the shortest form available in you language. */ + value = _("%ds"); + ++ if (grub_printf_fmt_check(value, "%d") != GRUB_ERR_NONE) ++ value = ""; /* Unsupported format. */ ++ + self->template = grub_strdup (value); + } + else if (grub_strcmp (name, "font") == 0) diff --git a/SOURCES/0479-kern-mm-Fix-grub_debug_calloc-compilation-error.patch b/SOURCES/0479-kern-mm-Fix-grub_debug_calloc-compilation-error.patch new file mode 100644 index 0000000..619d6d5 --- /dev/null +++ b/SOURCES/0479-kern-mm-Fix-grub_debug_calloc-compilation-error.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Marco A Benatto +Date: Tue, 9 Feb 2021 12:33:06 -0300 +Subject: [PATCH] kern/mm: Fix grub_debug_calloc() compilation error + +Fix compilation error due to missing parameter to +grub_printf() when MM_DEBUG is defined. + +Fixes: 64e26162e (calloc: Make sure we always have an overflow-checking calloc() available) + +Signed-off-by: Marco A Benatto +Reviewed-by: Daniel Kiper +--- + grub-core/kern/mm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index 80d0720d005..d8c8377578b 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -594,7 +594,7 @@ grub_debug_calloc (const char *file, int line, grub_size_t nmemb, grub_size_t si + + if (grub_mm_debug) + grub_printf ("%s:%d: calloc (0x%" PRIxGRUB_SIZE ", 0x%" PRIxGRUB_SIZE ") = ", +- file, line, size); ++ file, line, nmemb, size); + ptr = grub_calloc (nmemb, size); + if (grub_mm_debug) + grub_printf ("%p\n", ptr); diff --git a/SOURCES/0480-efi-net-Fix-malformed-device-path-arithmetic-errors-.patch b/SOURCES/0480-efi-net-Fix-malformed-device-path-arithmetic-errors-.patch new file mode 100644 index 0000000..054a810 --- /dev/null +++ b/SOURCES/0480-efi-net-Fix-malformed-device-path-arithmetic-errors-.patch @@ -0,0 +1,74 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Thomas Frauendorfer | Miray Software +Date: Tue, 4 Aug 2020 17:13:05 +0200 +Subject: [PATCH] efi/net: Fix malformed device path arithmetic errors in efi + net methods + +--- + grub-core/net/efi/net.c | 26 ++++++++++++++++++++------ + 1 file changed, 20 insertions(+), 6 deletions(-) + +diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c +index 3ae1fbbe3c8..a58c24f6364 100644 +--- a/grub-core/net/efi/net.c ++++ b/grub-core/net/efi/net.c +@@ -1318,11 +1318,18 @@ grub_efi_net_boot_from_https (void) + + dp = grub_efi_get_device_path (image->device_handle); + +- while (1) ++ while (dp) + { ++ grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp); ++ if (len < 4) ++ { ++ grub_error(GRUB_ERR_OUT_OF_RANGE, ++ "malformed EFI Device Path node has length=%d", len); ++ break; ++ } ++ + 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)) +@@ -1335,7 +1342,7 @@ grub_efi_net_boot_from_https (void) + + if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) + break; +- dp = (grub_efi_device_path_t *) ((char *) dp + len); ++ dp = GRUB_EFI_NEXT_DEVICE_PATH(dp); + } + + return 0; +@@ -1353,11 +1360,18 @@ grub_efi_net_boot_from_opa (void) + + dp = grub_efi_get_device_path (image->device_handle); + +- while (1) ++ while (dp) + { ++ grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp); ++ if (len < 4) ++ { ++ grub_error(GRUB_ERR_OUT_OF_RANGE, ++ "malformed EFI Device Path node has length=%d", len); ++ break; ++ } ++ + 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)) +@@ -1368,7 +1382,7 @@ grub_efi_net_boot_from_opa (void) + + if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) + break; +- dp = (grub_efi_device_path_t *) ((char *) dp + len); ++ dp = GRUB_EFI_NEXT_DEVICE_PATH(dp); + } + + return 0; diff --git a/SOURCES/centos-ca-secureboot.der b/SOURCES/centos-ca-secureboot.der deleted file mode 100644 index 44a2563..0000000 Binary files a/SOURCES/centos-ca-secureboot.der and /dev/null differ diff --git a/SOURCES/centossecureboot001.der b/SOURCES/centossecureboot001.der deleted file mode 100644 index e8216b1..0000000 Binary files a/SOURCES/centossecureboot001.der and /dev/null differ diff --git a/SOURCES/centossecureboot202.der b/SOURCES/centossecureboot202.der deleted file mode 100644 index ab8213c..0000000 Binary files a/SOURCES/centossecureboot202.der and /dev/null differ diff --git a/SOURCES/centossecurebootca2.der b/SOURCES/centossecurebootca2.der deleted file mode 100644 index 42bdfcf..0000000 Binary files a/SOURCES/centossecurebootca2.der and /dev/null differ diff --git a/SOURCES/grub.macros b/SOURCES/grub.macros index 6279c55..98ad11a 100644 --- a/SOURCES/grub.macros +++ b/SOURCES/grub.macros @@ -112,7 +112,7 @@ %ifarch aarch64 %{arm} %global platform_modules " " %else -%global platform_modules " backtrace chain usb usbserial_common usbserial_pl2303 usbserial_ftdi usbserial_usbdebug " +%global platform_modules " backtrace chain usb usbserial_common usbserial_pl2303 usbserial_ftdi usbserial_usbdebug keylayouts at_keyboard " %endif %ifarch aarch64 %{arm} @@ -344,6 +344,8 @@ PYTHON=python3 ./autogen.sh \ --with-grubdir=%{name} \\\ --program-transform-name=s,grub,%{name}, \\\ --disable-grub-mount \\\ + --with-debug-timestamps \\\ + --enable-boot-time \\\ --disable-werror || ( cat config.log ; exit 1 ) \ git add . \ git commit -m "After efi configure" \ @@ -367,11 +369,11 @@ done \ %ifarch x86_64 aarch64 %{arm} %define mkimage() \ %{4}./grub-mkimage -O %{1} -o %{2}.orig \\\ - -p /EFI/%{efi_vendor} -d grub-core ${GRUB_MODULES} \\\ - --sbat %{4}./sbat.csv \ + -p /EFI/%{efi_vendor} -d grub-core ${GRUB_MODULES} \\\ + --sbat %{4}./sbat.csv \ %{4}./grub-mkimage -O %{1} -o %{3}.orig \\\ - -p /EFI/BOOT -d grub-core ${GRUB_MODULES} \\\ - --sbat %{4}./sbat.csv \ + -p /EFI/BOOT -d grub-core ${GRUB_MODULES} \\\ + --sbat %{4}./sbat.csv \ %{expand:%%{pesign -s -i %%{2}.orig -o %%{2}.one -a %%{5} -c %%{6} -n %%{7}}} \ %{expand:%%{pesign -s -i %%{3}.orig -o %%{3}.one -a %%{5} -c %%{6} -n %%{7}}} \ %{expand:%%{pesign -s -i %%{2}.one -o %%{2} -a %%{8} -c %%{9} -n %%{10}}} \ @@ -388,11 +390,13 @@ done \ %define do_efi_build_images() \ GRUB_MODULES=" all_video boot blscfg btrfs \\\ - cat configfile \\\ + cat configfile cryptodisk \\\ echo efi_netfs efifwsetup efinet ext2 \\\ - fat font gfxmenu gfxterm gzio \\\ + fat font gcry_rijndael gcry_rsa gcry_serpent \\\ + gcry_sha256 gcry_twofish gcry_whirlpool \\\ + gfxmenu gfxterm gzio \\\ halt hfsplus http increment iso9660 jpeg \\\ - loadenv loopback linux lvm lsefi lsefimmap \\\ + loadenv loopback linux lvm lsefi lsefimmap luks \\\ mdraid09 mdraid1x minicmd net \\\ normal part_apple part_msdos part_gpt \\\ password_pbkdf2 png reboot \\\ @@ -436,6 +440,8 @@ cd grub-%{1}-%{tarversion} \ --with-grubdir=%{name} \\\ --program-transform-name=s,grub,%{name}, \\\ --disable-grub-mount \\\ + --with-debug-timestamps \\\ + --enable-boot-time \\\ --disable-werror || ( cat config.log ; exit 1 ) \ git add . \ git commit -m "After legacy configure" \ @@ -558,7 +564,7 @@ touch ${RPM_BUILD_ROOT}/boot/%{name}/grub.cfg \ %dir %attr(0700,root,root)%{efi_esp_dir}/fonts \ %dir %attr(0700,root,root)/boot/loader/entries \ %ghost %config(noreplace) %attr(0700,root,root)%{efi_esp_dir}/grub.cfg \ -%config(noreplace) /boot/grub2/grubenv \ +%config(noreplace) %verify(not size mode md5 mtime) /boot/grub2/grubenv \ %ghost %config(noreplace) %attr(0700,root,root)%{efi_esp_dir}/grubenv \ %{expand:%if 0%{?without_efi_modules} \ %exclude %{_libdir}/grub/%{6} \ diff --git a/SOURCES/grub.patches b/SOURCES/grub.patches index 578dfee..cc743e3 100644 --- a/SOURCES/grub.patches +++ b/SOURCES/grub.patches @@ -315,111 +315,166 @@ Patch0314: 0314-linux-Fix-integer-overflows-in-initrd-size-handling.patch Patch0315: 0315-blscfg-Always-look-for-BLS-snippets-in-the-root-devi.patch Patch0316: 0316-blscfg-Don-t-hardcode-an-env-var-as-fallback-for-the.patch Patch0317: 0317-tftp-roll-over-block-counter-to-prevent-timeouts-wit.patch -Patch0318: 0318-kern-Add-lockdown-support.patch -Patch0319: 0319-kern-lockdown-Set-a-variable-if-the-GRUB-is-locked-d.patch -Patch0320: 0320-efi-Lockdown-the-GRUB-when-the-UEFI-Secure-Boot-is-e.patch -Patch0321: 0321-efi-Use-grub_is_lockdown-instead-of-hardcoding-a-dis.patch -Patch0322: 0322-acpi-Don-t-register-the-acpi-command-when-locked-dow.patch -Patch0323: 0323-mmap-Don-t-register-cutmem-and-badram-commands-when-.patch -Patch0324: 0324-commands-Restrict-commands-that-can-load-BIOS-or-DT-.patch -Patch0325: 0325-commands-setpci-Restrict-setpci-command-when-locked-.patch -Patch0326: 0326-commands-hdparm-Restrict-hdparm-command-when-locked-.patch -Patch0327: 0327-gdb-Restrict-GDB-access-when-locked-down.patch -Patch0328: 0328-loader-xnu-Don-t-allow-loading-extension-and-package.patch -Patch0329: 0329-docs-Document-the-cutmem-command.patch -Patch0330: 0330-dl-Only-allow-unloading-modules-that-are-not-depende.patch -Patch0331: 0331-usb-Avoid-possible-out-of-bound-accesses-caused-by-m.patch -Patch0332: 0332-mmap-Fix-memory-leak-when-iterating-over-mapped-memo.patch -Patch0333: 0333-net-net-Fix-possible-dereference-to-of-a-NULL-pointe.patch -Patch0334: 0334-net-tftp-Fix-dangling-memory-pointer.patch -Patch0335: 0335-kern-parser-Fix-resource-leak-if-argc-0.patch -Patch0336: 0336-kern-efi-Fix-memory-leak-on-failure.patch -Patch0337: 0337-kern-efi-mm-Fix-possible-NULL-pointer-dereference.patch -Patch0338: 0338-gnulib-regexec-Resolve-unused-variable.patch -Patch0339: 0339-gnulib-regcomp-Fix-uninitialized-token-structure.patch -Patch0340: 0340-gnulib-argp-help-Fix-dereference-of-a-possibly-NULL-.patch -Patch0341: 0341-gnulib-regexec-Fix-possible-null-dereference.patch -Patch0342: 0342-gnulib-regcomp-Fix-uninitialized-re_token.patch -Patch0343: 0343-io-lzopio-Resolve-unnecessary-self-assignment-errors.patch -Patch0344: 0344-kern-partition-Check-for-NULL-before-dereferencing-i.patch -Patch0345: 0345-disk-ldm-Make-sure-comp-data-is-freed-before-exiting.patch -Patch0346: 0346-disk-ldm-If-failed-then-free-vg-variable-too.patch -Patch0347: 0347-disk-ldm-Fix-memory-leak-on-uninserted-lv-references.patch -Patch0348: 0348-disk-cryptodisk-Fix-potential-integer-overflow.patch -Patch0349: 0349-hfsplus-Check-that-the-volume-name-length-is-valid.patch -Patch0350: 0350-zfs-Fix-possible-negative-shift-operation.patch -Patch0351: 0351-zfs-Fix-resource-leaks-while-constructing-path.patch -Patch0352: 0352-zfs-Fix-possible-integer-overflows.patch -Patch0353: 0353-zfsinfo-Correct-a-check-for-error-allocating-memory.patch -Patch0354: 0354-affs-Fix-memory-leaks.patch -Patch0355: 0355-libgcrypt-mpi-Fix-possible-unintended-sign-extension.patch -Patch0356: 0356-libgcrypt-mpi-Fix-possible-NULL-dereference.patch -Patch0357: 0357-syslinux-Fix-memory-leak-while-parsing.patch -Patch0358: 0358-normal-completion-Fix-leaking-of-memory-when-process.patch -Patch0359: 0359-commands-hashsum-Fix-a-memory-leak.patch -Patch0360: 0360-video-efi_gop-Remove-unnecessary-return-value-of-gru.patch -Patch0361: 0361-video-fb-fbfill-Fix-potential-integer-overflow.patch -Patch0362: 0362-video-fb-video_fb-Fix-multiple-integer-overflows.patch -Patch0363: 0363-video-fb-video_fb-Fix-possible-integer-overflow.patch -Patch0364: 0364-video-readers-jpeg-Test-for-an-invalid-next-marker-r.patch -Patch0365: 0365-gfxmenu-gui_list-Remove-code-that-coverity-is-flaggi.patch -Patch0366: 0366-loader-bsd-Check-for-NULL-arg-up-front.patch -Patch0367: 0367-loader-xnu-Fix-memory-leak.patch -Patch0368: 0368-loader-xnu-Free-driverkey-data-when-an-error-is-dete.patch -Patch0369: 0369-loader-xnu-Check-if-pointer-is-NULL-before-using-it.patch -Patch0370: 0370-util-grub-editenv-Fix-incorrect-casting-of-a-signed-.patch -Patch0371: 0371-util-glue-efi-Fix-incorrect-use-of-a-possibly-negati.patch -Patch0372: 0372-script-execute-Fix-NULL-dereference-in-grub_script_e.patch -Patch0373: 0373-commands-ls-Require-device_name-is-not-NULL-before-p.patch -Patch0374: 0374-script-execute-Avoid-crash-when-using-outside-a-func.patch -Patch0375: 0375-lib-arg-Block-repeated-short-options-that-require-an.patch -Patch0376: 0376-script-execute-Don-t-crash-on-a-for-loop-with-no-ite.patch -Patch0377: 0377-commands-menuentry-Fix-quoting-in-setparams_prefix.patch -Patch0378: 0378-kern-misc-Always-set-end-in-grub_strtoull.patch -Patch0379: 0379-video-readers-jpeg-Catch-files-with-unsupported-quan.patch -Patch0380: 0380-video-readers-jpeg-Catch-OOB-reads-writes-in-grub_jp.patch -Patch0381: 0381-video-readers-jpeg-Don-t-decode-data-before-start-of.patch -Patch0382: 0382-term-gfxterm-Don-t-set-up-a-font-with-glyphs-that-ar.patch -Patch0383: 0383-fs-fshelp-Catch-impermissibly-large-block-sizes-in-r.patch -Patch0384: 0384-fs-hfsplus-Don-t-fetch-a-key-beyond-the-end-of-the-n.patch -Patch0385: 0385-fs-hfsplus-Don-t-use-uninitialized-data-on-corrupt-f.patch -Patch0386: 0386-fs-hfs-Disable-under-lockdown.patch -Patch0387: 0387-fs-sfs-Fix-over-read-of-root-object-name.patch -Patch0388: 0388-fs-jfs-Do-not-move-to-leaf-level-if-name-length-is-n.patch -Patch0389: 0389-fs-jfs-Limit-the-extents-that-getblk-can-consider.patch -Patch0390: 0390-fs-jfs-Catch-infinite-recursion.patch -Patch0391: 0391-fs-nilfs2-Reject-too-large-keys.patch -Patch0392: 0392-fs-nilfs2-Don-t-search-children-if-provided-number-i.patch -Patch0393: 0393-fs-nilfs2-Properly-bail-on-errors-in-grub_nilfs2_btr.patch -Patch0394: 0394-io-gzio-Bail-if-gzio-tl-td-is-NULL.patch -Patch0395: 0395-io-gzio-Add-init_dynamic_block-clean-up-if-unpacking.patch -Patch0396: 0396-io-gzio-Catch-missing-values-in-huft_build-and-bail.patch -Patch0397: 0397-io-gzio-Zero-gzio-tl-td-in-init_dynamic_block-if-huf.patch -Patch0398: 0398-disk-lvm-Don-t-go-beyond-the-end-of-the-data-we-read.patch -Patch0399: 0399-disk-lvm-Don-t-blast-past-the-end-of-the-circular-me.patch -Patch0400: 0400-disk-lvm-Bail-on-missing-PV-list.patch -Patch0401: 0401-disk-lvm-Do-not-crash-if-an-expected-string-is-not-f.patch -Patch0402: 0402-disk-lvm-Do-not-overread-metadata.patch -Patch0403: 0403-disk-lvm-Sanitize-rlocn-offset-to-prevent-wild-read.patch -Patch0404: 0404-disk-lvm-Do-not-allow-a-LV-to-be-it-s-own-segment-s-.patch -Patch0405: 0405-kern-parser-Fix-a-memory-leak.patch -Patch0406: 0406-kern-parser-Introduce-process_char-helper.patch -Patch0407: 0407-kern-parser-Introduce-terminate_arg-helper.patch -Patch0408: 0408-kern-parser-Refactor-grub_parser_split_cmdline-clean.patch -Patch0409: 0409-kern-buffer-Add-variable-sized-heap-buffer.patch -Patch0410: 0410-kern-parser-Fix-a-stack-buffer-overflow.patch -Patch0411: 0411-kern-efi-Add-initial-stack-protector-implementation.patch -Patch0412: 0412-util-mkimage-Remove-unused-code-to-add-BSS-section.patch -Patch0413: 0413-util-mkimage-Use-grub_host_to_target32-instead-of-gr.patch -Patch0414: 0414-util-mkimage-Always-use-grub_host_to_target32-to-ini.patch -Patch0415: 0415-util-mkimage-Unify-more-of-the-PE32-and-PE32-header-.patch -Patch0416: 0416-util-mkimage-Reorder-PE-optional-header-fields-set-u.patch -Patch0417: 0417-util-mkimage-Improve-data_size-value-calculation.patch -Patch0418: 0418-util-mkimage-Refactor-section-setup-to-use-a-helper.patch -Patch0419: 0419-util-mkimage-Add-an-option-to-import-SBAT-metadata-i.patch -Patch0420: 0420-kern-misc-Split-parse_printf_args-into-format-parsin.patch -Patch0421: 0421-kern-misc-Add-STRING-type-for-internal-printf-format.patch -Patch0422: 0422-kern-misc-Add-function-to-check-printf-format-agains.patch -Patch0423: 0423-gfxmenu-gui-Check-printf-format-in-the-gui_progress_.patch -Patch0424: 0424-kern-mm-Fix-grub_debug_calloc-compilation-error.patch -Patch0425: 0425-efi-net-Fix-malformed-device-path-arithmetic-errors-.patch +Patch0318: 0318-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch +Patch0319: 0319-grub-install-disable-support-for-EFI-platforms.patch +Patch0320: 0320-New-with-debug-timestamps-configure-flag-to-prepend-.patch +Patch0321: 0321-Added-debug-statements-to-grub_disk_open-and-grub_di.patch +Patch0322: 0322-Introduce-function-grub_debug_is_enabled-void-return.patch +Patch0323: 0323-Don-t-clear-screen-when-debugging-is-enabled.patch +Patch0324: 0324-grub_file_-instrumentation-new-file-debug-tag.patch +Patch0325: 0325-ieee1275-Avoiding-many-unecessary-open-close.patch +Patch0326: 0326-ieee1275-powerpc-implements-fibre-channel-discovery-.patch +Patch0327: 0327-ieee1275-powerpc-enables-device-mapper-discovery.patch +Patch0328: 0328-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch +Patch0329: 0329-bufio-Use-grub_size_t-instead-of-plain-int-for-size.patch +Patch0330: 0330-verifiers-File-type-for-fine-grained-signature-verif.patch +Patch0331: 0331-verifiers-Framework-core.patch +Patch0332: 0332-verifiers-Add-possibility-to-verify-kernel-and-modul.patch +Patch0333: 0333-verifiers-Add-possibility-to-defer-verification-to-o.patch +Patch0334: 0334-verifiers-Rename-verify-module-to-pgp-module.patch +Patch0335: 0335-pgp-Fix-emu-build-and-tests-after-pgp-module-renamin.patch +Patch0336: 0336-include-grub-file.h-Add-device-tree-file-type.patch +Patch0337: 0337-grub-core-loader-efi-fdt.c-Fixup-grub_file_open-call.patch +Patch0338: 0338-arm64-efi-Fix-breakage-caused-by-verifiers.patch +Patch0339: 0339-arm-uboot-ia64-sparc64-Fix-up-grub_file_open-calls.patch +Patch0340: 0340-verifiers-fix-double-close-on-pgp-s-sig-file-descrip.patch +Patch0341: 0341-verifiers-Xen-fallout-cleanup.patch +Patch0342: 0342-verifiers-ARM-Xen-fallout-cleanup.patch +Patch0343: 0343-verifiers-IA-64-fallout-cleanup.patch +Patch0344: 0344-verifiers-PowerPC-fallout-cleanup.patch +Patch0345: 0345-verifiers-MIPS-fallout-cleanup.patch +Patch0346: 0346-verifiers-Fix-calling-uninitialized-function-pointer.patch +Patch0347: 0347-rhel-extra-file-type-fixes.patch +Patch0348: 0348-dl-Add-support-for-persistent-modules.patch +Patch0349: 0349-Add-suport-for-signing-grub-with-an-appended-signatu.patch +Patch0350: 0350-docs-grub-Document-signing-grub-under-UEFI.patch +Patch0351: 0351-docs-grub-Document-signing-grub-with-an-appended-sig.patch +Patch0352: 0352-docs-grub-grub-install-is-no-longer-a-shell-script.patch +Patch0353: 0353-docs-grub-pubkey-has-been-supported-for-some-time.patch +Patch0354: 0354-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch +Patch0355: 0355-verifiers-provide-unsafe-module-list.patch +Patch0356: 0356-pgp-factor-out-rsa_pad.patch +Patch0357: 0357-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch +Patch0358: 0358-posix_wrap-tweaks-in-preparation-for-libtasn1.patch +Patch0359: 0359-libtasn1-import-libtasn1-4.16.0.patch +Patch0360: 0360-libtasn1-disable-code-not-needed-in-grub.patch +Patch0361: 0361-libtasn1-changes-for-grub-compatibility.patch +Patch0362: 0362-libtasn1-compile-into-asn1-module.patch +Patch0363: 0363-test_asn1-test-module-for-libtasn1.patch +Patch0364: 0364-grub-install-support-embedding-x509-certificates.patch +Patch0365: 0365-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch +Patch0366: 0366-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch +Patch0367: 0367-appended-signatures-support-verifying-appended-signa.patch +Patch0368: 0368-appended-signatures-verification-tests.patch +Patch0369: 0369-appended-signatures-documentation.patch +Patch0370: 0370-ieee1275-link-appended-signature-enforcement-to-ibm-.patch +Patch0371: 0371-include-grub-verify.h-Add-include-guard.patch +Patch0372: 0372-arm64-xen-Fix-too-few-arguments-to-function-grub_cre.patch +Patch0373: 0373-kern-Add-lockdown-support.patch +Patch0374: 0374-kern-lockdown-Set-a-variable-if-the-GRUB-is-locked-d.patch +Patch0375: 0375-efi-Lockdown-the-GRUB-when-the-UEFI-Secure-Boot-is-e.patch +Patch0376: 0376-efi-Use-grub_is_lockdown-instead-of-hardcoding-a-dis.patch +Patch0377: 0377-acpi-Don-t-register-the-acpi-command-when-locked-dow.patch +Patch0378: 0378-mmap-Don-t-register-cutmem-and-badram-commands-when-.patch +Patch0379: 0379-commands-Restrict-commands-that-can-load-BIOS-or-DT-.patch +Patch0380: 0380-commands-setpci-Restrict-setpci-command-when-locked-.patch +Patch0381: 0381-commands-hdparm-Restrict-hdparm-command-when-locked-.patch +Patch0382: 0382-gdb-Restrict-GDB-access-when-locked-down.patch +Patch0383: 0383-loader-xnu-Don-t-allow-loading-extension-and-package.patch +Patch0384: 0384-docs-Document-the-cutmem-command.patch +Patch0385: 0385-dl-Only-allow-unloading-modules-that-are-not-depende.patch +Patch0386: 0386-usb-Avoid-possible-out-of-bound-accesses-caused-by-m.patch +Patch0387: 0387-mmap-Fix-memory-leak-when-iterating-over-mapped-memo.patch +Patch0388: 0388-net-net-Fix-possible-dereference-to-of-a-NULL-pointe.patch +Patch0389: 0389-net-tftp-Fix-dangling-memory-pointer.patch +Patch0390: 0390-kern-parser-Fix-resource-leak-if-argc-0.patch +Patch0391: 0391-kern-efi-Fix-memory-leak-on-failure.patch +Patch0392: 0392-kern-efi-mm-Fix-possible-NULL-pointer-dereference.patch +Patch0393: 0393-gnulib-regexec-Resolve-unused-variable.patch +Patch0394: 0394-gnulib-regcomp-Fix-uninitialized-token-structure.patch +Patch0395: 0395-gnulib-argp-help-Fix-dereference-of-a-possibly-NULL-.patch +Patch0396: 0396-gnulib-regexec-Fix-possible-null-dereference.patch +Patch0397: 0397-gnulib-regcomp-Fix-uninitialized-re_token.patch +Patch0398: 0398-io-lzopio-Resolve-unnecessary-self-assignment-errors.patch +Patch0399: 0399-kern-partition-Check-for-NULL-before-dereferencing-i.patch +Patch0400: 0400-disk-ldm-Make-sure-comp-data-is-freed-before-exiting.patch +Patch0401: 0401-disk-ldm-If-failed-then-free-vg-variable-too.patch +Patch0402: 0402-disk-ldm-Fix-memory-leak-on-uninserted-lv-references.patch +Patch0403: 0403-disk-cryptodisk-Fix-potential-integer-overflow.patch +Patch0404: 0404-hfsplus-Check-that-the-volume-name-length-is-valid.patch +Patch0405: 0405-zfs-Fix-possible-negative-shift-operation.patch +Patch0406: 0406-zfs-Fix-resource-leaks-while-constructing-path.patch +Patch0407: 0407-zfs-Fix-possible-integer-overflows.patch +Patch0408: 0408-zfsinfo-Correct-a-check-for-error-allocating-memory.patch +Patch0409: 0409-affs-Fix-memory-leaks.patch +Patch0410: 0410-libgcrypt-mpi-Fix-possible-unintended-sign-extension.patch +Patch0411: 0411-libgcrypt-mpi-Fix-possible-NULL-dereference.patch +Patch0412: 0412-syslinux-Fix-memory-leak-while-parsing.patch +Patch0413: 0413-normal-completion-Fix-leaking-of-memory-when-process.patch +Patch0414: 0414-commands-hashsum-Fix-a-memory-leak.patch +Patch0415: 0415-video-efi_gop-Remove-unnecessary-return-value-of-gru.patch +Patch0416: 0416-video-fb-fbfill-Fix-potential-integer-overflow.patch +Patch0417: 0417-video-fb-video_fb-Fix-multiple-integer-overflows.patch +Patch0418: 0418-video-fb-video_fb-Fix-possible-integer-overflow.patch +Patch0419: 0419-video-readers-jpeg-Test-for-an-invalid-next-marker-r.patch +Patch0420: 0420-gfxmenu-gui_list-Remove-code-that-coverity-is-flaggi.patch +Patch0421: 0421-loader-bsd-Check-for-NULL-arg-up-front.patch +Patch0422: 0422-loader-xnu-Fix-memory-leak.patch +Patch0423: 0423-loader-xnu-Free-driverkey-data-when-an-error-is-dete.patch +Patch0424: 0424-loader-xnu-Check-if-pointer-is-NULL-before-using-it.patch +Patch0425: 0425-util-grub-editenv-Fix-incorrect-casting-of-a-signed-.patch +Patch0426: 0426-util-glue-efi-Fix-incorrect-use-of-a-possibly-negati.patch +Patch0427: 0427-script-execute-Fix-NULL-dereference-in-grub_script_e.patch +Patch0428: 0428-commands-ls-Require-device_name-is-not-NULL-before-p.patch +Patch0429: 0429-script-execute-Avoid-crash-when-using-outside-a-func.patch +Patch0430: 0430-lib-arg-Block-repeated-short-options-that-require-an.patch +Patch0431: 0431-script-execute-Don-t-crash-on-a-for-loop-with-no-ite.patch +Patch0432: 0432-commands-menuentry-Fix-quoting-in-setparams_prefix.patch +Patch0433: 0433-kern-misc-Always-set-end-in-grub_strtoull.patch +Patch0434: 0434-video-readers-jpeg-Catch-files-with-unsupported-quan.patch +Patch0435: 0435-video-readers-jpeg-Catch-OOB-reads-writes-in-grub_jp.patch +Patch0436: 0436-video-readers-jpeg-Don-t-decode-data-before-start-of.patch +Patch0437: 0437-term-gfxterm-Don-t-set-up-a-font-with-glyphs-that-ar.patch +Patch0438: 0438-fs-fshelp-Catch-impermissibly-large-block-sizes-in-r.patch +Patch0439: 0439-fs-hfsplus-Don-t-fetch-a-key-beyond-the-end-of-the-n.patch +Patch0440: 0440-fs-hfsplus-Don-t-use-uninitialized-data-on-corrupt-f.patch +Patch0441: 0441-fs-hfs-Disable-under-lockdown.patch +Patch0442: 0442-fs-sfs-Fix-over-read-of-root-object-name.patch +Patch0443: 0443-fs-jfs-Do-not-move-to-leaf-level-if-name-length-is-n.patch +Patch0444: 0444-fs-jfs-Limit-the-extents-that-getblk-can-consider.patch +Patch0445: 0445-fs-jfs-Catch-infinite-recursion.patch +Patch0446: 0446-fs-nilfs2-Reject-too-large-keys.patch +Patch0447: 0447-fs-nilfs2-Don-t-search-children-if-provided-number-i.patch +Patch0448: 0448-fs-nilfs2-Properly-bail-on-errors-in-grub_nilfs2_btr.patch +Patch0449: 0449-io-gzio-Bail-if-gzio-tl-td-is-NULL.patch +Patch0450: 0450-io-gzio-Add-init_dynamic_block-clean-up-if-unpacking.patch +Patch0451: 0451-io-gzio-Catch-missing-values-in-huft_build-and-bail.patch +Patch0452: 0452-io-gzio-Zero-gzio-tl-td-in-init_dynamic_block-if-huf.patch +Patch0453: 0453-disk-lvm-Don-t-go-beyond-the-end-of-the-data-we-read.patch +Patch0454: 0454-disk-lvm-Don-t-blast-past-the-end-of-the-circular-me.patch +Patch0455: 0455-disk-lvm-Bail-on-missing-PV-list.patch +Patch0456: 0456-disk-lvm-Do-not-crash-if-an-expected-string-is-not-f.patch +Patch0457: 0457-disk-lvm-Do-not-overread-metadata.patch +Patch0458: 0458-disk-lvm-Sanitize-rlocn-offset-to-prevent-wild-read.patch +Patch0459: 0459-disk-lvm-Do-not-allow-a-LV-to-be-it-s-own-segment-s-.patch +Patch0460: 0460-kern-parser-Fix-a-memory-leak.patch +Patch0461: 0461-kern-parser-Introduce-process_char-helper.patch +Patch0462: 0462-kern-parser-Introduce-terminate_arg-helper.patch +Patch0463: 0463-kern-parser-Refactor-grub_parser_split_cmdline-clean.patch +Patch0464: 0464-kern-buffer-Add-variable-sized-heap-buffer.patch +Patch0465: 0465-kern-parser-Fix-a-stack-buffer-overflow.patch +Patch0466: 0466-kern-efi-Add-initial-stack-protector-implementation.patch +Patch0467: 0467-util-mkimage-Remove-unused-code-to-add-BSS-section.patch +Patch0468: 0468-util-mkimage-Use-grub_host_to_target32-instead-of-gr.patch +Patch0469: 0469-util-mkimage-Always-use-grub_host_to_target32-to-ini.patch +Patch0470: 0470-util-mkimage-Unify-more-of-the-PE32-and-PE32-header-.patch +Patch0471: 0471-util-mkimage-Reorder-PE-optional-header-fields-set-u.patch +Patch0472: 0472-util-mkimage-Improve-data_size-value-calculation.patch +Patch0473: 0473-util-mkimage-Refactor-section-setup-to-use-a-helper.patch +Patch0474: 0474-util-mkimage-Add-an-option-to-import-SBAT-metadata-i.patch +Patch0475: 0475-kern-misc-Split-parse_printf_args-into-format-parsin.patch +Patch0476: 0476-kern-misc-Add-STRING-type-for-internal-printf-format.patch +Patch0477: 0477-kern-misc-Add-function-to-check-printf-format-agains.patch +Patch0478: 0478-gfxmenu-gui-Check-printf-format-in-the-gui_progress_.patch +Patch0479: 0479-kern-mm-Fix-grub_debug_calloc-compilation-error.patch +Patch0480: 0480-efi-net-Fix-malformed-device-path-arithmetic-errors-.patch diff --git a/SOURCES/redhatsecureboot301.cer b/SOURCES/redhatsecureboot301.cer new file mode 100644 index 0000000..4ff8b79 Binary files /dev/null and b/SOURCES/redhatsecureboot301.cer differ diff --git a/SOURCES/redhatsecureboot502.cer b/SOURCES/redhatsecureboot502.cer new file mode 100644 index 0000000..be0b5e2 Binary files /dev/null and b/SOURCES/redhatsecureboot502.cer differ diff --git a/SOURCES/redhatsecurebootca3.cer b/SOURCES/redhatsecurebootca3.cer new file mode 100644 index 0000000..b235400 Binary files /dev/null and b/SOURCES/redhatsecurebootca3.cer differ diff --git a/SOURCES/redhatsecurebootca5.cer b/SOURCES/redhatsecurebootca5.cer new file mode 100644 index 0000000..dfb0284 Binary files /dev/null and b/SOURCES/redhatsecurebootca5.cer differ diff --git a/SPECS/grub2.spec b/SPECS/grub2.spec index d1e1aa6..86208d2 100644 --- a/SPECS/grub2.spec +++ b/SPECS/grub2.spec @@ -7,7 +7,7 @@ Name: grub2 Epoch: 1 Version: 2.02 -Release: 90%{?dist}.1 +Release: 99%{?dist} Summary: Bootloader with support for Linux, Multiboot and more Group: System Environment/Base License: GPLv3+ @@ -24,10 +24,10 @@ Source6: gitignore Source8: strtoull_test.c Source9: 20-grub.install Source12: 99-grub-mkconfig.install -Source13: centos-ca-secureboot.der -Source14: centossecureboot001.der -Source15: centossecurebootca2.der -Source16: centossecureboot202.der +Source13: redhatsecurebootca3.cer +Source14: redhatsecureboot301.cer +Source15: redhatsecurebootca5.cer +Source16: redhatsecureboot502.cer Source17: sbat.csv.in %include %{SOURCE1} @@ -55,11 +55,7 @@ BuildRequires: pesign >= 0.99-8 BuildRequires: ccache %endif -%if 0%{?centos} -%global efidir centos -%endif - -ExcludeArch: s390 s390x +ExcludeArch: s390 s390x %{arm} Obsoletes: %{name} <= %{evr} %if 0%{with_legacy_arch} @@ -173,10 +169,10 @@ git commit -m "After making subdirs" %build %if 0%{with_efi_arch} -%{expand:%do_primary_efi_build %%{grubefiarch} %%{grubefiname} %%{grubeficdname} %%{_target_platform} %%{efi_target_cflags} %%{efi_host_cflags} %{SOURCE13} %{SOURCE14} centossecureboot001 %{SOURCE15} %{SOURCE16} centossecureboot202} +%{expand:%do_primary_efi_build %%{grubefiarch} %%{grubefiname} %%{grubeficdname} %%{_target_platform} %%{efi_target_cflags} %%{efi_host_cflags} %{SOURCE13} %{SOURCE14} redhatsecureboot301 %{SOURCE15} %{SOURCE16} redhatsecureboot502} %endif %if 0%{with_alt_efi_arch} -%{expand:%do_alt_efi_build %%{grubaltefiarch} %%{grubaltefiname} %%{grubalteficdname} %%{_alt_target_platform} %%{alt_efi_target_cflags} %%{alt_efi_host_cflags} %{SOURCE13} %{SOURCE14} centossecureboot001 %{SOURCE15} %{SOURCE16} centossecureboot202} +%{expand:%do_alt_efi_build %%{grubaltefiarch} %%{grubaltefiname} %%{grubalteficdname} %%{_alt_target_platform} %%{alt_efi_target_cflags} %%{alt_efi_host_cflags} %{SOURCE13} %{SOURCE14} redhatsecureboot301 %{SOURCE15} %{SOURCE16} redhatsecureboot502} %endif %if 0%{with_legacy_arch} %{expand:%do_legacy_build %%{grublegacyarch}} @@ -358,7 +354,7 @@ fi %dir %attr(0700,root,root) %{efi_esp_dir} %exclude %{efi_esp_dir}/* %license COPYING -%ghost %config(noreplace) /boot/grub2/grubenv +%ghost %config(noreplace) %verify(not size mode md5 mtime) /boot/grub2/grubenv %doc INSTALL %doc NEWS %doc README @@ -507,7 +503,17 @@ fi %endif %changelog -* Thu Feb 25 2021 Javier Martinez Canillas - 2.02-90.el8_3.1 +* Thu Feb 25 2021 Javier Martinez Canillas - 2.02-99 +- Fix bug of grub2-install not checking for the SBAT option + Resolves: CVE-2020-14372 + Resolves: CVE-2020-25632 + Resolves: CVE-2020-25647 + Resolves: CVE-2020-27749 + Resolves: CVE-2020-27779 + Resolves: CVE-2021-20225 + Resolves: CVE-2021-20233 + +* Thu Feb 25 2021 Javier Martinez Canillas - 2.02-98 - Fix another batch of CVEs Resolves: CVE-2020-14372 Resolves: CVE-2020-25632 @@ -517,6 +523,50 @@ fi Resolves: CVE-2021-20225 Resolves: CVE-2021-20233 +* Tue Feb 23 2021 Javier Martinez Canillas - 2.02-97 +- Fix keylayouts module listed twice in GRUB_MODULES variable + Related: rhbz#1897587 + +* Tue Feb 23 2021 Javier Martinez Canillas - 2.02-96 +- Fix "Add 'at_keyboard_fallback_set' var to force the set manually" + Related: rhbz#1897587 +- Fix a boot failure due patch "ieee1275: claim up to 256MB memory" + Resolves: rhbz#1929111 + +* Tue Jan 26 2021 Javier Martinez Canillas - 2.02-95 +- Add appended signatures support for ppc64le LPAR Secure Boot (daxtens) + Resolves: rhbz#1853410 + +* Wed Jan 20 2021 Renaud Métrich - 2.02-94 +- Add 'at_keyboard_fallback_set' var to force the set manually +- Related: rhbz#1897587 + +* Mon Dec 14 2020 Javier Martinez Canillas - 2.02-93 +- add keylayouts and at_keyboard modules to UEFI Grub2 (rmetrich) + Related: rhbz#1897587 +- at_keyboard: use set 1 when keyboard is in Translate mode (rmetrich) + Resolves: rhbz#1897587 +- add GRUB enhanced debugging features (rmetrich) + Resolves: rhbz#1776249 +- ieee1275: Avoiding many unecessary open/close (diegodo) + Resolves: rhbz#1862632 +- ieee1275: device mapper and fibre channel discovery support (diegodo) + Resolves: rhbz#1873724 + +* Mon Nov 23 2020 Jan Hlavac - 2.02-92 +- grub2-install: disable support for EFI platforms + Resolves: rhbz#1737444 +- Include a few more modules to EFI build needed for LUKS support (javierm) + Related: rhbz#1873725 + +* Mon Nov 16 2020 Javier Martinez Canillas - 2.02-91 +- Fix tps-rpmtest failing due /boot/grub2/grubenv attributes mismatch + Resolves: rhbz#1813959 +- Include in EFI build the modules needed for LUKS support + Resolves: rhbz#1873725 +- Fix keyboards that report IBM PC AT scan codes + Resolves: rhbz#1897587 + * Mon Aug 31 2020 Javier Martinez Canillas - 2.02-90 - Roll over TFTP block counter to prevent timeouts with data packets Resolves: rhbz#1871034